一、订单簿基础:从零开始理解市场微观结构

做量化交易这些年,我见过不少新手一上来就盯着K线图猛看,却忽略了最底层的东西——订单簿。说实话,订单簿才是市场的「源代码」,K线只是它的编译结果。今天我们就从最基础的东西聊起。

1.1 什么是订单簿?

订单簿,说白了就是一个「等待成交的订单列表」。它记录了所有交易者挂出的、尚未成交的买卖意愿。

你可以把它想象成一个菜市场的大黑板:

  • 左边写着「我想买,出价多少,要多少斤」
  • 右边写着「我想卖,要价多少,有多少斤」
  • 中间是成交价——买卖双方达成一致的地方

我个人习惯把订单簿看作市场的「心跳」。每一笔挂单、每一次撤单,都是市场参与者在用真金白银投票。我在项目中遇到过不少次,明明K线看起来风平浪静,订单簿却暗流涌动——这种时候往往有大行情要来了。

核心要点:订单簿是市场微观结构的核心,它比K线更早反映市场情绪的变化。

1.2 限价单 vs 市价单

这两种订单类型,是交易系统最基础的「积木」。搞懂它们,后面的策略才能搭得稳。

限价单(Limit Order)

你指定一个价格,只有市场达到这个价格时才会成交。说白了就是「不到这个价我不干」。

  • 买单限价:「我只愿意在100元买入,高于100我不买」
  • 卖单限价:「我只愿意在110元卖出,低于110我不卖」

嗯,这里要注意:限价单不保证立即成交,但能保证成交价格。我曾经在写策略时犯过一个低级错误——限价单价格设得太死,结果行情一路狂奔,单子一直没成交,白白错过一波行情。

市价单(Market Order)

你不指定价格,系统以当前最优价格立即成交。说白了就是「不管多少钱,我现在就要」。

  • 买入市价单:吃掉当前卖一价的所有挂单
  • 卖出市价单:吃掉当前买一价的所有挂单

市价单的优点是「快」,缺点是「贵」。你想想看,当你用市价单买入时,实际上是在为「立即成交」这个特权付费——这个费用就是买卖价差。

我的经验:高频策略里,市价单用得越少越好。每用一次市价单,就等于给市场交了一次「流动性税」。我一般只在确定性极高的信号出现时才用市价单。

1.3 买卖盘口与价差

盘口,就是订单簿上「当前最优的买卖报价」。

术语 含义 例子
买一(Bid 1) 当前最高的买入报价 100.00元,1000股
卖一(Ask 1) 当前最低的卖出报价 100.02元,800股
价差(Spread) 卖一价 - 买一价 0.02元

价差这个东西,我刚开始做交易时根本没当回事。直到有一次,我写了一个高频策略,回测时收益曲线漂亮得不行,结果实盘一跑就亏钱。查了半天才发现——回测时我用了成交价的中间价,但实盘里每次交易都要付出半个价差的成本。高频交易里,价差就是你的「隐形杀手」。

避坑指南:我曾经在回测中忽略价差成本,导致策略实盘亏损。记住:价差是高频交易最大的隐性成本,没有之一。

1.4 订单簿的数据结构

搞量化的人,光懂概念不够,还得知道数据长什么样。下面是我常用的订单簿数据结构:

# 一个典型的订单簿数据结构
order_book = {
    'bids': [  # 买单列表,按价格从高到低排序
        {'price': 100.00, 'size': 1000, 'order_id': 'bid_001'},
        {'price': 99.98,  'size': 2000, 'order_id': 'bid_002'},
        {'price': 99.96,  'size': 1500, 'order_id': 'bid_003'},
    ],
    'asks': [  # 卖单列表,按价格从低到高排序
        {'price': 100.02, 'size': 800,  'order_id': 'ask_001'},
        {'price': 100.04, 'size': 1200, 'order_id': 'ask_002'},
        {'price': 100.06, 'size': 900,  'order_id': 'ask_003'},
    ],
    'timestamp': 1700000000.123,  # 精确到毫秒的时间戳
    'symbol': 'BTC/USDT'
}

为什么买单要按价格从高到低排?因为出价高的人优先成交。卖单则相反,要价低的人优先。这个排序规则,是撮合引擎的核心逻辑。

我建议你在本地搭建一个模拟订单簿,用Python跑一跑。代码很简单:

class OrderBook:
    def __init__(self):
        self.bids = []  # 买单
        self.asks = []  # 卖单
    
    def add_order(self, side, price, size):
        """添加订单到订单簿"""
        order = {'price': price, 'size': size}
        if side == 'buy':
            self.bids.append(order)
            # 按价格降序排列
            self.bids.sort(key=lambda x: x['price'], reverse=True)
        else:
            self.asks.append(order)
            # 按价格升序排列
            self.asks.sort(key=lambda x: x['price'])
    
    def get_spread(self):
        """计算当前价差"""
        if not self.bids or not self.asks:
            return None
        best_bid = self.bids[0]['price']
        best_ask = self.asks[0]['price']
        return best_ask - best_bid
    
    def match_order(self):
        """尝试撮合订单"""
        while self.bids and self.asks:
            best_bid = self.bids[0]
            best_ask = self.asks[0]
            if best_bid['price'] >= best_ask['price']:
                # 成交!
                trade_price = best_ask['price']
                trade_size = min(best_bid['size'], best_ask['size'])
                print(f"成交: {trade_size} @ {trade_price}")
                # 更新剩余数量
                best_bid['size'] -= trade_size
                best_ask['size'] -= trade_size
                # 移除已成交的订单
                if best_bid['size'] == 0:
                    self.bids.pop(0)
                if best_ask['size'] == 0:
                    self.asks.pop(0)
            else:
                break

这段代码虽然简单,但包含了订单簿的核心逻辑。我在做低延迟系统时,用的也是类似的思路——只不过把Python换成了C++,把列表换成了红黑树。

小技巧:实盘环境中,订单簿的更新速度极快(毫秒级)。用Python做回测没问题,但实盘建议用C++或Rust。我见过有人用Python做高频,结果订单簿更新速度跟不上行情,白白亏了不少钱。

知识体系总览

下面这张图,是我自己总结的订单簿知识体系。建议你保存下来,学完本章后对照着复习:

订单簿 什么是订单簿 未成交订单的集合 买卖双方意愿的实时记录 限价单 vs 市价单 限价单:指定价格,不保证成交 市价单:立即成交,不保证价格 买卖盘口与价差 买一:最高买入价 卖一:最低卖出价 价差 = 卖一 - 买一 订单簿数据结构 bids:买单列表(价格降序) asks:卖单列表(价格升序) timestamp:精确到毫秒的时间戳 核心:订单簿 = 市场微观结构的基石 理解订单簿,才能理解市场的真实运作

这张图把本章的知识点串起来了。你想想看,从定义到订单类型,再到盘口价差,最后落到数据结构——这是一个完整的知识闭环。搞懂了这些,后面讲高频策略时你才能跟得上。

本章小结:
  • 订单簿是市场的「源代码」,记录了所有未成交的买卖意愿
  • 限价单保价格不保成交,市价单保成交不保价格
  • 价差是高频交易最大的隐性成本,回测时一定要算进去
  • 订单簿数据结构:bids降序排列,asks升序排列

公众号:蓝海资料掘金营,微信deep3321