4. 套利信号生成:布林带法、Z-score法、固定阈值法、动态阈值法

信号生成,说白了就是回答一个问题:现在该不该进场?

我做跨期套利这些年,见过太多人把精力花在策略逻辑上,结果信号生成这块随便写个固定阈值就上线了。嗯,最后亏得挺惨。今天我把四种主流方法掰开揉碎讲清楚,每种方法我都踩过坑,希望能帮你少走弯路。

4.1 布林带法(Bollinger Bands)

布林带法是我个人最常用的方法之一。它基于一个朴素的想法:价差不会永远偏离均值。

核心公式很简单:

上轨 = 均值 + K × 标准差
中轨 = 均值
下轨 = 均值 - K × 标准差

当价差突破上轨,做空价差(卖近买远)。突破下轨,做多价差(买近卖远)。

参数怎么设?

我一般用20期窗口,K值取2。但这不是死的。我在项目中遇到过螺纹钢和热卷的套利,波动特别大,K值调到2.5才勉强不被假突破洗出去。

我的习惯:先用历史数据回测,找到最优K值。别迷信教科书上的2,市场会教你做人。

代码实现也不复杂:

def bollinger_signal(spread, window=20, k=2):
    mean = spread.rolling(window).mean()
    std = spread.rolling(window).std()
    upper = mean + k * std
    lower = mean - k * std
    
    signal = 0
    if spread.iloc[-1] > upper.iloc[-1]:
        signal = -1  # 做空价差
    elif spread.iloc[-1] < lower.iloc[-1]:
        signal = 1   # 做多价差
    return signal

4.2 Z-score法

Z-score法其实是布林带的标准化版本。它把价差转换成标准正态分布下的位置。

公式:

Z = (当前价差 - 均值) / 标准差

Z-score的好处是直观。|Z| > 2 就认为价差偏离过大,可以进场。|Z| < 0.5 就平仓。

为什么我喜欢Z-score?

因为它能跨品种比较。你想想看,螺纹钢和热卷的价差可能是50块,豆粕和菜粕的价差可能是200块。用布林带你得分别调参数,但Z-score统一用2倍标准差,省事多了。

我曾经踩过的坑:Z-score假设价差服从正态分布。但实际数据往往有厚尾特征。我见过一次极端行情,Z值飙到4.5还没回归,直接爆仓。所以建议加一个硬止损。
def zscore_signal(spread, window=20, entry_threshold=2.0, exit_threshold=0.5):
    mean = spread.rolling(window).mean()
    std = spread.rolling(window).std()
    z = (spread - mean) / std
    
    current_z = z.iloc[-1]
    if current_z > entry_threshold:
        return -1  # 做空
    elif current_z < -entry_threshold:
        return 1   # 做多
    elif abs(current_z) < exit_threshold:
        return 0   # 平仓
    return None    # 持仓不变

4.3 固定阈值法

固定阈值法,说白了就是拍脑袋定两个数。比如价差超过100块就做空,低于-50块就做多。

这种方法简单粗暴,适合刚起步的时候用。但我建议别长期依赖它。

为什么?

市场在变。去年有效的阈值,今年可能完全失效。我记得2020年做甲醇和乙二醇套利,固定阈值设的80块,前半年赚得挺好。下半年波动率翻倍,80块天天被突破,来回止损亏了20%。

方法 优点 缺点
固定阈值 简单、执行快 不适应市场变化
布林带 自适应波动率 参数敏感
Z-score 跨品种可比 正态假设不牢
动态阈值 最灵活 实现复杂

4.4 动态阈值法

动态阈值法是我现在的主力方法。它根据市场状态实时调整阈值。

核心思路:

  • 用滚动窗口计算均值和标准差
  • 根据波动率大小动态调整K值
  • 波动率大时放宽阈值,波动率小时收紧阈值

具体实现:

def dynamic_threshold(spread, window=20, base_k=2.0):
    mean = spread.rolling(window).mean()
    std = spread.rolling(window).std()
    
    # 计算波动率变化
    vol_ratio = std / std.rolling(window*2).mean()
    
    # 动态调整K值
    k = base_k * (1 + 0.5 * (vol_ratio - 1))
    
    upper = mean + k * std
    lower = mean - k * std
    
    current = spread.iloc[-1]
    if current > upper.iloc[-1]:
        return -1
    elif current < lower.iloc[-1]:
        return 1
    return 0
核心要点:动态阈值法的精髓在于K值自适应。市场安静时,K值变小,更容易捕捉小机会。市场疯狂时,K值变大,避免被假突破骗进去。

四种方法对比总结

我做个简单的对比,方便你选型:

  • 刚入门:用固定阈值法,快速跑通流程
  • 追求稳健:用布林带法,参数调好后很稳定
  • 多品种交易:用Z-score法,统一标准省心
  • 追求极致:用动态阈值法,适应各种市场环境

我个人建议,先从布林带或Z-score入手。跑顺了再升级到动态阈值。别一上来就搞复杂的,容易把自己绕晕。

套利信号生成方法对比 固定阈值法 简单但僵化 布林带法 自适应波动率 Z-score法 跨品种可比 动态阈值法 最灵活 共同目标:识别价差偏离,生成交易信号 输出:做多信号 / 做空信号 / 平仓信号 注意:所有方法都需要结合止损和仓位管理

嗯,信号生成这块就讲到这里。每种方法都有它的适用场景,关键是你得理解背后的逻辑,而不是死记硬背参数。下一节我们会聊到信号过滤和组合,到时候再细说。

专注资料整理