1. 订单簿基础:什么是订单簿?限价单与市价单的区别,订单簿在撮合引擎中的核心地位
做量化交易系统,第一个绕不开的东西就是订单簿。说白了,它就是交易所内存里的一张「实时挂单表」——谁想买、谁想卖,价格多少、数量多少,全在上面排着队。我刚开始接触撮合引擎时,觉得订单簿不就是个排序列表嘛,后来才发现,这里面的门道深着呢。
今天咱们就把订单簿的底裤扒干净。从定义到两种核心订单类型,再到它在撮合引擎里到底扮演什么角色,一步到位。
1.1 订单簿到底是什么?
订单簿,英文叫 Order Book,你可以把它想象成一个双向排队系统。一边是买单队列(Bids),按价格从高到低排;另一边是卖单队列(Asks),按价格从低到高排。交易所每时每刻都在维护这个结构。
举个例子,假设现在 BTC/USDT 的订单簿长这样:
| 方向 | 价格 (USDT) | 数量 (BTC) | 累计 |
|---|---|---|---|
| 卖单 | 30,020 | 1.2 | 4.5 |
| 卖单 | 30,010 | 2.0 | 3.3 |
| 卖单 | 30,000 | 1.3 | 1.3 |
| —— 当前价差 —— | |||
| 买单 | 29,990 | 0.8 | 2.1 |
| 买单 | 29,980 | 0.7 | 1.3 |
| 买单 | 29,970 | 0.6 | 0.6 |
看到没?卖单从最低价往上排,买单从最高价往下排。中间那个空档叫「价差」(Spread),是市场流动性的直接体现。我个人习惯把订单簿叫做「市场的毛细血管」——每一笔挂单都是流动性的一个细胞。
1.2 限价单 vs 市价单:性格完全不同的两兄弟
很多新手分不清限价单和市价单的本质区别。我一句话给你讲透:限价单指定价格,市价单指定成交意愿。
- 限价单(Limit Order):你说「我只在 30,000 以下买」,不到这个价我就不动。它会挂到订单簿里,等着被吃掉。优点是能控制成本,缺点是不一定能成交。
- 市价单(Market Order):你说「我现在就要买,不管什么价」,系统直接跟当前最优的对手单成交。优点是秒成交,缺点是可能滑点很大。
我记得有一次做回测,一个策略全用市价单,结果在流动性差的时段滑了 0.3%,直接把年化收益打没了。从那以后我对市价单就特别谨慎。
| 特性 | 限价单 | 市价单 |
|---|---|---|
| 价格控制 | 完全控制 | 无控制 |
| 成交保证 | 不保证 | 立即成交(部分或全部) |
| 对订单簿影响 | 增加流动性 | 消耗流动性 |
| 典型使用场景 | 做市、挂单策略 | 抢单、止损、大额吃单 |
1.3 订单簿在撮合引擎中的核心地位
撮合引擎说白了就干三件事:收单、对价、成交。而订单簿就是整个流程的「中央舞台」。所有限价单都挂在上面,市价单来了直接跟它碰撞。
你想想看,如果没有订单簿,市价单找谁成交?限价单挂在哪里?所以订单簿就是撮合引擎的内存数据库,而且是读写最频繁的那个。
我参与过一个期货交易所的撮合系统重构,当时订单簿的数据结构从 std::map 换成了自定义的跳表,因为 map 的插入和删除在极端行情下会触发红黑树重平衡,延迟抖动受不了。嗯,这里要注意,订单簿的每一次更新(新增、撤销、成交)都必须保证 O(log n) 甚至 O(1) 的性能,否则系统扛不住。
总结一下:订单簿是撮合引擎的心脏,限价单和市价单是两种最基本的血流方式。理解它们的区别和交互,是写出高性能撮合系统的第一步。后面我们会深入订单簿的底层数据结构、内存布局、以及如何用 C++ 和 Python 做极致优化。