3. 订单簿数据结构:订单簿的组成(买盘/卖盘)、价格优先与时间优先原则、Level2行情数据
好,咱们今天聊聊订单簿的数据结构。这东西听起来有点硬核,但说白了,它就是交易所用来记录所有挂单的「大账本」。我刚开始接触LOF做市时,总觉得订单簿就是个简单的价格列表,后来踩过坑才明白——数据结构设计的好坏,直接决定了你的做市策略能不能跑得稳。
3.1 订单簿的组成:买盘与卖盘
订单簿分两边:买盘(Bid)和卖盘(Ask)。买盘是大家想买入的价格和数量,卖盘是大家想卖出的价格和数量。交易所会把它们按价格排好,等着成交。
举个例子,假设现在某LOF基金的订单簿长这样:
| 买盘(Bid) | 价格 | 卖盘(Ask) |
|---|---|---|
| 5000手 | 1.200 | 3000手 |
| 8000手 | 1.199 | 6000手 |
| 12000手 | 1.198 | 9000手 |
你看,买盘最高价是1.200,卖盘最低价是1.201(假设卖盘第一档)。这个价差就是买卖价差,做市商赚的就是这个差价。我个人习惯把买盘叫「左侧」,卖盘叫「右侧」,这样在写代码时容易区分。
关键点:订单簿的深度(Depth)指的是每个价格档位上的挂单总量。深度越厚,说明市场流动性越好,大单冲击成本越低。
3.2 价格优先与时间优先原则
交易所撮合订单时,遵循两个基本原则:价格优先、时间优先。说白了就是——谁出价更好,谁先成交;出价一样时,谁先挂单,谁先成交。
价格优先:买单出价高的优先成交,卖单出价低的优先成交。这很好理解,你出1.200买,别人出1.199买,交易所肯定先满足你。
时间优先:如果两个人出价一样,比如都挂1.200买,那先挂单的人先成交。我记得有一次做回测,发现策略在模拟环境里跑得挺好,实盘却老是成交不了。后来一查,原来是模拟环境没考虑时间优先,所有同价订单都按比例成交——这跟实盘完全不一样。
避坑指南:我曾经在开发做市策略时,忽略了时间优先原则,导致策略在实盘中的成交率比回测低了30%。后来我加了个「排队位置预估」模块,才把问题解决。你想想看,如果订单簿上1.200价位已经有5000手在排队,你挂100手进去,得等前面5000手成交完才能轮到你。
3.3 Level2行情数据
普通行情只给你看五档买卖盘,Level2行情能给你看十档甚至全量订单簿。对于做市策略来说,Level2是必需品。
Level2数据包含什么?
- 十档买卖盘:比普通行情多五档,能看到更远的挂单情况
- 逐笔成交:每一笔成交的详细信息,包括成交时间、价格、数量、买卖方向
- 委托队列:每个价位上前50笔挂单的明细(部分交易所提供)
- 加权平均价:基于成交量的加权平均价格
我一般用Level2数据做两件事:一是判断大单动向,二是估算真实流动性。举个例子,如果卖一档只有100手挂着,但卖二档有5000手,那说明上方压力很大,我可能会暂时不往上做市。
小技巧:Level2数据里有个「委托队列」字段,能看到每个价位上前50笔挂单的明细。我曾经用这个数据做过一个「大单识别」模型,准确率还不错。具体做法是:如果某个价位上出现单笔挂单超过该价位总量50%的情况,就标记为「大单」,然后调整做市策略的报价宽度。
下面这张图展示了订单簿的核心数据结构,以及Level2行情如何与订单簿交互:
嗯,这里要注意一点:Level2数据虽然好,但数据量也大。如果你每秒处理1000笔逐笔成交,再加上十档订单簿的更新,对系统的实时性要求很高。我建议用C++或者Rust来处理底层数据,Python只做策略逻辑。
实战经验:我在搭建做市系统时,把订单簿数据存在内存里,用红黑树(Red-Black Tree)来维护价格排序。这样每次更新订单簿时,插入和删除操作都是O(log n)的复杂度,比用数组快得多。具体代码实现可以参考Linux内核的rbtree实现。
最后说一句,订单簿数据结构是量化交易的基石。你把它搞明白了,后面的做市策略、套利策略才能站得住脚。别急着写策略,先把数据吃透。