4、订单簿更新机制:增量更新 vs 快照更新,以及 Websocket 订阅

做量化交易,订单簿就是你的眼睛。眼睛要是花了,策略再牛也白搭。

今天咱们聊聊订单簿怎么更新。说白了,就是交易所怎么把最新的买卖盘口数据推给你。这里有两种主流方式:增量更新快照更新。我个人习惯把前者比作「打补丁」,后者比作「重装系统」。

4.1 快照更新:简单粗暴,但费流量

快照更新,就是交易所每隔一段时间,把整个订单簿的深度数据一次性发给你。

比如每100毫秒,你收到一个完整的买卖10档数据。这种方式实现简单,你不需要维护本地状态,拿到数据直接用就行。

但问题也很明显——数据量巨大。你想想看,如果每秒发10次快照,每次传输几千字节,一天下来流量惊人。而且高频场景下,100毫秒的延迟可能已经错过了最佳交易时机。

注意:快照更新不适合高频交易。我在项目中遇到过,用快照做高频策略,回测看着挺美,实盘一跑,延迟直接吃掉所有利润。

4.2 增量更新:轻量高效,但需要维护状态

增量更新就聪明多了。交易所只告诉你「变了什么」,而不是「全部是什么」。

比如某笔订单被吃掉了,交易所只发一条消息:「价格100.5的卖单,数量从10变成5」。你本地维护一个订单簿副本,收到消息后更新对应位置即可。

这样做的好处是带宽占用低、延迟小。但代价是——你得自己维护订单簿状态,而且必须保证增量消息不丢、不乱序。

核心要点:增量更新的前提是,你本地必须有一个「基准快照」。先拿一次完整快照,之后只接收增量。

我曾经踩过一个坑:某次Websocket断线重连后,没重新拉快照,直接收增量。结果本地订单簿和交易所对不上,策略疯狂报错。嗯,从那以后我学乖了——断线重连必须重新拉快照

4.3 增量更新的数据结构

增量消息通常长这样:

{
  "type": "incremental",
  "timestamp": 1699000000123,
  "bids": [
    [100.5, 10],   // 价格100.5,买一数量10
    [100.4, 0]     // 数量为0表示删除该档位
  ],
  "asks": [
    [101.0, 5],
    [101.2, 0]
  ]
}

注意看,数量为0表示该价格档位被清空。这是增量更新里最常见的「删除」操作。

我个人习惯在本地维护一个OrderBook类,用红黑树或跳表来存储价格档位。Python里可以用sortedcontainers库,C++用std::map,Java用TreeMap

4.4 Websocket 订阅:实时数据的通道

不管是快照还是增量,都得靠Websocket来传输。Websocket是长连接,交易所可以主动推数据给你,不用你轮询。

订阅流程一般是三步:

  1. 建立连接:用Websocket客户端连上交易所的ws地址
  2. 发送订阅消息:告诉交易所你要订阅哪个交易对的订单簿
  3. 接收数据:交易所开始推送快照或增量

举个例子,订阅币安的BTC/USDT订单簿:

// 订阅消息
{
  "method": "SUBSCRIBE",
  "params": [
    "btcusdt@depth20@100ms"  // 每100ms推送一次20档快照
  ],
  "id": 1
}

币安同时支持快照和增量两种模式。我个人建议:低频策略用快照,高频策略用增量

小技巧:订阅增量时,记得先拉一次快照作为基准。币安的做法是:你先订阅增量,然后主动请求一次快照,之后增量消息才能正确解析。

4.5 增量 vs 快照:怎么选?

直接上对比表:

对比维度 快照更新 增量更新
带宽占用
实现复杂度
延迟 较高(取决于推送间隔) 低(实时推送变化)
断线重连 简单,直接重新拉 复杂,需要重新拉快照+增量
适用场景 低频策略、数据回放 高频策略、实时交易

你想想看,如果你的策略是看1分钟K线做交易,快照完全够用。但如果你是做市商,每秒钟要更新几十次报价,那必须用增量。

4.6 实战中的避坑指南

最后分享几个我踩过的坑:

  • 乱序问题:Websocket消息可能乱序到达。我习惯在每条消息里加一个序列号,本地做排序校验。
  • 心跳检测:交易所通常每30秒发一次ping。如果连续3次没收到pong,主动重连。
  • 数据校验:每收到1000条增量后,主动拉一次快照做对比。如果偏差超过阈值,报警并重连。
  • 内存管理:订单簿的档位可能很多(比如100档)。用数组存的话,记得预分配内存,避免频繁扩容。
重要提醒:千万不要假设交易所的消息100%可靠。我曾经因为没处理乱序,导致本地订单簿价格差了0.5个点,直接亏了一笔。从那以后,我每条消息都做序列号校验。

4.7 知识体系图

下面这张图总结了订单簿更新的核心逻辑:

订单簿更新机制 交易所 快照更新 增量更新 接收完整快照 接收增量消息 直接替换本地数据 更新本地订单簿 本地订单簿状态 快照路径 增量路径

从图上可以看得很清楚:快照是「全量替换」,增量是「局部更新」。两者最终都汇聚到本地订单簿状态上。

好了,关于订单簿更新机制就聊这么多。记住一句话:快照保底,增量提效,Websocket是桥梁。下次实盘的时候,记得先拉快照再收增量,别像我一样踩坑。