4、OBI指标计算:实时计算买卖压力差、标准化处理、阈值设定
好,咱们进入正题。
前面聊了订单簿的基础结构,也讲了不平衡的基本逻辑。现在该动手了——怎么把「买卖压力差」这个抽象概念,变成一行行能跑的代码。
我个人习惯把OBI指标的计算拆成三步:原始压力差 → 标准化 → 阈值判定。每一步都有坑,我一个个说。
4.1 原始买卖压力差:从盘口数据到单边信号
先看最朴素的定义。
订单簿不平衡,说白了就是买盘和卖盘谁更「重」。我见过很多新手直接拿「买一量 - 卖一量」来算,结果被庄家挂单耍得团团转。你想想看,如果有人在买一挂了1000手,但卖一到卖五全是空单,这能说明买盘强吗?
所以我的做法是:取多档深度加权求和。
公式长这样:
OBI_raw = (∑(bid_volume_i * weight_i) - ∑(ask_volume_i * weight_i)) / (∑(bid_volume_i * weight_i) + ∑(ask_volume_i * weight_i))
其中权重 weight_i 我习惯用指数衰减:weight_i = e^(-λ * i)。λ取0.5左右,近档权重大,远档权重小。这样既考虑了深度,又不会被远端虚挂单干扰。
核心要点:OBI_raw 的取值范围是 [-1, 1]。正值表示买盘压力大,负值表示卖盘压力大。0表示均衡。
我在项目中遇到过一个问题:不同币种、不同交易所的盘口档位数量不一样。有的只有5档,有的有50档。如果统一取前5档,信息损失太大;如果全取,又没法横向对比。
我的解决方案是:统一取前10档,不足10档的用0补齐。这样既保留了大部分流动性信息,又保证了计算的一致性。
4.2 标准化处理:让不同品种站在同一起跑线
好,现在你算出了OBI_raw。但问题来了——
比特币的OBI_raw是0.3,以太坊的是0.5。能说以太坊的买盘压力更大吗?
不一定。因为不同品种的波动特性、流动性深度都不一样。0.3在比特币可能已经是极端值,在以太坊可能只是正常波动。
所以需要标准化。
我常用的方法有两种:
| 方法 | 公式 | 适用场景 |
|---|---|---|
| Z-score标准化 | OBI_z = (OBI_raw - μ) / σ | 历史数据充足,波动稳定的品种 |
| Min-Max标准化 | OBI_mm = (OBI_raw - min) / (max - min) | 新上市品种,或需要固定阈值区间 |
我个人更偏爱Z-score。为什么?因为它能告诉你当前的不平衡程度「偏离均值多少个标准差」。说白了,就是看这个信号有多「异常」。
我的经验:计算μ和σ时,建议用滚动窗口,比如过去24小时的5分钟切片。窗口太短容易过拟合,太长又反应迟钝。我一般取1440个数据点(24小时×60分钟/5分钟),效果比较稳。
嗯,这里要注意:标准化参数需要定期更新。我曾经吃过亏——用了一年前的μ和σ,结果市场结构变了,标准化后的信号全是噪音。现在我的做法是每天凌晨重新计算一次参数。
4.3 阈值设定:从连续信号到离散交易信号
标准化之后,你得到的是一个连续值。但交易决策需要的是「开仓」或「不开仓」的二元信号。
所以需要设定阈值。
阈值怎么定?我总结了三类方法:
- 固定阈值法:比如OBI_z > 2.0 开多,OBI_z < -2.0 开空。简单粗暴,但需要根据品种手动调参。
- 分位数法:取历史数据的90%分位数作为阈值。这样能保证信号出现的频率稳定,比如每天出现5-10次。
- 动态阈值法:根据当前波动率调整阈值。波动大时放宽,波动小时收紧。我常用ATR(平均真实波幅)来动态调整。
避坑指南:我曾经把阈值设得太低(比如1.5个标准差),结果一天触发上百次信号,手续费都亏麻了。后来改成2.5个标准差,信号质量明显提升。记住:阈值不是越高越好,也不是越低越好,而是要和你的交易频率、手续费成本匹配。
下面是我实际项目中用的代码片段:
def calculate_obi(bids, asks, lambda_decay=0.5, z_threshold=2.0):
# 计算加权买卖量
bid_weighted = sum([vol * np.exp(-lambda_decay * i) for i, vol in enumerate(bids[:10])])
ask_weighted = sum([vol * np.exp(-lambda_decay * i) for i, vol in enumerate(asks[:10])])
# 原始OBI
obi_raw = (bid_weighted - ask_weighted) / (bid_weighted + ask_weighted + 1e-8)
# Z-score标准化(假设已有滚动均值和标准差)
obi_z = (obi_raw - rolling_mean) / rolling_std
# 阈值判定
if obi_z > z_threshold:
signal = 'BUY'
elif obi_z < -z_threshold:
signal = 'SELL'
else:
signal = 'NEUTRAL'
return obi_raw, obi_z, signal
这段代码我用了好几年,核心逻辑没变过。唯一调整的就是 lambda_decay 和 z_threshold 这两个参数——不同市场、不同周期,最优值差别很大。
4.4 本章知识体系:一张图说清楚
下面这张SVG图,把OBI指标计算的完整流程画出来了。从原始盘口数据,到最终的交易信号,每一步的输入输出都很清楚。
这张图我每次培训都会用。你看,从左到右是数据流,从上到下是决策流。每一步都清晰可追溯——这也是量化交易的核心:可解释、可复现、可优化。
一个小技巧:在实际部署时,我会把OBI_raw、OBI_z、signal三个值都记录下来。这样回测时能分析「到底是哪一步出了问题」。比如发现OBI_z很高但没赚钱,那可能是阈值设错了;如果OBI_raw本身就没区分度,那就要回头改权重参数。
好了,OBI指标的计算就这些。说白了就是三步:算压力差、标准化、设阈值。每一步都有细节,但核心逻辑不复杂。你动手写一遍代码,跑几个品种的数据,很快就能找到感觉。
公众号:蓝海资料掘金营,微信deep3321