量化实盘笔记:用Python处理港股实时api逐笔序列号断档

用户头像sh_****559rtx
2026-08-24 发布

最近在维护一套港股量化策略时,我遇到一个比较隐蔽的数据质量问题:通过港股实时api接收的逐笔成交数据,偶尔会出现序列号不连续的情况。这个问题对低频策略可能影响不大,但对依赖逐笔成交分布的高频因子,累积起来会直接改变计算结果。这篇文章记录我的排查和解决过程,供同做港股量化的朋友参考。

场景:从一次成交统计偏差说起

我们的策略需要实时接收港股逐笔成交数据,用来计算盘口活跃度、成交分布和短期动量因子。实盘运行一段时间后,我发现某个因子的数值与交易所公布的汇总数据存在小幅偏差。一开始我怀疑是价格解析或者成交量字段处理有误,于是逐步排查了数据格式、时间戳对齐,甚至重新检查了策略逻辑,都没有找到明显问题。后来我把逐笔消息的序列号打印出来,才发现中间缺了一条记录。就是这一次断档,导致后续的累计成交量和因子值出现了偏差。

数据痛点:逐笔序列号断档意味着什么

港股实时api推送的逐笔行情中,通常会带一个递增的序列号字段,用来标识消息的先后顺序。理想情况下,本地收到的每一条消息,序列号都应该比上一条大1。但实际环境中,网络波动、程序处理延迟或者断线重连,都可能导致消息丢失。下面是我在日志中观察到的典型情况:

序列号 状态
60001 正常接收
60002 正常接收
60003 正常接收
60005 发现缺失

可以看到,60004这条消息没有到达本地。对于只展示最新价格的场景,少一条可能无所谓;但对于需要根据逐笔数据生成成交统计、还原盘口变化或者计算高频因子的量化策略来说,这种缺失需要认真对待。

解决方案:在数据入口增加序列号校验

我后来调整了行情接入模块,不让WebSocket消息直接进入策略计算,而是在数据入口增加一层校验。每收到一条逐笔数据,程序会保存上一条序列号,然后与当前序列号比较。如果连续就正常处理;如果出现跳号,就记录异常位置。这样做的好处是,后续如果发现因子值异常,可以快速定位是哪个时间段、哪只股票的行情出现了缺口。

下面是我在Python里用的基础检测代码:

import json
import websocket


last_seq = None


def on_message(ws, message):
    global last_seq

    data = json.loads(message)

    seq = data.get("seq")

    if last_seq is not None:
        if seq != last_seq + 1:
            print(f"发现序列号断档: {last_seq} -> {seq}")

    last_seq = seq

    print(data)


ws = websocket.WebSocketApp(
    "wss://api.alltick.co/stock/websocket",
    on_message=on_message
)

ws.run_forever()

这段代码只是基础检测,实际项目里我还会保存股票代码、交易时间以及缺失范围,方便后续恢复数据。我目前使用的港股实时行情源是AllTick,它在推送频率和字段完整度上可以满足量化需求,但序列校验逻辑需要自己在客户端实现。

实际开发中容易忽略的细节

处理逐笔行情时,我发现序列号并不是唯一判断标准。有几个细节需要特别注意:

  1. 序列号连续不代表时间戳一定有序,网络延迟可能导致不同消息到达本地的时间发生变化,因此我会同时记录交易时间和接收时间;
  2. WebSocket断线重连后,不能默认收到的数据就是完整的,需要重新检查序列是否和之前衔接;
  3. 如果数据用于回测,断档的tick会直接影响成交分布和因子值,不能简单跳过。

数据恢复机制

如果只是做行情监控,发现异常后记录即可。但如果数据用于回测或者策略计算,就需要设计恢复机制。我通常会保存以下信息:

  • 缺少的序列范围;
  • 对应股票代码;
  • 出现异常的时间。

然后通过历史行情数据补齐缺失部分,并重新合并到本地数据流中。这样即使实时连接短暂不稳定,也不会影响完整行情分析。

总结

接入港股实时api之后,我越来越觉得,行情系统真正难的地方不是获取数据,而是保证数据长期稳定可靠。对于量化策略来说,逐笔数据的完整性和顺序性直接影响统计结果和因子计算。提前做好序列检测、异常记录和数据恢复,是保证策略稳定运行的基础。

3848aa2ea1082243bb1d989aedc71b7f.jpg

评论