3. 订单簿数据结构:订单簿的构成、买卖盘口、深度图、Level1/Level2数据

好,咱们今天聊聊订单簿。这东西,说白了就是交易所的「记账本」。

我刚开始做交易系统那会儿,以为订单簿就是个简单的价格列表。后来被坑过一次——某次行情爆发,我的订单簿更新慢了,导致撮合结果全错。嗯,从那以后,我对订单簿的数据结构就格外上心。

3.1 订单簿的构成

订单簿,英文叫 Order Book。它记录着所有未成交的买卖委托。

我个人习惯把它拆成三部分:

  • 买盘(Bid Side):所有想买入的人,按价格从高到低排列
  • 卖盘(Ask Side):所有想卖出的人,按价格从低到高排列
  • 盘口(Order Book Depth):买卖双方在每个价位上的挂单量

你想想看,交易所每秒要处理几万笔订单。如果每次都用数组遍历,那性能肯定崩。所以,订单簿的底层数据结构很关键。

核心要点:订单簿必须支持高频的增、删、改、查操作。我建议用「价格-数量」的映射结构,比如红黑树或跳表。

3.2 买卖盘口

盘口,就是当前市场上最活跃的买卖价位。

举个例子:

卖盘(Ask) 价格 买盘(Bid)
200 手 10.05
150 手 10.04
10.03 100 手
10.02 300 手
10.01 250 手

这里有个关键概念——最优买卖价

  • 最优买价(Best Bid):10.03,100 手
  • 最优卖价(Best Ask):10.04,150 手
  • 买卖价差(Spread):10.04 - 10.03 = 0.01

我曾经在开发中遇到过一个坑:盘口数据更新时,如果只更新价格不更新数量,会导致撮合逻辑误判。所以,每次盘口变动,必须同时校验价格和数量。

避坑指南:我曾经因为盘口数据延迟,导致一个高频策略在价差为0时误判为「无套利机会」。后来加了时间戳校验,才解决这个问题。

3.3 深度图

深度图,就是把盘口数据可视化。横轴是价格,纵轴是累计挂单量。

我个人觉得,深度图是交易员最直观的工具。它能告诉你:

  • 在某个价位上,有多少流动性
  • 大单砸下去,价格会滑多少
  • 市场深度够不够支撑你的交易

下面我用 SVG 画一个简单的深度图结构:

订单簿深度图示意 低价 高价 累计挂单量 买盘深度 卖盘深度 最优买卖价

为什么会这样画?因为深度图本质上就是「价格-累计量」的阶梯函数。买盘从左到右价格递增,卖盘从右到左价格递减,中间的交汇点就是当前市价。

实战技巧:我建议你在做深度图时,不要只显示前10档。有些交易所提供全量深度,但全量数据量太大。我一般取前50档,既能看清趋势,又不会太卡。

3.4 Level1 / Level2 数据

这两个概念,很多新手容易搞混。我简单说清楚:

数据级别 包含内容 更新频率 典型用途
Level 1 最优买卖价、最新成交价、成交量 秒级 散户看盘、简单策略
Level 2 多档盘口(通常10-50档)、逐笔成交 毫秒级 高频交易、做市商

说白了,Level 1 就是「精简版」,Level 2 是「完整版」。

我记得有一次,一个客户问我:「为什么我的 Level 1 数据和 Level 2 数据对不上?」

原因很简单:Level 1 是快照数据,Level 2 是增量数据。快照和增量之间有时间差,所以会有短暂的不一致。这是正常现象。

核心要点:如果你做高频策略,必须用 Level 2 数据。Level 1 的延迟太高,等你看到最优价时,可能已经成交了。

3.5 代码示例:订单簿的简单实现

下面我用 Python 写一个极简的订单簿。注意,这只是教学用途,生产环境要复杂得多。

class OrderBook:
    def __init__(self):
        # 买盘:价格从高到低
        self.bids = {}  # {price: volume}
        # 卖盘:价格从低到高
        self.asks = {}  # {price: volume}
    
    def add_order(self, side, price, volume):
        if side == 'buy':
            self.bids[price] = self.bids.get(price, 0) + volume
        else:
            self.asks[price] = self.asks.get(price, 0) + volume
    
    def get_best_bid(self):
        if not self.bids:
            return None
        return max(self.bids.keys())
    
    def get_best_ask(self):
        if not self.asks:
            return None
        return min(self.asks.keys())
    
    def get_spread(self):
        best_bid = self.get_best_bid()
        best_ask = self.get_best_ask()
        if best_bid and best_ask:
            return best_ask - best_bid
        return None

这段代码虽然简单,但已经包含了订单簿的核心逻辑。你想想看,实际生产环境里,我们还要处理:

  • 订单的撤销和修改
  • 多线程并发访问
  • 内存和性能优化
  • 数据持久化

避坑指南:我曾经在生产环境中直接用 Python 字典做订单簿,结果在高并发下出现了哈希冲突,导致数据丢失。后来改用 C++ 的跳表实现,才解决问题。

3.6 总结

订单簿数据结构,是交易系统的核心。我个人的经验是:

  • 理解买卖盘口的构成,是基础中的基础
  • 深度图能帮你快速判断市场流动性
  • Level 1 和 Level 2 数据各有用途,别混用
  • 代码实现时,注意性能和并发安全

嗯,今天就聊到这儿。记住,订单簿不是死的,它是市场情绪的实时反映。你读懂了它,就读懂了市场的一半。

专注资料整理