7. 套利信号设计:基于Z-score的阈值开仓法,动态阈值与固定阈值对比
套利信号怎么设计?说白了,就是回答一个问题:价差偏离到什么程度,我们该动手?
我个人习惯用Z-score来做这个判断。为什么?因为它把不同量纲的价差序列,统一到了一个标准化的尺度上。你想想看,螺纹钢和热卷的价差,跟豆粕和菜粕的价差,数值范围完全不一样。但Z-score一算,大家就都在同一个坐标系里了。
7.1 Z-score的核心逻辑
Z-score的公式很简单:
Z = (当前价差 - 价差均值) / 价差标准差
它衡量的是:当前价差偏离均值多少个标准差。
举个例子。假设螺纹钢和热卷的价差均值是100,标准差是20。如果当前价差是140,那Z-score就是(140-100)/20 = 2.0。这意味着价差已经偏离均值2个标准差,属于比较极端的水平了。
我在项目中遇到过一个问题:直接用原始价差设阈值,比如价差超过150就开仓。结果行情一变,这个阈值就失效了。改用Z-score之后,阈值就稳定多了。
7.2 固定阈值法
固定阈值,就是设定一个固定的Z-score值作为开仓信号。比如:
- 当Z-score > 2.0,开空头套利(价差过高,预期回归)
- 当Z-score < -2.0,开多头套利(价差过低,预期回归)
- 当Z-score回到0附近,平仓
代码实现也很直接:
import numpy as np
import pandas as pd
def fixed_zscore_signal(spread, window=20, threshold=2.0):
"""
固定阈值Z-score信号生成
"""
mean = spread.rolling(window).mean()
std = spread.rolling(window).std()
zscore = (spread - mean) / std
signal = pd.Series(0, index=spread.index)
signal[zscore > threshold] = -1 # 开空
signal[zscore < -threshold] = 1 # 开多
# 回归平仓
signal[(zscore > -0.5) & (zscore < 0.5)] = 0
return signal, zscore
固定阈值的好处是简单、直观、回测结果容易解释。但问题也很明显:市场在变,阈值不变。
7.3 动态阈值法
动态阈值,就是让阈值随着市场波动率的变化而调整。核心思路是:波动大的时候,阈值放宽;波动小的时候,阈值收紧。
具体做法有很多种,我常用的是基于滚动窗口的百分位数法:
def dynamic_zscore_signal(spread, window=20, percentile=95):
"""
动态阈值Z-score信号生成
阈值基于滚动窗口的百分位数动态调整
"""
mean = spread.rolling(window).mean()
std = spread.rolling(window).std()
zscore = (spread - mean) / std
# 动态计算阈值
upper_threshold = zscore.rolling(window).quantile(percentile/100)
lower_threshold = zscore.rolling(window).quantile(1 - percentile/100)
signal = pd.Series(0, index=spread.index)
signal[zscore > upper_threshold] = -1
signal[zscore < lower_threshold] = 1
signal[(zscore > -0.5) & (zscore < 0.5)] = 0
return signal, zscore, upper_threshold, lower_threshold
还有一种更精细的做法,是用GARCH模型预测波动率,然后动态调整阈值。不过说实话,对于大多数商品套利,滚动百分位数法已经够用了。
7.4 两种方法的对比
| 对比维度 | 固定阈值 | 动态阈值 |
|---|---|---|
| 实现难度 | 低,一行代码搞定 | 中等,需要滚动计算 |
| 适应性 | 差,市场变了就失效 | 好,自动适应波动率变化 |
| 回测稳定性 | 参数敏感,容易过拟合 | 相对稳健,参数容忍度高 |
| 交易频率 | 波动大时频繁触发 | 自动调节,频率更合理 |
| 适用场景 | 波动率稳定的品种 | 波动率变化大的品种 |
我的建议:先用固定阈值做快速回测,验证策略逻辑是否成立。如果逻辑成立但回测结果不稳定,再切换到动态阈值。不要一上来就搞复杂的动态模型,容易陷入过度优化的陷阱。
7.5 核心逻辑流程图
下面这张图,把整个信号设计的流程串起来了:
7.6 实际应用中的避坑指南
嗯,这里要注意几个容易翻车的地方:
- 窗口长度的选择:窗口太短,Z-score会频繁跳动;窗口太长,对市场变化反应迟钝。我个人习惯用20-60个交易日,具体看品种的波动周期。
- 极端值的处理:价差数据偶尔会出现极端值,比如交割月前的异常波动。我建议先做3倍标准差截断,再算Z-score。
- 阈值不要对称:很多人的第一反应是上下阈值对称,比如±2.0。但实际中,价差的分布往往有偏。我曾经在豆粕菜粕套利中,发现上阈值2.5、下阈值1.8效果更好。
一个小技巧:在回测时,把固定阈值和动态阈值的结果放在一起对比。如果两者差异不大,说明市场波动率比较稳定,用固定阈值就够了。如果差异很大,那动态阈值大概率是更优的选择。
最后说一句:信号设计只是套利策略的第一步。信号再好,如果执行环节出了问题,照样赚不到钱。下一节我们会聊到仓位管理和风险控制,那才是真正决定盈亏的关键。
公众号:蓝海资料掘金营,微信deep3321