1. 课程导入

在量化交易、行情网关、撮合仿真与交易风控系统中,Tick增量行情与订单簿重建是连接“交易所原始数据”与“策略可用状态”的关键中间层。很多开发者第一次接触逐笔数据时,会误以为只要把买一卖一记录下来就是订单簿;真正进入实盘或回测环境后才发现,增量更新、快照对齐、序号连续性、乱序与丢包处理、撮合优先级维护,任何一环出错都会导致盘口失真。本课程的目标,是带你从零构建一套可解释、可验证、可复用的Tick增量行情处理与订单簿重建体系。

一、学习目标:从“能收到数据”到“能还原市场状态”

本课程不是单纯讲解某个API的字段含义,而是围绕一条完整数据链路展开。学完后,你应当具备以下能力:

  • 理解行情协议:区分快照行情、逐笔成交、逐笔委托、增量盘口等不同消息类型,明确各自在订单簿重建中的角色。
  • 掌握增量处理机制:能够根据序号、时间戳、消息类型判断连续性,处理重复、乱序、丢失与重传。
  • 实现订单簿重建:从初始快照出发,按价格优先、时间优先原则维护买卖盘,支持新增、修改、删除与成交扣减。
  • 建立验证与复盘能力:通过盘口交叉检查、数量守恒、序号缺口、成交回报比对,定位数据异常。
  • 形成工程化路线:能够把解析、缓存、重建、校验、输出拆分为可测试模块,并接入回测或实盘系统。

核心判断标准:一个订单簿重建系统是否可靠,不取决于它能否在正常行情下显示盘口,而取决于它在丢包、乱序、撤单、部分成交、快照切换时,能否给出可解释的状态与可追溯的修复路径。

二、核心概念:Tick、增量、快照与订单簿

在进入实战前,需要统一几个高频术语。不同交易所的命名可能不同,但底层语义基本一致。

概念含义在重建中的作用
Tick市场最小变动事件,通常指逐笔成交或逐笔委托驱动订单簿状态变化的基本输入
增量行情只传输发生变化的部分,如新增订单、撤单、成交降低带宽,但要求本地维护完整状态
快照某一时刻买卖盘口的完整切片用于初始化或修复本地订单簿
订单簿按价格与时间排序的未成交买卖订单集合策略计算盘口、深度、价差与冲击成本的基础
序号消息或订单簿版本的连续编号检测丢包、乱序与重复,决定是否重同步
撮合优先级价格优先、时间优先,同价按队列顺序决定成交扣减与队列位置维护

这里最容易混淆的是“逐笔成交”和“订单簿增量”。逐笔成交告诉你“发生了什么交易”,但不一定直接告诉你“哪一笔挂单被扣减”。如果协议只提供成交价量,你需要结合订单簿队列推断扣减位置;如果协议提供委托编号,则可以直接定位订单。课程后续会分别处理这两种情况。

三、整体框架:一条可落地的数据流水线

为了避免一上来就陷入字段细节,我们先建立整体框架。一个完整的Tick增量行情与订单簿重建系统,通常包含以下层次:

  1. 接入层:通过WebSocket、TCP或文件回放获取原始消息,处理心跳、登录、订阅与断线重连。
  2. 解码层:将二进制或JSON消息解析为统一事件结构,如成交事件、委托事件、撤单事件、快照事件。
  3. 排序与连续性层:按序号和时间戳排序,检测缺口、重复与乱序,决定缓存、等待或触发重同步。
  4. 订单簿重建层:维护买卖盘价格档位与订单队列,执行新增、修改、删除、成交扣减。
  5. 校验层:检查买一卖一是否交叉、数量是否守恒、序号是否连续、快照与增量是否一致。
  6. 输出层:向策略或回测引擎输出盘口快照、深度指标、事件流与异常日志。

下面这张SVG展示了从原始行情到订单簿状态的完整数据链路,以及关键校验点。它对应本节最值得视觉化的核心结构:增量消息如何经过排序、重建与校验,最终形成可用盘口。

Tick增量行情与订单簿重建数据链路 原始行情 WebSocket/TCP/回放 解码与归一化 成交/委托/撤单/快照 排序与连续性 序号/时间戳/缺口 订单簿重建 价格档/队列/扣减 盘口输出 深度/价差/事件 校验层:交叉检查 / 数量守恒 / 序号缺口 异常触发缓存、等待或快照重同步 异常处理:重传 / 重同步 / 告警 保证状态可追溯、可恢复 关键原则:先保证序号连续与状态一致,再追求低延迟;任何盘口输出都必须可回溯到原始消息与重建步骤。

四、实战路线图:30章如何一步步推进

本课程共30章,整体按“基础认知—协议解析—重建算法—异常处理—工程实战—性能优化”推进。第1章建立全局观,后续章节会逐步深入。你可以把路线图理解为三个阶段:

  • 第一阶段:看懂数据。理解逐笔成交、逐笔委托、快照、增量盘口的字段与语义,能够把原始消息转换为统一事件。
  • 第二阶段:重建状态。实现订单簿初始化、增量更新、成交扣减、撤单删除、队列维护与盘口计算。
  • 第三阶段:工程可靠。处理丢包、乱序、重连、快照切换、性能瓶颈与回测一致性,形成可上线模块。

学习建议:每章至少准备一份真实或模拟的Tick数据。不要只看代码,要用小样本逐步打印“输入消息—中间状态—输出盘口”,这样才能真正理解增量重建的每一步。

五、常见误区与复盘:为什么你的订单簿会“看起来对,实际错”

在实战中,订单簿重建最常见的误区不是代码写不出来,而是“看起来能跑,但状态已经错了”。以下问题值得提前警惕:

  1. 只用快照,不处理增量:快照有间隔,期间盘口变化全部丢失,策略看到的是过期状态。
  2. 忽略序号连续性:丢了一条撤单消息,盘口就会多出一笔永不消失的挂单。
  3. 把逐笔成交直接当扣减:成交价量无法直接定位订单时,必须结合队列推断,否则会扣错档位。
  4. 不处理乱序与重复:网络抖动或重传会导致同一消息被应用两次,数量被重复扣减。
  5. 不做交叉校验:买一大于卖一、数量为负、档位倒挂,都是状态错误的信号。
  6. 重同步策略缺失:发现缺口后继续硬跑,错误会累积,最终无法恢复。

复盘要点:每次盘口异常,都要能回答三个问题——异常从哪条消息开始?当时本地状态是什么?如果重新从快照加增量回放,能否得到一致结果?回答不了,就说明系统缺少可追溯性。

下面给出一个最小化的增量处理伪代码框架,帮助你在后续章节中建立代码结构感。它不是完整实现,而是强调“排序—校验—应用—输出”的顺序。

# 伪代码: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增量行情不是简单的消息转发,订单簿重建也不是简单的买卖盘展示。只有把序号连续性、撮合优先级、快照与增量的关系、异常恢复路径想清楚,后续的代码实现和性能优化才有稳固基础。接下来,我们将从最基础的行情消息类型开始,逐层拆解这条链路中的每一个关键环节。