1. 课程导入
在量化交易、行情网关、撮合仿真与交易风控系统中,Tick增量行情与订单簿重建是连接“交易所原始数据”与“策略可用状态”的关键中间层。很多开发者第一次接触逐笔数据时,会误以为只要把买一卖一记录下来就是订单簿;真正进入实盘或回测环境后才发现,增量更新、快照对齐、序号连续性、乱序与丢包处理、撮合优先级维护,任何一环出错都会导致盘口失真。本课程的目标,是带你从零构建一套可解释、可验证、可复用的Tick增量行情处理与订单簿重建体系。
一、学习目标:从“能收到数据”到“能还原市场状态”
本课程不是单纯讲解某个API的字段含义,而是围绕一条完整数据链路展开。学完后,你应当具备以下能力:
- 理解行情协议:区分快照行情、逐笔成交、逐笔委托、增量盘口等不同消息类型,明确各自在订单簿重建中的角色。
- 掌握增量处理机制:能够根据序号、时间戳、消息类型判断连续性,处理重复、乱序、丢失与重传。
- 实现订单簿重建:从初始快照出发,按价格优先、时间优先原则维护买卖盘,支持新增、修改、删除与成交扣减。
- 建立验证与复盘能力:通过盘口交叉检查、数量守恒、序号缺口、成交回报比对,定位数据异常。
- 形成工程化路线:能够把解析、缓存、重建、校验、输出拆分为可测试模块,并接入回测或实盘系统。
核心判断标准:一个订单簿重建系统是否可靠,不取决于它能否在正常行情下显示盘口,而取决于它在丢包、乱序、撤单、部分成交、快照切换时,能否给出可解释的状态与可追溯的修复路径。
二、核心概念:Tick、增量、快照与订单簿
在进入实战前,需要统一几个高频术语。不同交易所的命名可能不同,但底层语义基本一致。
| 概念 | 含义 | 在重建中的作用 |
|---|---|---|
| Tick | 市场最小变动事件,通常指逐笔成交或逐笔委托 | 驱动订单簿状态变化的基本输入 |
| 增量行情 | 只传输发生变化的部分,如新增订单、撤单、成交 | 降低带宽,但要求本地维护完整状态 |
| 快照 | 某一时刻买卖盘口的完整切片 | 用于初始化或修复本地订单簿 |
| 订单簿 | 按价格与时间排序的未成交买卖订单集合 | 策略计算盘口、深度、价差与冲击成本的基础 |
| 序号 | 消息或订单簿版本的连续编号 | 检测丢包、乱序与重复,决定是否重同步 |
| 撮合优先级 | 价格优先、时间优先,同价按队列顺序 | 决定成交扣减与队列位置维护 |
这里最容易混淆的是“逐笔成交”和“订单簿增量”。逐笔成交告诉你“发生了什么交易”,但不一定直接告诉你“哪一笔挂单被扣减”。如果协议只提供成交价量,你需要结合订单簿队列推断扣减位置;如果协议提供委托编号,则可以直接定位订单。课程后续会分别处理这两种情况。
三、整体框架:一条可落地的数据流水线
为了避免一上来就陷入字段细节,我们先建立整体框架。一个完整的Tick增量行情与订单簿重建系统,通常包含以下层次:
- 接入层:通过WebSocket、TCP或文件回放获取原始消息,处理心跳、登录、订阅与断线重连。
- 解码层:将二进制或JSON消息解析为统一事件结构,如成交事件、委托事件、撤单事件、快照事件。
- 排序与连续性层:按序号和时间戳排序,检测缺口、重复与乱序,决定缓存、等待或触发重同步。
- 订单簿重建层:维护买卖盘价格档位与订单队列,执行新增、修改、删除、成交扣减。
- 校验层:检查买一卖一是否交叉、数量是否守恒、序号是否连续、快照与增量是否一致。
- 输出层:向策略或回测引擎输出盘口快照、深度指标、事件流与异常日志。
下面这张SVG展示了从原始行情到订单簿状态的完整数据链路,以及关键校验点。它对应本节最值得视觉化的核心结构:增量消息如何经过排序、重建与校验,最终形成可用盘口。
四、实战路线图:30章如何一步步推进
本课程共30章,整体按“基础认知—协议解析—重建算法—异常处理—工程实战—性能优化”推进。第1章建立全局观,后续章节会逐步深入。你可以把路线图理解为三个阶段:
- 第一阶段:看懂数据。理解逐笔成交、逐笔委托、快照、增量盘口的字段与语义,能够把原始消息转换为统一事件。
- 第二阶段:重建状态。实现订单簿初始化、增量更新、成交扣减、撤单删除、队列维护与盘口计算。
- 第三阶段:工程可靠。处理丢包、乱序、重连、快照切换、性能瓶颈与回测一致性,形成可上线模块。
学习建议:每章至少准备一份真实或模拟的Tick数据。不要只看代码,要用小样本逐步打印“输入消息—中间状态—输出盘口”,这样才能真正理解增量重建的每一步。
五、常见误区与复盘:为什么你的订单簿会“看起来对,实际错”
在实战中,订单簿重建最常见的误区不是代码写不出来,而是“看起来能跑,但状态已经错了”。以下问题值得提前警惕:
- 只用快照,不处理增量:快照有间隔,期间盘口变化全部丢失,策略看到的是过期状态。
- 忽略序号连续性:丢了一条撤单消息,盘口就会多出一笔永不消失的挂单。
- 把逐笔成交直接当扣减:成交价量无法直接定位订单时,必须结合队列推断,否则会扣错档位。
- 不处理乱序与重复:网络抖动或重传会导致同一消息被应用两次,数量被重复扣减。
- 不做交叉校验:买一大于卖一、数量为负、档位倒挂,都是状态错误的信号。
- 重同步策略缺失:发现缺口后继续硬跑,错误会累积,最终无法恢复。
复盘要点:每次盘口异常,都要能回答三个问题——异常从哪条消息开始?当时本地状态是什么?如果重新从快照加增量回放,能否得到一致结果?回答不了,就说明系统缺少可追溯性。
下面给出一个最小化的增量处理伪代码框架,帮助你在后续章节中建立代码结构感。它不是完整实现,而是强调“排序—校验—应用—输出”的顺序。
# 伪代码:Tick增量行情处理主循环
def on_message(raw_msg):
event = decode(raw_msg) # 解码为统一事件
if event.type == "SNAPSHOT":
order_book.reset(event.bids, event.asks, event.seq)
return
if not seq_continuous(event.seq):
buffer.push(event) # 缓存乱序或缺口消息
if gap_detected():
request_resync() # 触发快照重同步
return
apply_event(order_book, event) # 应用增量:新增/修改/删除/成交
if not validate(order_book):
log_anomaly(event)
request_resync()
publish(order_book.snapshot()) # 输出盘口
本章的核心任务,是让你先建立“数据链路—状态维护—异常校验”三位一体的认知。Tick增量行情不是简单的消息转发,订单簿重建也不是简单的买卖盘展示。只有把序号连续性、撮合优先级、快照与增量的关系、异常恢复路径想清楚,后续的代码实现和性能优化才有稳固基础。接下来,我们将从最基础的行情消息类型开始,逐层拆解这条链路中的每一个关键环节。