3、订单不平衡指标计算:主动买盘与主动卖盘、净成交量计算、订单不平衡比率(OIR)
好,咱们直接进入正题。
订单不平衡,说白了就是——买的人多还是卖的人多。这个信号在量化交易里有多重要?我个人的经验是,很多短线策略的盈利来源,本质上就是在捕捉这种不平衡。你想想看,如果市场上买盘远远大于卖盘,价格不涨才怪。反过来也一样。
3.1 主动买盘与主动卖盘:谁在主导行情?
先搞清楚一个概念:什么是主动买盘?什么是主动卖盘?
我刚开始做交易的时候,也搞混过。后来想通了,其实就一句话——谁主动成交,谁就是主导方。
- 主动买盘(Aggressive Buy):买方直接以卖一价、卖二价……吃掉了卖单。说白了,就是买方等不及了,直接按对手盘的价格成交。
- 主动卖盘(Aggressive Sell):卖方直接以买一价、买二价……砸给了买单。就是卖方急着出手,主动降价成交。
嗯,这里要注意:被动挂单成交的不算。比如你挂了个买单在买一,等着别人来砸你,那这笔成交算主动卖盘,不是你主动买的。
核心逻辑:主动买盘代表买方力量,主动卖盘代表卖方力量。两者之差,就是净方向。
我在项目中遇到过一个问题:有些交易所的逐笔成交数据里,标记的买卖方向并不准确。比如一笔大单拆成多笔小单,方向可能被标记反了。所以后来我习惯自己算——用成交价格和买卖盘口对比来判断。
3.2 净成交量计算:简单但容易踩坑
净成交量,公式很简单:
净成交量 = 主动买盘成交量 - 主动卖盘成交量
正值表示买方力量更强,负值表示卖方占优。绝对值越大,说明不平衡越严重。
但这里有个坑——时间窗口怎么选?
我见过有人用1秒的窗口算净成交量,结果噪声大得没法看。也有人用1小时,结果信号滞后到姥姥家。我个人习惯是:
- 高频策略:用1秒或3秒窗口,配合tick级数据
- 日内策略:用1分钟或5分钟窗口
- 中低频:用15分钟以上,甚至日级别
我的建议:不要死板固定窗口。可以试试用成交量加权的方式,或者用自适应窗口——比如当成交量突然放大时,缩短窗口长度。
另外,计算的时候别忘了处理集合竞价阶段的数据。我曾经有一次没过滤掉开盘集合竞价的数据,结果净成交量算出来异常大,差点让我以为发现了什么圣杯……后来发现是集合竞价的单子被重复计算了。
3.3 订单不平衡比率(OIR):归一化才有可比性
净成交量有个问题——它是个绝对值。同样净买入1000手,在茅台和ST股票上的意义完全不同。所以我们需要一个比率:
OIR = (主动买盘成交量 - 主动卖盘成交量) / (主动买盘成交量 + 主动卖盘成交量)
OIR的取值范围在[-1, 1]之间:
- +1:全是主动买盘,没有主动卖盘(极端看多)
- -1:全是主动卖盘,没有主动买盘(极端看空)
- 0:买卖平衡
这个指标的好处是——跨品种、跨时间都可以直接比较。比如你可以把茅台的OIR和工商银行的OIR放在一起看,不会因为价格不同而失真。
| OIR值 | 市场含义 | 我的经验判断 |
|---|---|---|
| 0.7 ~ 1.0 | 强烈买方主导 | 短期可能超买,注意回调风险 |
| 0.3 ~ 0.7 | 温和买方主导 | 趋势可能延续,适合顺势 |
| -0.3 ~ 0.3 | 买卖均衡 | 观望为主,或者等突破 |
| -0.7 ~ -0.3 | 温和卖方主导 | 空头占优,谨慎做多 |
| -1.0 ~ -0.7 | 强烈卖方主导 | 短期可能超卖,注意反弹 |
注意:OIR接近±1的时候,往往意味着极端情绪。但极端情绪不一定立刻反转——我见过OIR连续+0.9以上持续了十几分钟,价格一路飙升。所以别看到OIR接近1就急着反向开仓,小心被轧空。
3.4 知识体系总览
下面这张图,我把整个订单不平衡指标的计算逻辑串起来了。你可以把它当作一个参考框架:
从这张图可以看出来,整个计算链条其实不复杂。但真正难的地方在于——数据清洗和窗口选择。我见过太多人把精力花在优化OIR公式上,结果数据源本身就有问题,算出来的东西毫无意义。
3.5 代码实现:从数据到指标
下面给一个简单的Python实现,假设你已经有了逐笔成交数据:
import pandas as pd
import numpy as np
def calculate_oir(trade_data, window='1min'):
"""
计算订单不平衡比率
参数:
trade_data: DataFrame,包含字段 ['price', 'volume', 'side']
side: 'buy'表示主动买盘, 'sell'表示主动卖盘
window: 重采样窗口,如 '1min', '5min', '1s'
返回:
oir_series: OIR时间序列
"""
# 分别计算主动买盘和主动卖盘的成交量
buy_volume = trade_data[trade_data['side'] == 'buy']['volume']
sell_volume = trade_data[trade_data['side'] == 'sell']['volume']
# 按时间窗口重采样
buy_resampled = buy_volume.resample(window).sum()
sell_resampled = sell_volume.resample(window).sum()
# 计算净成交量和总成交量
net_volume = buy_resampled - sell_resampled
total_volume = buy_resampled + sell_resampled
# 计算OIR,避免除零
oir = np.where(total_volume > 0, net_volume / total_volume, 0)
return pd.Series(oir, index=buy_resampled.index)
# 使用示例
# oir = calculate_oir(my_trade_data, window='5min')
# print(oir.tail())
一个小技巧:如果数据量很大,建议用numpy的向量化操作,别用for循环。我之前用for循环处理一天的tick数据,跑了快10分钟。改成向量化后,3秒搞定。
嗯,代码本身不复杂。但实际生产环境中,你需要处理的问题会多得多——比如数据缺失、异常值、不同交易所的数据格式差异等等。这些我在后面的章节会详细讲。
最后说一句:OIR是个好指标,但它不是万能的。我见过有人只用OIR做交易,结果在市场流动性极差的时候亏得很惨。记住,任何指标都需要结合上下文来使用。
公众号:蓝海资料掘金营,微信deep3321