第一章:订单簿重建与维护
做市系统的核心,说白了就是一本「电子账本」——订单簿。
你想想看,每秒几万笔交易进来,订单簿要是乱了,整个系统就废了。我当年刚入行时,就遇到过订单簿数据不一致导致爆仓的事故。嗯,从那以后,我对订单簿重建这块特别较真。
1.1 从撮合引擎日志重建订单簿
交易所的撮合引擎会输出日志,记录每一笔成交、每一个撤单。我们要做的,就是把这些日志「回放」一遍,还原出当时的订单簿状态。
我个人习惯用「事件驱动」的方式来做这件事。每个日志条目就是一个事件,按时间顺序依次处理。
举个例子,日志里可能有这么几种事件:
NEW_ORDER— 新订单进来CANCEL_ORDER— 订单撤销TRADE— 订单成交(部分或全部)AMEND_ORDER— 修改订单(价格或数量)
重建时,我维护一个内存里的 OrderBook 对象。每来一个事件,就更新它。代码大概长这样:
class OrderBookReconstructor:
def __init__(self):
self.bids = {} # 价格 -> 订单列表
self.asks = {}
def apply_event(self, event):
if event.type == 'NEW_ORDER':
self._add_order(event)
elif event.type == 'CANCEL_ORDER':
self._remove_order(event.order_id)
elif event.type == 'TRADE':
self._reduce_order(event.order_id, event.quantity)
# ... 其他事件类似
这里有个坑:日志可能乱序。比如撤单事件比下单事件先到。我曾经因为这个吃过亏,后来加了个「事件缓冲队列」,等所有事件按时间戳排好序再处理。
1.2 增量更新机制
全量重建太慢了。你想想看,如果每次重启都要回放几亿条日志,黄花菜都凉了。
所以我们需要「增量更新」。说白了就是:只记录变化的部分,不重复计算不变的部分。
我常用的做法是维护一个「增量快照链」:
- 每 N 毫秒生成一个全量快照
- 两次快照之间,只记录增量事件
- 恢复时,加载最近的全量快照,再回放之后的增量事件
举个例子:
| 时间 | 操作 | 说明 |
|---|---|---|
| T0 | 全量快照 | 保存当前所有订单 |
| T0 ~ T1 | 增量事件 | 只记录新增/撤销/成交 |
| T1 | 全量快照 | 再次保存全量 |
恢复时,加载 T1 的快照,然后回放 T1 之后的增量事件。这样速度能快几十倍。
1.3 快照与回放技术
快照怎么存?我见过三种方案:
- 内存快照:直接序列化内存里的订单簿对象。快,但重启就没了。
- 文件快照:写到磁盘上。慢一点,但持久化。
- 数据库快照:存到关系型数据库里。最慢,但方便查询。
我个人习惯用「内存 + 文件」双写。内存快照用于快速恢复,文件快照用于容灾。你想想看,万一机器断电了,内存快照就没了,但文件快照还在。
回放技术这块,有个关键点:回放速度要可控。
我做过一个回放引擎,支持三种模式:
- 实时回放:按原始时间戳间隔回放,用于模拟真实环境
- 加速回放:跳过空闲期,只处理有事件的时间段
- 全速回放:不等待,一口气处理完所有事件
代码实现上,我用了「生产者-消费者」模式:
class ReplayEngine:
def __init__(self, events, mode='realtime'):
self.events = events
self.mode = mode
self.current_index = 0
def run(self):
while self.current_index < len(self.events):
event = self.events[self.current_index]
self._apply_event(event)
if self.mode == 'realtime':
time.sleep(event.interval) # 按原始间隔等待
elif self.mode == 'fast':
# 跳过空闲期
pass
# 'fullspeed' 模式不等待
self.current_index += 1
这里有个经验:全速回放时,CPU 占用会很高。我建议在回放线程里加个 time.sleep(0),让出 CPU 给其他线程。
1.4 知识体系总览
下面这张图,是我自己画的订单簿重建与维护的整体流程。你看一眼就能明白各个模块的关系:
从这张图你能看到,整个流程是:日志进来 → 解析排序 → 分两条路走(增量更新 + 快照)→ 最终合并重建出完整的订单簿。
嗯,第一章的内容就到这。订单簿重建是做市系统的地基,地基不稳,上层策略再牛也白搭。我见过太多团队在这上面栽跟头了。
公众号:蓝海资料掘金营,微信deep3321