3、订单簿特征提取:买卖价差(Spread)、市场深度(Depth)、订单簿不平衡(Order Book Imbalance)
做市的核心,说白了就是跟订单簿打交道。
你每天盯着盘口,看到的那些跳动的数字,其实藏着很多信息。我个人习惯,拿到一个订单簿数据,先不看价格,先看三个东西:价差、深度、不平衡。这三个特征,基本能告诉我当前市场的「脾气」。
3.1 买卖价差(Spread)—— 市场的「呼吸」
价差,就是卖一价减去买一价。听起来简单,但这里面门道不少。
为什么价差重要?
价差直接反映了市场的流动性成本。价差越小,说明买卖双方越「和气」,你进出场的成本就越低。价差突然拉大,往往意味着有大事要发生,或者流动性 provider 在撤退。
核心公式:
Spread = Ask_Price_1 - Bid_Price_1
相对价差 = Spread / Mid_Price
我在项目中遇到过一个问题:只看绝对价差,有时候会误判。比如一个100块的股票,价差0.01,看起来很窄;但一个1块的股票,价差0.01,其实已经很宽了。所以,我建议你同时关注相对价差。
实战小技巧:
我个人习惯用「加权平均价差」—— 把卖一到卖五的价差按挂单量加权。这样能更真实地反映你实际成交的成本。
3.2 市场深度(Depth)—— 市场的「厚度」
深度,就是订单簿上各个价位的挂单量。它告诉你:如果你想砸一笔大单,市场能接住多少。
深度怎么量化?
我一般看两个维度:
- 档位深度: 比如买一、买二、买三的挂单量
- 累计深度: 从买一到买N的累计挂单量
举个例子,假设我们想看看买盘前5档的深度:
def calculate_depth(order_book, levels=5, side='bid'):
"""
计算指定方向的累计深度
:param order_book: 订单簿数据,格式为 [(price, volume), ...]
:param levels: 考虑的档位数
:param side: 'bid' 或 'ask'
"""
total_volume = 0
for i in range(min(levels, len(order_book))):
price, volume = order_book[i]
total_volume += volume
return total_volume
# 使用示例
bid_depth = calculate_depth(bid_orders, levels=5, side='bid')
ask_depth = calculate_depth(ask_orders, levels=5, side='ask')
print(f"买盘前5档深度: {bid_depth}")
print(f"卖盘前5档深度: {ask_depth}")
嗯,这里要注意:深度不是越大越好。深度太大,说明市场可能处于「僵持」状态,价格不容易突破。深度突然变浅,往往是变盘的信号。
避坑指南:
我曾经犯过一个错误:只看深度绝对值,忽略了深度变化的速度。有一次,一个品种的深度在10秒内从1000手缩到100手,我还在按原来的策略做市,结果被一波流直接打穿。后来我加了一个「深度衰减率」指标,专门监控深度的变化速度。
3.3 订单簿不平衡(Order Book Imbalance)—— 市场的「情绪」
不平衡,说白了就是买盘和卖盘谁更强。这个指标,我个人觉得是做市策略里最有「灵魂」的一个。
计算公式:
def order_book_imbalance(bid_volume, ask_volume):
"""
计算订单簿不平衡度
返回值范围:[-1, 1]
正值表示买盘强,负值表示卖盘强
"""
if bid_volume + ask_volume == 0:
return 0
return (bid_volume - ask_volume) / (bid_volume + ask_volume)
# 示例
bid_depth = 1500 # 买盘总深度
ask_depth = 800 # 卖盘总深度
imbalance = order_book_imbalance(bid_depth, ask_depth)
print(f"订单簿不平衡度: {imbalance:.3f}") # 输出: 0.304
你想想看,当 imbalance 接近 1 时,说明买盘远远强于卖盘,价格大概率要涨。但这里有个陷阱:
为什么不能只看 imbalance?
因为大户会「挂假单」。我曾经见过一个场景:某品种的 imbalance 一直维持在 0.8 以上,看起来买盘很强。但那些买单都是「冰山订单」,真正能成交的只有表面那一点点。结果价格一涨,那些买单全撤了,变成了卖单。
我的改进方案:
用「加权不平衡度」—— 给近档的挂单更高的权重,远档的挂单更低的权重。这样能减少远端假单的干扰。
def weighted_imbalance(bid_orders, ask_orders, decay=0.9):
"""
加权订单簿不平衡度
:param bid_orders: 买单列表 [(price, volume), ...]
:param ask_orders: 卖单列表 [(price, volume), ...]
:param decay: 衰减系数,越远档权重越低
"""
weighted_bid = 0
weighted_ask = 0
for i, (price, volume) in enumerate(bid_orders):
weighted_bid += volume * (decay ** i)
for i, (price, volume) in enumerate(ask_orders):
weighted_ask += volume * (decay ** i)
if weighted_bid + weighted_ask == 0:
return 0
return (weighted_bid - weighted_ask) / (weighted_bid + weighted_ask)
# 使用示例
bid_orders = [(100.0, 100), (99.9, 200), (99.8, 150)]
ask_orders = [(100.1, 80), (100.2, 120), (100.3, 90)]
w_imbalance = weighted_imbalance(bid_orders, ask_orders, decay=0.8)
print(f"加权不平衡度: {w_imbalance:.3f}")
3.4 三个特征的综合运用
单独看一个指标,很容易被误导。我习惯把这三个特征放在一起看:
| 场景 | 价差 | 深度 | 不平衡 | 市场含义 |
|---|---|---|---|---|
| 正常交易 | 窄 | 适中 | 接近0 | 流动性好,适合做市 |
| 大单进场 | 突然变宽 | 一侧变深 | 偏向一侧 | 可能有机构在操作 |
| 流动性危机 | 极宽 | 极浅 | 剧烈波动 | 赶紧撤单,别玩了 |
| 假突破 | 先窄后宽 | 远端挂单多 | 突然反转 | 可能是陷阱,别追 |
说白了,这三个特征就是做市商的「三原色」。你把这三种颜色调好了,就能画出市场的真实面貌。
我的个人经验:
我一般会在策略里设置一个「特征监控面板」,实时显示这三个指标的变化曲线。当三个指标同时出现异常时,我会手动干预策略。比如,价差突然扩大 + 深度骤减 + 不平衡剧烈波动,这通常意味着市场要出大事,我会暂停所有做市活动,先观察再说。
最后,送你一张我总结的知识结构图,帮你理清这三个特征的关系:
这三个特征,你吃透了,做市策略的底层逻辑就通了。剩下的,就是怎么把这些特征用到你的策略里去。