第五章:订单簿重建与维护

好,咱们今天聊聊订单簿重建。这玩意儿,说白了就是交易所把海量的买卖单子,整理成一本清晰的账本。你想想看,每秒几万笔订单进来,没有一套靠谱的机制,系统早崩了。

我个人习惯把订单簿重建分成三个核心环节:数据解析、快照与增量合并、一致性校验。这三个环节环环相扣,任何一个出问题,你的交易信号就可能完全跑偏。

5.1 Level 2 / Level 3 数据解析

先说说数据源。Level 2 数据,通常包含十档或二十档的买卖盘口。Level 3 更狠,能看到每一笔挂单的详细信息。我在项目中遇到过,有些交易所的 Level 3 数据,一条消息里可能包含几十个字段。

解析的时候,我建议用 零拷贝 技术。什么意思?就是别把数据从网络缓冲区复制来复制去,直接引用原始字节流。举个例子:

// 伪代码示例:零拷贝解析订单消息
struct OrderMessage {
    uint64_t order_id;
    uint32_t price;      // 价格,单位:最小变动价位
    uint32_t quantity;   // 数量
    uint8_t  side;       // 0=买,1=卖
    uint8_t  type;       // 0=新增,1=修改,2=删除
};

// 直接映射到接收缓冲区
const OrderMessage* msg = 
    reinterpret_cast<const OrderMessage*>(buffer + offset);

避坑指南:我曾经在解析某家交易所的增量数据时,发现它的价格字段用了浮点数。嗯,这里要注意,浮点数做价格比较会出大问题。后来我统一转成了整数,按最小变动价位存储。

5.2 订单簿快照与增量合并

订单簿重建的核心逻辑,就是 快照 + 增量 模式。交易所每隔一段时间(比如 1 秒)会发一个完整的订单簿快照。平时呢,只发增量的变化。

为什么这么做?你想想看,如果每秒都发全量数据,带宽根本扛不住。我见过一个极端案例,某数字货币交易所的订单簿深度有 100 档,全量数据一次就几十 KB,每秒发一次,光数据量就够呛。

合并的逻辑其实不复杂:

  1. 收到快照,清空当前订单簿,用快照数据重建
  2. 收到增量,按 order_id 找到对应位置,更新或删除
  3. 如果增量序号不连续,说明丢了数据,必须重新请求快照

关键点:增量消息必须带序列号。我习惯用 uint64 的序列号,从 0 开始递增。一旦发现序列号跳变,立即丢弃当前订单簿,请求新的快照。宁可慢一秒,也不能用脏数据。

5.3 价格档位管理

价格档位,就是订单簿上每个价格对应的挂单总量。管理好价格档位,直接影响你的交易决策速度。

我个人喜欢用 跳表(Skip List) 或者 红黑树 来管理。为什么?因为订单簿需要支持:

  • 按价格排序(买盘从高到低,卖盘从低到高)
  • 快速查找某个价格是否存在
  • 插入和删除操作频繁

用数组?不行。你想想看,如果价格档位有 1000 个,每次插入都要移动元素,性能扛不住。用哈希表?也不行,因为你需要按价格排序。

我曾在项目中用 C++ 的 std::map(底层是红黑树),效果不错。但要注意,每次操作的时间复杂度是 O(log n),对于高频交易来说,这个开销可以接受。

数据结构 插入 删除 查找 排序
数组 O(n) O(n) O(log n) 天然有序
哈希表 O(1) O(1) O(1) 无序
红黑树 O(log n) O(log n) O(log n) 有序
跳表 O(log n) O(log n) O(log n) 有序

注意:价格档位的精度问题。有些交易所的价格档位是浮动的,比如 0.01 元一个档位。但有些是固定的,比如 0.0001 元。我建议统一用整数存储,避免浮点误差。

5.4 数据一致性校验

这是最后一道防线。订单簿数据一旦出错,你的策略就会基于错误的市场状态做决策,后果很严重。

我常用的校验手段有三个:

  1. 快照校验:每次收到快照,计算所有档位的总买卖量,跟交易所提供的校验和对比
  2. 增量校验:每条增量消息处理完后,检查订单簿的买卖盘口是否平衡
  3. 交叉校验:用多个数据源(比如两家交易所的同一品种)做对比,看价格和深度是否一致

举个例子,我曾经遇到过一个 bug:某次增量消息里,一个订单的修改操作把价格改成了负数。嗯,这明显是数据异常。我后来加了一层校验,所有价格和数量必须大于 0,否则直接丢弃这条增量。

个人经验:我建议在订单簿的每个档位上加一个 last_update_time 字段。如果某个档位超过 5 秒没有更新,就主动请求一次快照。这能有效防止数据「僵死」。

核心逻辑流程图

下面这张图,展示了订单簿重建的完整流程。从数据解析到一致性校验,每一步都不能少。

订单簿重建核心流程 交易所数据流 Level 2/3 数据解析 快照/增量? 快照 增量 清空并重建订单簿 按 order_id 更新 数据一致性校验

这张图里,最关键的就是那个菱形判断节点。快照来了,直接重建;增量来了,按 order_id 更新。但别忘了,增量消息的序列号必须连续,否则就要回退到快照模式。

总结一下:订单簿重建,本质上是一个状态机。快照是初始状态,增量是状态转移。一致性校验是状态机的守卫条件。三者缺一不可。

好了,这一章的内容就到这里。记住,订单簿是交易系统的基石,地基不稳,楼盖得再高也没用。


无相订单流研究社 微信Lucian808555