第一章 订单簿与市场深度分析

做高频交易这些年,我每天打交道最多的东西,就是订单簿。说白了,订单簿就是交易所给你的一张实时报价单——谁想买、谁想卖、出什么价、要多少量。你想想看,没有这个,你连市场在干嘛都不知道,还谈什么策略?

我个人习惯把订单簿比作一个战场的地图。买盘是防守方,卖盘是进攻方。你要做的,就是通过这张地图,判断下一秒谁会赢。

订单簿的数据结构

先看最基础的东西。订单簿长什么样?

交易所传过来的数据,通常是一个价格-数量的映射。买盘叫Bid,卖盘叫Ask。每个价格档位(Price Level)上,挂着所有未成交的订单总量。

举个例子,一个简化的订单簿长这样:

卖盘(Ask):
  价格 100.05  数量 200
  价格 100.04  数量 150
  价格 100.03  数量 300

买盘(Bid):
  价格 100.02  数量 250
  价格 100.01  数量 180
  价格 100.00  数量 400

这里有个关键点:价格优先,时间优先。买单出价高的排前面,卖单出价低的排前面。同一个价格,先来的先成交。

我在项目中遇到过一个问题——数据量太大。期货高频的订单簿,每秒可能更新几百次。如果用Python的list去存,性能根本扛不住。后来我改用sortedcontainers库,或者直接用C++的std::map,才把延迟压下去。

我的建议: 别在Python里手写排序。用现成的有序容器,或者直接用C++扩展。你想想看,每次更新都排序,延迟能低才怪。

买卖盘口分析

盘口,就是订单簿最前面那几档。买一、卖一、买二、卖二……这些是市场最直接的博弈点。

我一般关注三个东西:

  • 价差(Spread):卖一价减去买一价。价差越小,流动性越好。做高频交易,价差就是你的成本。
  • 盘口厚度:每个价位的挂单量。厚度大,说明这个价位有支撑或阻力。
  • 挂单变化:某个价位的挂单突然增加或减少,往往意味着大资金在行动。

举个例子,如果你看到买一价100.02上突然多了500手挂单,而之前只有250手。这说明有人在护盘,或者想在这个价位吸筹。这时候,你就要小心了——价格可能跌不下去。

注意: 挂单是可以撤的。我曾经见过有人挂大单假装护盘,等别人跟单后瞬间撤单,然后反向砸盘。这叫“挂单欺诈”,做高频交易一定要防这一手。

市场深度计算

市场深度,说白了就是“你想吃掉多少量,价格会滑多少”。

计算方式很简单:从最优价格开始,累加每个价位的挂单量,直到达到目标数量。然后看平均成交价和当前价的差距。

比如,你想买1000手。当前卖一100.03有300手,卖二100.04有150手,卖三100.05有200手,卖四100.06有350手。那么:

吃掉卖一:300手,花费 300 * 100.03
吃掉卖二:150手,花费 150 * 100.04
吃掉卖三:200手,花费 200 * 100.05
吃掉卖四:350手,花费 350 * 100.06(但只需要350手中的350手)

总花费 = 300*100.03 + 150*100.04 + 200*100.05 + 350*100.06
平均成交价 = 总花费 / 1000

这个平均价和当前卖一价的差值,就是你的冲击成本。

我习惯用Python写一个快速计算函数:

def calc_market_depth(ask_book, target_qty):
    """
    ask_book: 列表,每个元素是 (price, qty),按价格升序
    target_qty: 目标买入数量
    返回: (平均成交价, 冲击成本)
    """
    total_cost = 0.0
    filled = 0
    for price, qty in ask_book:
        take = min(qty, target_qty - filled)
        total_cost += take * price
        filled += take
        if filled >= target_qty:
            break
    avg_price = total_cost / filled
    impact = avg_price - ask_book[0][0]
    return avg_price, impact

嗯,这里要注意:实际交易中,你的订单可能只吃掉一部分,剩下的会留在盘口。但做策略分析时,我们通常假设全部吃掉,这样算出来的冲击成本是上限。

盘口失衡指标构建

盘口失衡,就是买盘和卖盘的力量对比。如果买盘明显强于卖盘,价格大概率要涨。反之亦然。

最简单的指标是订单簿失衡率(Order Book Imbalance, OBI)

OBI = (买盘总量 - 卖盘总量) / (买盘总量 + 卖盘总量)

OBI的取值范围是[-1, 1]。正值表示买盘强,负值表示卖盘强。

但光看总量不够。我更喜欢看加权失衡指标——离最优价格越近的挂单,权重越大。因为近端挂单对价格的直接影响更大。

举个例子:

def weighted_imbalance(bid_book, ask_book, decay=0.9):
    """
    bid_book: 买盘列表 [(price, qty), ...],按价格降序
    ask_book: 卖盘列表 [(price, qty), ...],按价格升序
    decay: 衰减因子,越远的价位权重越小
    """
    bid_weighted = 0.0
    ask_weighted = 0.0
    weight = 1.0
    for price, qty in bid_book:
        bid_weighted += qty * weight
        weight *= decay
    weight = 1.0
    for price, qty in ask_book:
        ask_weighted += qty * weight
        weight *= decay
    return (bid_weighted - ask_weighted) / (bid_weighted + ask_weighted + 1e-8)

这个指标我用了很久。它比简单的总量失衡更敏感,能提前捕捉到盘口的变化。

实战经验: 当加权失衡指标超过0.6或低于-0.6时,往往意味着短期趋势要爆发。我曾经靠这个指标,在螺纹钢期货上抓到过一波20跳的行情。当然,也有被打脸的时候——指标到了0.8,结果瞬间反转。所以,任何指标都不是万能的。

知识体系总览

下面这张图,是我自己总结的订单簿分析框架。你可以把它当作一个检查清单:

订单簿分析 数据结构 价格-数量映射 有序容器存储 增量更新 盘口分析 价差计算 盘口厚度 挂单变化 市场深度 冲击成本 深度曲线 流动性评估 失衡指标 简单失衡率 加权失衡指标 阈值判断 应用:锁单与撤单策略

这张图把订单簿分析拆成了四个模块。数据结构是地基,盘口分析和市场深度是工具,失衡指标是决策依据。最后,所有这些都服务于锁单和撤单策略——这也是我们后面章节要深入的内容。

好了,这一章就到这里。记住一句话:订单簿是你的眼睛,但别只看表面。挂单会撤,深度会变,指标会骗人。保持怀疑,持续验证,这才是高频交易者的生存之道。


专注资料整理