第六章:交易信号生成——阈值设定与信号过滤

信号生成,说白了就是给策略装上一双「眼睛」。什么时候该进场?什么时候该跑路?止损设在哪?这些问题的答案,都藏在阈值设定和信号过滤里。

我做了这么多年量化,见过太多策略在回测里跑得漂亮,一上实盘就崩。原因往往不是策略逻辑有问题,而是信号处理太粗糙。今天咱们就把这块硬骨头啃下来。

6.1 阈值设定方法

阈值,就是判断信号是否有效的「门槛」。门槛设得太低,假信号满天飞;设得太高,真机会全错过。这里有两种主流方法:固定阈值和动态阈值。

6.1.1 固定阈值

固定阈值最简单,也最直接。比如价差超过2个标准差就开仓,回到0.5个标准差就平仓。我早期做股指期货跨期套利时,用的就是这套逻辑。

核心思路:基于历史统计量(均值、标准差)设定固定数值,不随时间变化。

# 固定阈值示例:基于历史标准差
import numpy as np

def fixed_threshold(spread, window=60):
    mean = np.mean(spread[-window:])
    std = np.std(spread[-window:])
    
    open_long = spread[-1] < mean - 2 * std   # 开多信号
    open_short = spread[-1] > mean + 2 * std  # 开空信号
    close_all = abs(spread[-1] - mean) < 0.5 * std  # 平仓信号
    
    return open_long, open_short, close_all

嗯,这里要注意:固定阈值对市场结构变化非常敏感。我记得2020年3月那波行情,很多用固定阈值的策略直接被打穿。为什么?因为波动率变了,但阈值没变。

避坑指南:我曾经用固定阈值做螺纹钢和热卷的跨品种套利,回测三年年化15%。结果实盘第二个月就亏了8%。后来发现是样本期内波动率偏低,阈值设得太窄,实盘里假信号太多。

6.1.2 动态阈值

动态阈值,就是让阈值跟着市场走。波动大的时候放宽,波动小的时候收紧。我个人习惯用滚动窗口的均值和标准差,或者用EWMA(指数加权移动平均)来动态调整。

# 动态阈值示例:EWMA动态调整
def dynamic_threshold(spread, decay=0.05):
    # 计算EWMA均值和标准差
    ewma_mean = spread.ewm(alpha=decay).mean()
    ewma_std = spread.ewm(alpha=decay).std()
    
    current_mean = ewma_mean.iloc[-1]
    current_std = ewma_std.iloc[-1]
    
    # 动态阈值:2倍滚动标准差
    upper = current_mean + 2 * current_std
    lower = current_mean - 2 * current_std
    
    return lower, upper

动态阈值的好处是自适应。你想想看,市场波动率从10%飙到30%,固定阈值还在用原来的标准,那不是找死吗?动态阈值会自动调整,说白了就是「见人说人话,见鬼说鬼话」。

方法 优点 缺点 适用场景
固定阈值 简单、回测快、逻辑清晰 对市场结构变化敏感 波动率稳定的品种
动态阈值 自适应、鲁棒性强 参数敏感、过拟合风险 波动率变化大的品种

6.2 开仓信号与平仓信号

阈值设好了,接下来就是具体的开仓和平仓逻辑。这里我分享一套我自己用了多年的框架。

6.2.1 开仓信号设计

开仓信号,核心就四个字:价差偏离。当价差偏离到一定程度,我们认为市场出现了定价错误,这时候进场。

  • 开多信号:价差低于下阈值(价差被低估,做多价差)
  • 开空信号:价差高于上阈值(价差被高估,做空价差)

但光有阈值还不够。我建议加一个确认条件,比如价差连续N根K线都在阈值之外,或者成交量放大配合。为什么?因为单根K线的突破可能是噪音。

个人经验:我在做豆粕和菜粕的跨品种套利时,发现单纯用阈值开仓,胜率只有55%。后来加了「连续3根5分钟K线都在阈值外」的确认条件,胜率直接提到68%。

6.2.2 平仓信号设计

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

我常用的平仓逻辑有三种:

  1. 回归平仓:价差回到均值附近(比如0.5倍标准差内)
  2. 目标平仓:价差达到预设的目标位(比如3倍标准差)
  3. 时间平仓:持仓超过一定时间(比如24小时)强制平仓
# 综合平仓信号示例
def close_signal(spread, mean, std, hold_time):
    # 回归平仓
    if abs(spread - mean) < 0.5 * std:
        return "回归平仓"
    # 目标平仓
    if abs(spread - mean) > 3 * std:
        return "目标平仓"
    # 时间平仓
    if hold_time > 24 * 60:  # 24小时
        return "时间平仓"
    return None

6.3 止损信号设计

止损,是量化交易者的最后一道防线。我见过太多人,策略逻辑没问题,就是不舍得止损,最后爆仓出局。

止损信号设计,我建议从三个维度考虑:

  • 价格止损:价差反向突破某个阈值(比如3.5倍标准差)
  • 时间止损:持仓超过最大持有时间
  • 波动率止损:波动率突然放大,说明市场结构变了

血的教训:我曾经做铁矿石跨期套利,设了2%的价格止损。结果有一次价差瞬间拉大,直接打穿止损,亏了5%。后来我改成「波动率自适应止损」——波动率大的时候止损放宽,波动率小的时候收紧。效果好了很多。

# 波动率自适应止损
def adaptive_stop(spread, entry_price, current_vol):
    base_stop = 0.02  # 基础止损2%
    vol_factor = current_vol / 0.15  # 假设基准波动率15%
    
    stop_loss = entry_price * (1 + base_stop * vol_factor)
    return stop_loss

6.4 信号过滤机制

信号过滤,就是给信号「洗个澡」,把噪音去掉。我常用的过滤方法有:

  1. 时间过滤:避开开盘和收盘的混乱期
  2. 成交量过滤:成交量太低时,价差容易被操纵
  3. 趋势过滤:大趋势明显时,套利信号可能失效
  4. 相关性过滤:两个品种的相关性突然下降,说明套利关系破裂

核心原则:宁可错过,不可做错。信号过滤的本质,是用「交易频率」换「胜率」。

# 信号过滤示例
def signal_filter(spread_signal, volume, correlation):
    # 成交量过滤
    if volume < 1000:
        return False
    # 相关性过滤
    if correlation < 0.6:
        return False
    # 时间过滤(避开开盘前30分钟)
    if current_time < "09:30":
        return False
    return True

我个人习惯把信号过滤做成一个「漏斗」——每一层过滤掉一部分信号,最后剩下的才是真正值得交易的。你想想看,100个信号里能过滤出10个,这10个的胜率大概率比那90个高。

信号生成与过滤流程图 原始价差信号 阈值判断(固定/动态) 开仓/平仓信号 信号过滤(4层漏斗) 最终交易信号 时间过滤 成交量过滤 趋势过滤 相关性过滤

最后说一句:信号生成没有银弹。固定阈值还是动态阈值?开仓信号要不要加确认?止损设多少?这些问题的答案,都取决于你的品种、周期和风险偏好。我的建议是:先用历史数据回测,找到最优参数组合,然后留20%的数据做样本外验证。别一上来就实盘,那是送钱。

我的习惯:每次调整信号参数,我都会记录下调整的原因和预期效果。三个月后回头看,哪些判断对了,哪些错了。这个习惯帮我避开了很多坑。

公众号:蓝海数据掘金营,微信deep3321