2、订单簿基础:订单簿数据结构、限价单与市价单、买卖盘口与深度

好,咱们直接进入正题。订单簿这东西,说白了就是交易所用来记录所有挂单的「大账本」。你想想看,一个市场里有人想买、有人想卖,总得有个地方把这些意愿记下来吧?订单簿就是干这个的。

我个人习惯把订单簿理解成一个「双向排队系统」。左边是买单队列,右边是卖单队列,中间是成交价。谁出价高谁排前面,谁出价低谁先成交——就这么简单。

订单簿的数据结构

先看底层实现。订单簿的核心数据结构,其实就是一个价格优先、时间优先的排序容器。

我见过不少新手问:「为什么不用数组存订单?」嗯,你想想看,一个活跃的币对可能有几万甚至几十万笔挂单,用数组遍历排序?那性能直接爆炸。

实际生产中,我们通常用红黑树跳表来实现。C++ 用 std::map,Java 用 TreeMap,Go 的话我习惯用 github.com/emirpasic/gods/trees/redblacktree

这里给个简化版的订单簿结构:

// 订单簿核心结构(伪代码)
struct OrderBook {
    // 买单:价格降序排列(最高价在前)
    map<Price, OrderQueue, greater<Price>> bids;
    // 卖单:价格升序排列(最低价在前)
    map<Price, OrderQueue, less<Price>> asks;
    
    // 每个价格档位对应一个订单队列
    struct OrderQueue {
        queue<Order> orders;  // 先进先出
        Volume totalVolume;   // 该价格总挂单量
    };
};

注意看,每个价格档位内部还有一个队列。为什么?因为同一价格可能有多个订单,得按时间顺序排队。这就是「价格优先、时间优先」的完整含义。

核心要点:订单簿的查询和修改必须在微秒级完成。做市商每秒可能要更新几百次订单簿,如果数据结构选错了,延迟直接爆炸。

限价单与市价单

这两种订单类型,是交易系统里最基础、也最重要的概念。

限价单(Limit Order):你指定一个价格,只有市场价达到这个价格时才成交。说白了就是「我只接受这个价,高了我不买,低了我不卖」。

我在项目中遇到过一个问题:有个做市策略同时挂了500个限价单,结果行情剧烈波动时,系统处理撤单和改单的速度跟不上,导致大量订单以不利价格成交。后来我们加了批量撤单价格档位合并的逻辑才解决。

市价单(Market Order):不指定价格,直接按当前最优价成交。你想想看,这就像你去菜市场说「给我来10斤土豆,多少钱都行」——成交快,但价格不可控。

市价单的坑在哪里?我举个例子:

// 市价单买入的执行过程
function executeMarketBuy(volume) {
    let remaining = volume;
    let totalCost = 0;
    
    // 从最优卖单开始吃
    for (let [price, queue] of asks) {
        let matchVolume = min(remaining, queue.totalVolume);
        totalCost += matchVolume * price;
        remaining -= matchVolume;
        
        if (remaining == 0) break;
    }
    
    // 如果卖单不够,订单部分成交或失败
    if (remaining > 0) {
        // 处理部分成交逻辑
    }
}

看到问题了吗?如果卖单深度不够,市价单会「吃掉」所有可用的卖单,然后剩下的部分要么取消,要么变成限价单继续挂着。这就是所谓的滑点——你本来想花100块买,结果因为深度不够,实际花了105块。

避坑指南:我曾经见过一个新手写的做市策略,市价单没有设置最大滑点保护。结果有一次流动性骤降,一笔市价单直接打穿了5个价格档位,亏损了十几个BP。从那以后,我所有的市价单都强制加上 maxSlippage 参数。

买卖盘口与深度

盘口(Order Book Depth)就是订单簿的可视化呈现。通常我们看到的是这样的结构:

卖5 100.50 2,000
卖4 100.40 1,500
卖3 100.30 3,000
卖2 100.20 2,500
卖1 100.10 1,000
—— —— ——
买1 100.00 800
买2 99.90 1,200
买3 99.80 2,000
买4 99.70 1,800
买5 99.60 3,500

这里有个关键概念叫价差(Spread)——就是卖1价和买1价的差值。价差越小,说明市场流动性越好。做市商赚的就是这个价差。

深度(Depth)则是指某个价格区间内的总挂单量。深度越厚,大额订单对价格的冲击就越小。

下面这张图展示了订单簿的深度结构:

订单簿深度结构图 深度 价格 价差 买单深度 卖单深度 价格越低 深度越厚 价格越高 深度越厚

你看这个图,买单深度在低价区更厚,卖单深度在高价区更厚。这符合直觉——价格越低,愿意买的人越多;价格越高,愿意卖的人越多。

实战技巧:我个人习惯用「深度斜率」来判断市场情绪。如果买单深度斜率比卖单陡,说明买方力量强,价格可能上涨。反之亦然。这个指标比单纯看价格涨跌更稳定。

订单簿的更新机制

订单簿不是静态的,它每时每刻都在变化。常见的更新事件有四种:

  • 新增订单:新限价单进入队列,按价格插入对应位置
  • 撤单:从队列中移除指定订单
  • 成交:市价单吃掉限价单,减少对应档位的挂单量
  • 改单:本质上是撤单+重新下单,但有些交易所支持原子操作

这里有个细节:改单操作如果只是改数量不改价格,很多交易所允许原地修改。但如果改了价格,就必须先撤单再重新排队。我见过有人利用这个机制做「插队」操作——先下一个低价买单,然后改单到高价,变相实现价格优先。嗯,这种骚操作一般会被交易所的风控系统拦截。

好了,订单簿的基础就这些。记住一句话:订单簿是市场的微观结构,读懂它,你就能读懂市场的每一次呼吸。


专注资料整理