4. 订单簿快照特征构建

逐笔委托与逐笔成交是订单簿的“原始事件流”,而绝大多数特征检验与回测框架消费的是“等间隔快照”。本节要解决的核心问题是:如何用逐笔事件重建任意时刻的订单簿状态,并在快照时点上计算买卖价差、深度、斜率、压力等特征,同时保证快照频率与逐笔事件在时间轴上严格对齐,不产生前视偏差。

一、事件重放:订单簿状态的增量维护

重建订单簿的基本做法是维护两个有序结构:买侧(Bid)按价格从高到低排序,卖侧(Ask)按价格从低到高排序,每个价位挂一个数量队列。逐笔委托到达时按类型分派:限价委托插入对应价位队列;市价委托立即与对手方最优价位撮合;撤单按委托编号定位并扣减剩余量。逐笔成交则用于校验——成交回报中的价格与数量应当与订单簿撮合结果一致,若不一致说明事件流存在缺失或乱序,需要标记该时段数据不可信。

工程上常用“价格→累计量”的字典加排序键实现,但更稳妥的是用平衡树或跳表维护价位,保证插入、删除、取最优价为 O(log n)。一个关键细节是委托编号到价位的反向索引:撤单事件只带委托编号,没有价格,必须靠索引 O(1) 定位,否则重放成本会随簿深线性上升。

二、快照时点的对齐:事件时间而非墙钟时间

快照频率与逐笔事件的对齐是本节最容易出错的地方。常见错误是用墙钟时间每隔 N 秒切一刀,然后取“最近一条事件之后”的簿状态。正确做法是定义快照时点 tk,只重放时间戳 ≤ tk 的事件,得到 tk 时刻的簿状态;tk 之后的事件一律不得进入该快照。这样每个快照都是“截至该时点的信息集”,回测中用它预测 tk 之后的收益,因果方向才成立。

若逐笔事件时间戳存在同毫秒多事件,需按交易所序号(如逐笔序号、通道序号)二次排序,保证重放顺序确定。对于快照间隔,常见选择是 500ms、1s、3s;间隔越短,特征越贴近微观结构,但噪声与计算量也越大。建议在回测配置中把快照间隔作为显式参数记录,避免不同实验间口径漂移。

逐笔事件流 → 订单簿重放 → 快照特征面板 逐笔事件流 委托 #A 买 10.02×300 成交 10.03×100 撤单 #A 剩余 200 委托 #B 卖 10.04×500 成交 10.02×150 委托 #C 买 10.01×400 按时间戳 + 序号排序 订单簿状态(tₖ 时刻) 卖侧 Ask 10.05 × 400 10.04 × 500 10.03 × 200 价差 = 10.02 − 10.01 10.02 × 150 10.01 × 400 10.00 × 600 买侧 Bid 快照特征面板 买卖价差 = 0.01 盘口深度(5档) = 1850 斜率 = Δ量/Δ价 = 2500 压力 = 买量/卖量 = 1.15 中间价 = 10.015 快照时点 tₖ = 10:00:01.000

三、四类核心快照特征的计算口径

买卖价差取最优卖价减最优买价,即 Ask₁ − Bid₁;也可用相对价差 (Ask₁ − Bid₁)/中间价,后者便于跨标的比较。注意当某一侧为空(极端行情或数据缺失)时,价差应置为缺失而非 0,否则会污染后续统计。

深度通常定义为前 N 档的累计挂单量,买侧与卖侧分别计算。N 的选取要与标的 tick 和典型挂单量匹配:tick 较粗的品种用 5 档即可,tick 细的品种可能需要 10 档或按价格带宽(如中间价 ±0.1%)累计。深度是绝对量,跨标的比较时应除以近 20 日同时段均值做归一化。

斜率刻画挂单量随价格偏离的衰减速度。一种可操作口径是:对前 N 档做“累计量 ~ 价格偏离”的线性回归,取斜率;斜率越大,说明量集中在盘口附近,簿较“薄”;斜率越小,说明量分散在较远价位,簿较“厚”。回归前需固定档数 N,否则不同快照间不可比。

压力衡量买卖两侧力量对比,常用买侧前 N 档累计量除以卖侧前 N 档累计量。比值大于 1 表示买压占优。为避免除零,分母加一个极小常数;同时建议对压力取对数,使其在 1 附近对称,便于作为回归特征。

四、对齐校验与常见陷阱

构建完成后必须做三项校验。第一,因果校验:随机抽取若干快照,确认其重放所用事件的最大时间戳不超过快照时点。第二,成交校验:用快照簿对下一区间内的逐笔成交做“可成交性”检查,若出现成交价优于当时最优价且无法由簿内挂单解释,说明事件流有缺口。第三,特征连续性校验:价差、深度在相邻快照间的跳变若超过阈值,应回查该时段是否有大额撤单或数据断流。

常见陷阱:用“快照到达本地的时间”而非“交易所生成时间”做对齐,会引入网络延迟导致的前视;把撤单量当作负成交计入成交量,会扭曲压力特征;对缺失档位补零而非置缺失,会让斜率与深度在稀疏时段系统性偏低。

最后,把每个快照的特征连同时间戳、标的、快照间隔一起落成宽表,作为后续逐笔特征有效性检验的输入。特征面板的列名、单位与缺失标记应在框架层统一约定,确保不同批次重建的数据可以直接拼接回测。