2. 行情数据基础
要理解交易所行情协议,必须先回到行情数据的“源头”——撮合引擎。交易所行情不是凭空产生的,而是撮合引擎在处理订单时留下的“副产品”。本节从撮合机制出发,串联订单簿模型、Level-1/Level-2 行情、快照与逐笔的生成逻辑,并给出典型应用场景,为后续协议解析打下数据模型基础。
一、核心原理:撮合引擎如何产生行情
撮合引擎的核心任务是价格优先、时间优先地匹配买卖订单。它维护一个按价格排序的订单簿(Order Book),买单按价格从高到低、卖单按价格从低到高排列,同价位按到达时间排队。当新订单进入时,引擎尝试与对手方最优价成交,未成交部分挂入订单簿。
撮合过程中会产生两类关键事件:订单簿状态变化(新增、修改、撤销、成交)和成交明细(价格、数量、方向、时间)。行情系统正是基于这些事件,生成两种形态的数据:快照(Snapshot)与逐笔(Tick-by-Tick / Incremental)。
二、订单簿模型与 Level-1 / Level-2 行情
订单簿模型决定了行情的深度与粒度。常见分层如下:
- Level-1(L1):仅最优一档买卖价与量,即 Best Bid/Ask(BBO)。数据量小、更新频率相对低,适合行情展示、简单策略。
- Level-2(L2):多档买卖盘口(如 5 档、10 档),展示深度信息。适合做盘口压力判断、价差分析。
- 逐笔委托 / 逐笔成交:最细粒度,包含每一笔订单与成交事件,可完整重建订单簿,是高频与做市策略的基础。
不同市场对 L2 的定义略有差异:有的交易所 L2 指“多档聚合盘口”,有的则指“逐笔委托明细”。在协议解析时,必须结合交易所文档确认字段语义,不能想当然。
三、快照与逐笔的生成逻辑
快照通常由行情系统按固定周期(如每 100ms、500ms)或按事件触发,从订单簿中抽取前 N 档买卖价量,并附带时间戳、序号等元数据。逐笔则是撮合引擎每产生一个事件就推送一条增量消息,包含订单号、价格、数量、方向、事件类型等。
两者在协议中的典型关系是:先通过快照获取基准状态,再通过逐笔增量持续更新。若逐笔丢失或序号跳变,需要用新快照重新对齐。下面是一个简化的逐笔增量更新伪代码:
# 伪代码:用逐笔增量维护本地订单簿
book = load_snapshot(snapshot) # 初始快照
for tick in tick_stream:
if tick.seq != book.next_seq: # 序号不连续
book = load_snapshot(get_snapshot()) # 重新对齐
continue
if tick.type == "ADD":
book.add(tick.side, tick.price, tick.qty, tick.order_id)
elif tick.type == "CANCEL":
book.remove(tick.order_id)
elif tick.type == "TRADE":
book.match(tick.price, tick.qty)
book.next_seq += 1
四、典型应用场景与误区复盘
不同行情形态服务于不同场景:
| 行情形态 | 数据粒度 | 典型场景 | 延迟敏感度 |
|---|---|---|---|
| Level-1 快照 | 最优一档 | 行情展示、简单趋势策略 | 低 |
| Level-2 快照 | 多档盘口 | 盘口分析、价差套利 | 中 |
| 逐笔成交 | 每笔成交 | 高频、做市、微观结构研究 | 高 |
| 逐笔委托 | 每笔订单事件 | 订单簿重建、延迟套利 | 极高 |
常见误区有三:其一,把快照当作实时全量,忽略快照之间的变化需要逐笔补齐;其二,混淆“逐笔成交”与“逐笔委托”,前者只反映成交,后者才包含挂单与撤单;其三,忽视序号与时间戳,导致乱序、重复消息无法正确处理。
掌握本节的数据模型后,后续解析具体协议时,就能快速判断某条消息属于快照还是逐笔、影响订单簿的哪一部分、是否需要触发重新对齐。这是行情协议解析实战中最基础也最关键的一步。