4. 信号生成逻辑:Z-score阈值与开平仓规则

好,咱们进入正题。前面几章我们把配对关系算出来了,价差序列也构造好了。现在的问题是——什么时候进场?什么时候离场?

说白了,信号生成就是给交易系统装上一双眼睛。让它能识别出「机会来了」和「该走了」这两个关键时刻。

我个人习惯用Z-score来做这个判断。为什么?因为它简单、直观,而且经过大量实盘验证,效果相当稳定。

4.1 Z-score:把价差变成标准分数

先回忆一下Z-score的定义:

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

嗯,其实就是把价差序列标准化。Z-score告诉你当前价差偏离均值多少个标准差。比如Z=2,意味着当前价差比均值高了两个标准差。

我在项目中遇到过一个问题:直接用原始价差设阈值,不同时间段的阈值完全不一样。牛市里价差波动大,熊市里波动小。用Z-score一标准化,所有问题都解决了。

核心思想:Z-score把不同时间段的价差拉到同一个尺度上比较。阈值设置变得通用且可复用。

4.2 阈值设置:开仓与平仓的触发条件

阈值怎么设?我一般用±2作为开仓阈值,±0.5作为平仓阈值。当然这不是死规矩,你可以根据品种波动性调整。

信号类型 Z-score范围 操作
开多信号 Z ≤ -2 买入弱势股,卖出强势股
开空信号 Z ≥ 2 买入强势股,卖出弱势股
平多信号 Z ≥ -0.5 平掉多头仓位
平空信号 Z ≤ 0.5 平掉空头仓位

你想想看,为什么开仓阈值设得比平仓阈值大?因为我们要确保价差确实偏离到了极端位置,这时候回归的概率才高。而平仓时,价差只要回到均值附近就可以走了,没必要等到完全归零。

我的经验:如果交易频率太高,可以适当提高开仓阈值到±2.5。如果信号太少,就降低到±1.8。这需要根据回测结果动态调整。

4.3 开仓规则:什么时候进场

开仓规则其实就两条:

  1. Z-score突破阈值:比如Z从-1.5跌到-2.1,触发开多信号
  2. 确认信号:我个人习惯加一个确认条件——突破后至少维持一个周期,防止假突破

举个例子:

def generate_entry_signal(z_score, threshold=2.0):
    """
    生成开仓信号
    返回: 1=开多, -1=开空, 0=无信号
    """
    if z_score <= -threshold:
        return 1  # 开多:价差过低,预期回归
    elif z_score >= threshold:
        return -1  # 开空:价差过高,预期回归
    else:
        return 0

代码很简单对吧?但实际交易中,我还会加一个「冷却期」——开仓后至少等5个周期才能再次开仓。为什么?因为价差可能在阈值附近来回震荡,频繁开仓会亏死手续费。

注意:千万不要在Z-score刚突破阈值时就全仓杀入。我曾经吃过这个亏,价差突破后继续往极端方向跑,结果被套了好几天。建议分批建仓,或者等一个回调确认。

4.4 平仓规则:什么时候离场

平仓比开仓更重要。为什么?因为开仓决定你赚不赚钱,平仓决定你赚多少。

我常用的平仓规则有三种:

  • 均值回归平仓:Z-score回到±0.5以内,说明价差已经回归
  • 止损平仓:Z-score继续往极端方向跑,比如从2跑到3,说明配对关系可能失效了
  • 时间平仓:持仓超过N个周期,强制平仓。防止死扛
def generate_exit_signal(z_score, position, stop_loss=3.0, mean_revert=0.5):
    """
    生成平仓信号
    position: 当前持仓方向 (1=多头, -1=空头, 0=空仓)
    """
    if position == 1:  # 持有多头
        if z_score >= -mean_revert:
            return 1  # 均值回归平仓
        elif z_score <= -stop_loss:
            return 1  # 止损平仓
    elif position == -1:  # 持有空头
        if z_score <= mean_revert:
            return -1  # 均值回归平仓
        elif z_score >= stop_loss:
            return -1  # 止损平仓
    return 0  # 不平仓

嗯,这里要注意:止损阈值一定要比开仓阈值大。比如开仓用±2,止损用±3。留出足够的缓冲空间,避免被正常波动震出去。

4.5 完整的信号生成流程

把上面这些整合起来,就是一个完整的信号生成系统。我画了一张流程图,帮你理清逻辑:

Z-score信号生成流程图 计算当前Z-score 是否已有持仓? 检查平仓条件 Z-score回到均值?或触发止损? 或持仓超时? 执行平仓 检查开仓条件 Z-score突破阈值? 且确认信号? 执行开仓 每次新数据到来,重复此流程 开仓阈值±2,平仓阈值±0.5,止损阈值±3

4.6 实战中的避坑指南

最后分享几个我踩过的坑:

  • 窗口期选择:计算Z-score用的滚动窗口不能太短也不能太长。太短(比如20期)信号太多,假信号也多。太长(比如200期)反应太慢。我一般用60期,也就是过去60个交易日的价差数据。
  • 极端行情处理:2015年股灾时,很多配对关系瞬间崩溃。Z-score直接飙到10以上。这时候千万别按正常逻辑开仓,先暂停交易,等市场稳定再说。
  • 手续费影响:高频交易的手续费是隐形杀手。我建议在回测时把手续费算进去,如果信号频率太高,适当降低阈值或者增加确认条件。

一个小技巧:可以在Z-score基础上加一个「动量过滤器」。比如只有当Z-score的绝对值在增加(即价差正在加速偏离)时才开仓。这样能过滤掉很多震荡行情中的假信号。

好了,信号生成逻辑就讲到这里。记住一句话:好的信号系统,开仓要谨慎,平仓要果断。下一章我们聊聊如何用Python实现这个系统的回测框架。


公众号:蓝海资料掘金营,微信deep3321