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行情交互 买盘(Bid) 价格档位1: 1.200 5000手 价格档位2: 1.199 8000手 价格档位3: 1.198 12000手 ... 共10档(Level2) 卖盘(Ask) 价格档位1: 1.201 3000手 价格档位2: 1.202 6000手 价格档位3: 1.203 9000手 ... 共10档(Level2) 撮合引擎 价格优先 → 时间优先 Level2行情数据 十档买卖盘 | 逐笔成交 | 委托队列 | 加权平均价

嗯,这里要注意一点:Level2数据虽然好,但数据量也大。如果你每秒处理1000笔逐笔成交,再加上十档订单簿的更新,对系统的实时性要求很高。我建议用C++或者Rust来处理底层数据,Python只做策略逻辑。

实战经验:我在搭建做市系统时,把订单簿数据存在内存里,用红黑树(Red-Black Tree)来维护价格排序。这样每次更新订单簿时,插入和删除操作都是O(log n)的复杂度,比用数组快得多。具体代码实现可以参考Linux内核的rbtree实现。

最后说一句,订单簿数据结构是量化交易的基石。你把它搞明白了,后面的做市策略、套利策略才能站得住脚。别急着写策略,先把数据吃透。

专注资料整理