4、订单簿重建:从增量更新重建完整订单簿、价格档位聚合、快照与增量合并
订单簿重建,说白了就是怎么把交易所发来的「碎片」拼成一张完整的「价格地图」。我刚开始做高频交易那会儿,觉得这事挺简单——不就是把买单卖单排个序嘛。结果第一次实盘就吃了大亏,数据对不上,策略直接崩了。嗯,这里面的坑,我今天一个一个给你讲清楚。
4.1 为什么需要订单簿重建?
交易所为了节省带宽,不会每次都把完整的订单簿发给你。你想想看,如果每秒发1000次全量快照,光网络开销就够受的。所以主流交易所的做法是:
- 定期发送快照:比如每100ms或1s发一次完整的订单簿
- 实时发送增量:每次有订单成交、撤单、新订单时,只发变化的部分
你的任务,就是把这两者合并起来。我见过不少新手直接拿增量去覆盖快照,结果价格档位全乱了。其实核心就一句话:快照是基准,增量是修正。
4.2 增量更新的数据结构
先看看交易所发来的增量长什么样。以币安的深度增量为例:
{
"e": "depthUpdate", // 事件类型
"E": 123456789, // 事件时间
"s": "BTCUSDT", // 交易对
"U": 100, // 第一更新ID
"u": 200, // 最后更新ID
"b": [ // 买单增量
["50000.00", "1.500"], // [价格, 数量]
["49990.00", "0.000"] // 数量为0表示删除该档位
],
"a": [ // 卖单增量
["50010.00", "2.000"],
["50020.00", "0.000"]
]
}
注意看,数量为0代表删除这个价格档位。这个细节我当年就踩过坑——以为0就是没变化,结果订单簿越积越厚,内存都爆了。
4.3 快照与增量的合并逻辑
合并的核心流程其实不复杂,但顺序很重要。我个人习惯这样处理:
- 获取快照:拿到当前最新的全量订单簿
- 缓存增量:把快照之后收到的所有增量存起来
- 按序应用:按更新ID从小到大,逐个应用到快照上
- 重建完成:得到最新的完整订单簿
这里有个关键点——更新ID的连续性。我曾经遇到过一次交易所网络抖动,中间丢了几个增量,结果订单簿直接错位了。所以一定要做校验:
4.4 价格档位聚合
订单簿重建完成后,你拿到的可能是「原始精度」的数据。比如比特币的价格档位可能精确到小数点后两位,但你的策略只需要整数位。这时候就需要聚合。
聚合说白了就是按指定精度合并价格档位。举个例子:
原始买单:
50000.01 -> 0.5 BTC
50000.02 -> 0.3 BTC
50000.03 -> 0.2 BTC
聚合到整数位后:
50000 -> 1.0 BTC (三档合并)
代码实现也很直接:
def aggregate_price_levels(order_book, tick_size):
"""
按tick_size聚合价格档位
:param order_book: 原始订单簿,格式 {price: volume}
:param tick_size: 聚合精度,比如0.01、1、10
:return: 聚合后的订单簿
"""
aggregated = {}
for price, volume in order_book.items():
# 向下取整到最近的tick
agg_price = (price // tick_size) * tick_size
if agg_price in aggregated:
aggregated[agg_price] += volume
else:
aggregated[agg_price] = volume
return aggregated
4.5 快照与增量合并的完整流程
把上面所有东西串起来,整个订单簿重建的流程可以用一张图来概括:
这张图把整个流程串起来了。你注意看那个「不连续」的分支——很多人觉得丢一两个增量没事,但实际上一旦错位,后面所有数据都是错的。我建议你写代码时,宁可多花100ms重新请求快照,也不要冒险用不完整的数据。
4.6 实战中的性能优化
订单簿重建看起来简单,但高频场景下性能要求极高。我分享几个优化经验:
- 用字典而不是列表:价格档位的增删改查,字典的O(1)复杂度远胜列表的O(n)
- 预分配内存:如果你知道订单簿大概有10000个档位,提前初始化字典大小,避免频繁扩容
- 批量处理增量:不要来一个增量就重建一次,攒够一批(比如10个)再统一处理
- 使用有序字典:Python的OrderedDict可以保持插入顺序,方便快速获取最优买卖价
- 快照是基准,增量是修正,两者缺一不可
- 增量ID必须连续,否则重新请求快照
- 数量为0的增量表示删除该档位
- 价格聚合用向下取整,避免档位重叠
- 性能优化:字典+批量处理+预分配
嗯,订单簿重建这块就讲这么多。说白了就是「快照打底,增量修补,聚合收尾」三步走。你写代码的时候,记得把校验逻辑写扎实了——数据质量不过关,后面策略再牛也白搭。
公众号:蓝海资料掘金营,微信deep3321