3. 订单簿重建排障
在交易执行成本估计中,订单簿重建是计算买卖价差、市场冲击、有效价差和到达价格的基础环节。一旦重建出的订单簿与真实市场状态不一致,后续所有成本指标都会系统性偏移。本节聚焦两类最常见的重建故障——快照频率不足与消息乱序,分析它们如何污染成本估计,并给出可操作的排障路径。
一、重建逻辑与故障定位
标准重建流程是:先取一份交易所快照(Snapshot)作为基准,再按序号(Sequence Number)依次应用增量消息(Add/Modify/Delete/Trade),使本地簿持续逼近真实簿。快照频率不足意味着基准更新太慢,增量消息累积的漂移无法被及时纠正;消息乱序则意味着增量应用顺序错误,导致价位数量、档位甚至买卖方向出现错位。两者都会让重建簿在某一时刻与真实簿产生偏差,而成本估计恰恰依赖这些时刻的盘口状态。
二、快照频率不足的偏差机制
假设某标的快照每 5 秒推送一次,而增量消息每秒约 200 条。若本地重建在两次快照之间只依赖增量,任何一条增量处理错误都会在长达 5 秒的窗口内持续放大。更隐蔽的问题是:快照本身可能滞后于增量流,若重建程序在应用增量时未严格校验“快照序号 ≤ 当前增量序号”,就会出现重复应用或漏应用。
一个可复现的教学示例:某标的真实买一价为 100.02、卖一价为 100.04,有效价差 0.02。由于快照间隔过长,重建簿在某一时点仍保留已撤销的卖一档 100.03,导致重建卖一价变为 100.03,有效价差被低估为 0.01。若按此价差估计 10 万股执行成本,价差项偏差约 1000 元(示例参数,仅用于说明量级)。排障时应先统计“快照序号与增量序号的时间差分布”,若 P95 超过设定阈值(如 2 秒),即判定快照频率不足。
三、消息乱序的识别与处理
乱序通常表现为增量消息的序号不连续:收到 seq=105 后直接收到 seq=107,而 106 迟到。若程序直接按到达顺序应用,106 到达时可能已基于过期状态修改档位,造成数量错误。正确的处理策略是维护一个按序号排序的缓冲队列,设定最大等待窗口(如 50ms 或 20 条消息),窗口内补齐后按序应用;若超时仍缺失,则丢弃缓冲并强制从最近快照重新同步。
# 增量消息序号校验伪代码(示例)
expected_seq = snapshot_seq + 1
buffer = {}
while msg := recv():
if msg.seq == expected_seq:
apply(msg)
expected_seq += 1
while expected_seq in buffer:
apply(buffer.pop(expected_seq))
expected_seq += 1
elif msg.seq > expected_seq:
buffer[msg.seq] = msg
if len(buffer) > MAX_BUFFER or timeout():
resync_from_snapshot() # 丢弃缓冲,重新拉快照
else:
drop(msg) # 过期消息,直接丢弃
四、成本估计偏差的量化与验收
修复后不能只看“订单簿看起来对了”,而要用成本指标做回归验证。建议选取同一时间窗口,分别用修复前、修复后的重建簿计算三项指标:有效价差均值、5 档深度加权价差、以及固定数量(如 5 万股)的冲击成本估计。若修复后有效价差均值向交易所公布值收敛,且冲击成本偏差幅度下降至 5% 以内(示例阈值),可判定重建链路恢复可信。排障记录中应保留快照间隔、乱序率、重同步次数三个关键参数,便于后续复盘定位同类问题。