4、交易信号生成:Z-score阈值法、布林带法、移动平均回归法、机器学习信号

信号生成,说白了就是决定「什么时候开仓、什么时候平仓」。

我个人习惯把这部分叫做策略的「扳机」。没有扳机,再好的价差分析也只是纸上谈兵。今天咱们一口气聊四种主流方法:Z-score阈值法、布林带法、移动平均回归法,还有机器学习信号。每一种我都踩过坑,咱们边聊边避雷。

4.1 Z-score阈值法:最经典的统计信号

Z-score 的原理其实很简单——它衡量当前价差偏离均值多少个标准差。

# 计算Z-score
import numpy as np

def calculate_zscore(spread, window=20):
    mean = np.mean(spread[-window:])
    std = np.std(spread[-window:])
    if std == 0:
        return 0
    return (spread[-1] - mean) / std

# 生成信号
z = calculate_zscore(spread)
if z > 2.0:
    signal = -1  # 做空价差
elif z < -2.0:
    signal = 1   # 做多价差
else:
    signal = 0   # 观望

阈值选多少?我一般用 ±2.0 作为初始值。但注意——这不是死规矩。我在项目中遇到过,有些品种波动率特别低,±1.5 就够用了;有些高波动的品种,±2.5 才勉强触发信号。

我的经验:先用历史数据跑一遍,看看Z-score的分布。如果90%的时间都在±1.5以内,那阈值设到±2.0基本没信号。反过来,如果经常突破±3.0,说明你的价差序列可能不平稳,先回去做协整检验。

4.2 布林带法:可视化信号生成

布林带法其实是Z-score的「可视化版本」。它用移动均线做中轨,上下轨是均线加减K倍标准差。

def bollinger_signal(spread, window=20, k=2):
    ma = np.mean(spread[-window:])
    std = np.std(spread[-window:])
    upper = ma + k * std
    lower = ma - k * std
    
    current = spread[-1]
    if current > upper:
        return -1  # 触及上轨,做空
    elif current < lower:
        return 1   # 触及下轨,做多
    else:
        return 0

嗯,这里要注意:布林带法有个隐含假设——价差会回归中轨。但万一趋势来了呢?价差可能沿着上轨一直跑。我曾经在螺纹钢和热卷的套利上吃过这个亏,布林带连续触发三次做空信号,结果价差越拉越大,亏得我头皮发麻。

避坑指南:布林带法只适合均值回复行情。如果价差有明显的趋势性,建议配合趋势过滤器使用。比如先判断价差是否在合理区间内,再决定是否用布林带信号。

4.3 移动平均回归法:平滑信号的利器

移动平均回归法,说白了就是用两条不同周期的均线来生成信号。短周期均线上穿长周期均线,做多;下穿,做空。

def ma_cross_signal(spread, short_window=5, long_window=20):
    short_ma = np.mean(spread[-short_window:])
    long_ma = np.mean(spread[-long_window:])
    
    # 判断交叉
    prev_short = np.mean(spread[-short_window-1:-1])
    prev_long = np.mean(spread[-long_window-1:-1])
    
    if prev_short <= prev_long and short_ma > long_ma:
        return 1   # 金叉,做多
    elif prev_short >= prev_long and short_ma < long_ma:
        return -1  # 死叉,做空
    else:
        return 0

这个方法的好处是平滑——不会像Z-score那样频繁跳动。但缺点也很明显:滞后。你想想看,均线本身就是滞后指标,等它交叉了,行情可能已经走了一半。

我个人的习惯是:把移动平均回归法作为「辅助确认信号」。比如Z-score触发了开仓,但均线还没交叉,我就再等等。等均线也确认了,再进场。虽然会错过一些机会,但胜率明显提高。

4.4 机器学习信号:从规则到预测

前面三种方法都是基于规则的。机器学习不一样——它试图从历史数据中「学」出信号模式。

# 简单的逻辑回归信号
from sklearn.linear_model import LogisticRegression
import pandas as pd

# 构造特征:价差、Z-score、布林带位置、动量等
def build_features(spread):
    df = pd.DataFrame({'spread': spread})
    df['zscore'] = (spread - spread.rolling(20).mean()) / spread.rolling(20).std()
    df['momentum'] = spread.diff(5)
    df['bb_position'] = (spread - spread.rolling(20).mean()) / (spread.rolling(20).std() * 2)
    return df.dropna()

# 训练模型
features = build_features(spread)
X = features[['zscore', 'momentum', 'bb_position']]
y = (features['spread'].shift(-1) > features['spread']).astype(int)  # 预测未来价差上涨

model = LogisticRegression()
model.fit(X[:-100], y[:-100])

# 生成信号
prob = model.predict_proba(X[-1:])[0][1]
signal = 1 if prob > 0.6 else (-1 if prob < 0.4 else 0)

机器学习的好处是能捕捉非线性关系。比如价差在某个Z-score区间内,配合特定的动量,信号特别准——这些规则方法很难手工写出来。

但我也得泼盆冷水:机器学习不是万能药。我在项目中遇到过,模型在回测里表现完美,一上实盘就崩。为什么?因为市场环境变了,模型学到的规律失效了。

核心建议:机器学习信号一定要配合「失效检测」。比如每周检查一次模型的预测准确率,如果连续低于50%,就自动切换回规则方法。别迷信模型,它只是工具。

四种方法对比

方法 优点 缺点 适用场景
Z-score阈值法 简单直观,计算快 阈值难调,对异常值敏感 平稳价差序列
布林带法 可视化好,容易理解 滞后,趋势行情失效 均值回复行情
移动平均回归法 平滑,减少假信号 滞后严重 趋势确认
机器学习信号 捕捉非线性关系 过拟合,实盘易失效 数据量大、特征丰富

知识体系结构图

交易信号生成方法体系 交易信号生成 Z-score阈值法 布林带法 移动平均回归法 机器学习信号 均值±2σ 阈值动态调整 中轨±Kσ 趋势过滤器 金叉/死叉 辅助确认信号 特征工程 失效检测 核心原则:没有最好的方法,只有最合适的方法

最后说一句:别想着用一种方法打天下。我自己的策略里,通常是Z-score做主信号,布林带做可视化监控,移动平均回归做确认,机器学习做辅助。四种方法配合着用,效果比单一方法好得多。

专注资料整理