2. 盘口数据获取与清洗实战
上一节我们建立了“盘口流动性随时段变化”的分析框架,但真正动手时,第一个拦路虎往往不是分析模型,而是数据本身。交易所Level-2行情包含逐笔委托、逐笔成交和快照三类核心数据,它们的时间戳精度、字段含义、更新节奏各不相同。如果直接拿原始报文做分时段统计,很容易得出“开盘流动性最好”这类与直觉相反的结论——原因往往不是市场,而是数据没有对齐、没有清洗、没有重建。本节我们以一条完整的处理链路,把原始Level-2数据加工成可用于分时段流动性分析的标准化数据集。
一、先看清三类数据的字段与语义差异
逐笔委托(Order)记录每一笔委托的进入、撤单与成交回报,关键字段通常包括:证券代码、委托时间(精确到毫秒或微秒)、委托序号、买卖方向、委托价格、委托数量、委托类型。逐笔成交(Trade)记录撮合结果,关键字段包括成交时间、成交序号、成交价格、成交数量、买卖方向(部分交易所提供主动方标识)。快照(Snapshot)则是按固定频率(如每3秒)对盘口十档或更多档位的切片,包含买一至买十价量、卖一至卖十价量、最新价、累计成交量等。
三者的语义差异决定了清洗策略不同:逐笔委托是“意图流”,逐笔成交是“结果流”,快照是“状态流”。分时段流动性分析通常需要从意图流和结果流重建出高频快照,再与交易所快照交叉校验。这里有一个关键约定必须提前明确:本文所有时间均以交易所撮合时钟为基准,时间戳统一转换为“当日零点起的毫秒数”,后续对齐、分桶、重建都基于这一参照系,避免跨时区或跨字段口径混乱。
二、字段解析:把二进制报文变成结构化表
交易所原始数据多为二进制或定长报文,第一步是按协议文档解析。以逐笔委托为例,解析后的目标结构应至少保留:symbol, ts_ms, seq, side, price, qty, order_type。解析时有两个易错点:一是价格字段常以“分”或“厘”为单位的整数存储,需除以对应倍数还原为元;二是数量字段可能以“股”或“手”为单位,必须与后续流动性指标口径一致。建议在解析阶段就统一为“元”和“股”,并在数据字典中固定下来。
# 示例:逐笔委托解析后的标准化字段(示例数据,非实测)
symbol ts_ms seq side price qty order_type
600000 34200000 1001 B 10.52 300 LIMIT
600000 34200120 1002 S 10.53 500 LIMIT
600000 34200235 1003 B 10.52 200 CANCEL
注意最后一行的CANCEL类型:撤单在逐笔委托中同样占一条记录,若把它当作新增委托计入委托量,会系统性高估盘口深度。解析阶段必须保留order_type,为后续过滤撤单提供依据。
三、时间对齐:让三条流落在同一时间轴上
逐笔委托和逐笔成交的时间戳来自同一撮合时钟,通常可直接比较;但快照的时间戳是“切片时刻”,与逐笔事件存在天然错位。对齐的核心原则是:以事件时间为准,快照只作为校验基准,不参与重建。具体做法是先将逐笔委托与逐笔成交按ts_ms升序合并,同一毫秒内按seq排序,形成一条统一的事件序列。对于跨日数据,还需处理“夜盘归属”问题:若交易所将夜盘计入下一交易日,则需按交易所规则调整trade_date,否则分时段统计会把夜盘错误归入前一日。
另一个常见问题是时间戳重复。同一毫秒内可能有多笔委托和成交,此时不能简单去重,而应保留全部记录并依靠seq维持顺序。若发现seq回退或跳变,说明数据存在丢包或乱序,需要标记该时间段为“不完整区间”,在后续分时段统计中降权或剔除。
四、异常值处理:识别并隔离而非直接删除
Level-2数据中的异常主要有四类:价格越界(如超出当日涨跌停板)、数量为负或为零、时间戳倒挂、以及明显的“胖手指”委托(如价格偏离最新价数十个百分点)。处理原则是先标记、后隔离、再复核,而不是一删了之。建议增加is_valid与invalid_reason两个字段,保留原始记录以便追溯。
- 价格越界:与当日涨跌停价比较,超出即标记
PRICE_OUT_OF_BAND。 - 数量异常:
qty <= 0标记QTY_INVALID;单笔数量超过该股当日平均单笔量50倍标记QTY_OUTLIER,仅隔离不删除。 - 时间倒挂:
ts_ms小于前一条记录且seq也回退,标记TS_REVERSED。 - 撤单无对应委托:撤单记录的
seq找不到原始委托,标记ORPHAN_CANCEL,这类记录不能计入任何方向的委托量。
五、快照重建:从事件流还原盘口状态
重建的目标是:在任意给定时刻t,根据此前所有有效委托和成交,还原出买十档与卖十档的价量。实现上维护两个有序结构(买盘按价格降序、卖盘按价格升序),逐条扫描事件序列:新增委托插入对应价位并累加数量;撤单从原价位扣减;成交则同时扣减被动方挂单量。每处理完一个事件,记录当前时刻的盘口状态;若需要固定频率快照(如每3秒),则在跨越时间桶边界时输出一次状态。
# 重建逻辑伪代码(示例)
for event in sorted_events:
if event.type == 'ORDER' and event.side == 'B':
bid_book[event.price] += event.qty
elif event.type == 'CANCEL':
book = bid_book if event.side == 'B' else ask_book
book[event.price] -= event.qty
elif event.type == 'TRADE':
passive = ask_book if event.aggressor == 'B' else bid_book
passive[event.price] -= event.qty
if crossed_bucket(event.ts_ms, last_bucket):
emit_snapshot(bid_book, ask_book, event.ts_ms)
重建完成后,必须与交易所快照做交叉校验:在相同时间点比较买一价、卖一价和十档总量,若偏差超过预设阈值(例如买一价不一致,或十档总量偏差超过2%),说明事件流存在缺失或解析错误,应回到解析阶段排查。校验通过的数据集,才具备分时段流动性分析的可信度。
六、产出标准化数据集与质量报告
最终交付的数据集建议按“事件表+重建快照表+质量报告”三件套组织。事件表保留全部字段与异常标记;重建快照表按固定频率输出,字段包括ts_ms, bid1~bid10, ask1~ask10, bid_qty_sum, ask_qty_sum, spread;质量报告则汇总各时段的记录数、异常占比、与交易所快照的校验偏差。下面这张图概括了从原始报文到可用数据集的完整处理链路与关键判断点。