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 才勉强触发信号。
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区间内,配合特定的动量,信号特别准——这些规则方法很难手工写出来。
但我也得泼盆冷水:机器学习不是万能药。我在项目中遇到过,模型在回测里表现完美,一上实盘就崩。为什么?因为市场环境变了,模型学到的规律失效了。
四种方法对比
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| Z-score阈值法 | 简单直观,计算快 | 阈值难调,对异常值敏感 | 平稳价差序列 |
| 布林带法 | 可视化好,容易理解 | 滞后,趋势行情失效 | 均值回复行情 |
| 移动平均回归法 | 平滑,减少假信号 | 滞后严重 | 趋势确认 |
| 机器学习信号 | 捕捉非线性关系 | 过拟合,实盘易失效 | 数据量大、特征丰富 |
知识体系结构图
最后说一句:别想着用一种方法打天下。我自己的策略里,通常是Z-score做主信号,布林带做可视化监控,移动平均回归做确认,机器学习做辅助。四种方法配合着用,效果比单一方法好得多。