2. Level2行情基础

在Level2行情一致性校验的实战中,第一步不是写代码,而是把三类核心数据的“身份”搞清楚:逐笔成交、逐笔委托、快照行情。它们分别回答“已经发生了什么”“市场想做什么”“某一瞬间市场长什么样”。如果对字段含义和交易所规范理解偏差,后续所有校验都会建立在错误前提上。

一、三类行情数据的核心定位

逐笔成交是交易所撮合引擎产生的成交回报,记录每一笔真实成交的价格、数量、买卖方向及成交类型。逐笔委托是订单进入撮合队列前后的委托明细,反映买卖双方的意图和撤单行为。快照行情则是按固定时间间隔(如沪深交易所通常为3秒)对订单簿进行切片,给出最优买卖档位及汇总统计。三者关系可以概括为:逐笔委托驱动订单簿变化,逐笔成交消耗订单簿,快照是订单簿在时间轴上的采样。

Level2三类行情数据关系与订单簿演化 逐笔委托 Order:新增/撤单 买卖方向、价格、数量 逐笔成交 Trade:成交价、量 买方/卖方订单号 快照行情 Snapshot:3秒切片 十档/五档最优报价 订单簿(Order Book) 逐笔委托改变订单簿 → 逐笔成交消耗订单簿 → 快照采样订单簿 一致性校验关注点 委托序号连续性 · 成交与委托匹配 · 快照与逐笔重建结果比对 · 时间戳对齐

二、逐笔成交与逐笔委托的字段含义

沪深交易所的逐笔数据字段命名略有差异,但核心语义一致。以下以通用字段为例说明:

字段所属类型含义校验意义
SeqNum逐笔成交/委托交易所内部连续序号检测丢包、乱序
OrderNo逐笔委托委托订单编号与成交记录关联
Price逐笔成交/委托价格(元)价格合法性、涨跌停
Qty逐笔成交/委托数量(股/手)数量守恒校验
Side逐笔成交/委托买卖方向方向一致性
TradeType逐笔成交成交类型(成交/撤单)区分真实成交与撤单
BidPrice/AskPrice快照最优买/卖价与逐笔重建比对
上交所逐笔委托中,撤单表现为一条独立的撤单记录,其 OrderNo 指向被撤委托;深交所则在逐笔委托中通过 ExecType 字段区分。校验时必须按交易所分别处理,不能混用。

三、快照行情的结构与采样逻辑

快照行情通常包含:时间戳、最新价、成交量、成交额、十档买卖价格与数量、买卖委托总数等。它的关键特征是“离散采样”,即每3秒对订单簿拍一张照片。因此快照之间可能发生大量逐笔事件,但快照本身不记录这些中间过程。

一致性校验的核心思路是:用逐笔委托和逐笔成交重建订单簿,再在快照时间点上与交易所发布的快照进行比对。如果重建结果与快照在最优价、档位数量、累计成交量上出现偏差,就说明逐笔数据存在丢失、重复或字段解析错误。

# 快照重建伪代码示例
for snapshot in snapshots:
    target_time = snapshot.timestamp
    while tick.time <= target_time:
        if tick.type == "order":
            order_book.apply_order(tick)
        elif tick.type == "trade":
            order_book.apply_trade(tick)
    rebuilt = order_book.get_top10()
    assert rebuilt.bid_price[0] == snapshot.bid_price[0]
    assert rebuilt.ask_price[0] == snapshot.ask_price[0]
    assert rebuilt.total_volume == snapshot.total_volume

四、典型误区与复盘

  • 误区一:把逐笔委托当成逐笔成交。逐笔委托包含未成交的挂单和撤单,只有逐笔成交才是真实撮合结果。混用会导致成交量虚高。
  • 误区二:忽略交易所字段差异。上交所和深交所的逐笔委托字段名、撤单表示方式、序号规则均不同,直接套用同一套解析逻辑必然出错。
  • 误区三:快照时间戳对齐不严谨。快照时间戳通常为交易所生成时间,而逐笔数据带有本地接收时间。若用本地时间对齐,会引入网络延迟误差,导致重建结果与快照错位。
  • 误区四:忽略集合竞价阶段。开盘前和收盘前的集合竞价阶段,逐笔数据行为与连续竞价不同,快照也可能不更新,校验时需单独处理。
实战中建议先做“序号连续性检查”,再做“逐笔重建快照比对”。如果序号本身就有跳变,后续所有一致性结论都不可信。先定位丢包,再谈一致性。