3. 交易策略基础:策略设计原则、策略类型与信号生成

做量化交易这几年,我越来越觉得策略设计就像盖房子。地基没打好,后面装修得再漂亮也没用。今天咱们就聊聊策略设计的基本原则、几种主流策略类型,以及信号是怎么生成的。

3.1 策略设计原则:别让策略死在起跑线上

我个人习惯把策略设计原则归纳为三条。这三条看着简单,但我在项目中踩过的坑,十有八九都是违背了其中一条。

3.1.1 可解释性原则

说白了,你的策略得能说清楚「为什么赚钱」。我见过有人把50个技术指标扔进神经网络,回测曲线漂亮得不行。结果实盘一周就亏了20%。为什么?因为那些指标组合根本就是过拟合,没有任何逻辑支撑。

嗯,这里要注意:如果你自己都解释不清策略的逻辑,市场一定会用亏损给你解释清楚

3.1.2 稳健性原则

策略不能只在某个特定行情下有效。你想想看,如果一个策略在2015年股灾里赚了钱,但在2016年震荡市里亏成狗,那它就不是好策略。

我曾经做过一个趋势跟踪策略,在牛市里年化收益80%。我兴奋得不行,直接上了实盘。结果熊市一来,三个月回撤了40%。后来我学乖了,任何策略都要在多种市场环境下测试——趋势市、震荡市、高波动、低波动,一个都不能少。

3.1.3 简洁性原则

参数越少越好。为什么?因为参数越多,过拟合的风险就越大。我见过一个策略有20多个参数,每个参数都优化得恰到好处。但实盘呢?一塌糊涂。

我的经验法则:策略参数不要超过5个。如果超过5个,你大概率是在拟合历史数据,而不是在发现市场规律。

3.2 策略类型:三大主流流派

交易策略千千万,但核心逻辑逃不出这三类。咱们一个一个看。

3.2.1 趋势跟踪策略

趋势跟踪,说白了就是「追涨杀跌」。它的核心假设是:趋势一旦形成,就会持续一段时间

最常见的实现方式就是均线交叉。比如5日均线上穿20日均线时买入,下穿时卖出。代码很简单:

def moving_average_crossover(data, short_window=5, long_window=20):
    data['MA_short'] = data['close'].rolling(window=short_window).mean()
    data['MA_long'] = data['close'].rolling(window=long_window).mean()
    
    # 生成信号:1表示买入,-1表示卖出,0表示持有
    data['signal'] = 0
    data.loc[data['MA_short'] > data['MA_long'], 'signal'] = 1
    data.loc[data['MA_short'] < data['MA_long'], 'signal'] = -1
    
    return data

我在项目中遇到过一个问题:均线策略在强趋势行情里赚得盆满钵满,但在震荡行情里会被反复打脸。后来我加了ATR(平均真实波幅)作为过滤器——只有波动率足够大时才开仓。效果好了不少。

避坑指南:我曾经在趋势策略里用了太短的均线(比如3日和5日),结果手续费把利润全吃掉了。短周期趋势策略一定要考虑交易成本。

3.2.2 均值回归策略

均值回归和趋势跟踪正好相反。它赌的是「价格偏离均值后一定会回来」。说白了就是「低买高卖」的数学版本。

最经典的实现是布林带策略。当价格触及下轨时买入,触及上轨时卖出。

def bollinger_band_strategy(data, window=20, num_std=2):
    data['MA'] = data['close'].rolling(window=window).mean()
    data['std'] = data['close'].rolling(window=window).std()
    data['upper'] = data['MA'] + num_std * data['std']
    data['lower'] = data['MA'] - num_std * data['std']
    
    data['signal'] = 0
    data.loc[data['close'] < data['lower'], 'signal'] = 1   # 买入
    data.loc[data['close'] > data['upper'], 'signal'] = -1  # 卖出
    
    return data

嗯,这里要注意:均值回归策略在单边行情里会死得很惨。我记得有一次做股指期货的均值回归,遇到了一波连续上涨,我一路逆势做空,结果爆仓了。后来我加了趋势过滤器——只有市场处于震荡状态时才用均值回归。

3.2.3 统计套利策略

统计套利,说白了就是「找亲戚」。找两个相关性高的品种,当它们的价差偏离正常范围时,做多一个、做空另一个,赌价差会回归。

最经典的是配对交易。比如茅台和五粮液,历史上它们的价差一直在某个范围内波动。当价差扩大到2倍标准差时,就开仓。

def pairs_trading_strategy(price_a, price_b, window=60, entry_z=2):
    # 计算价差
    spread = price_a - price_b
    spread_mean = spread.rolling(window=window).mean()
    spread_std = spread.rolling(window=window).std()
    z_score = (spread - spread_mean) / spread_std
    
    # 生成信号
    signal_a = 0
    signal_b = 0
    
    if z_score > entry_z:
        signal_a = -1  # 做空A
        signal_b = 1   # 做多B
    elif z_score < -entry_z:
        signal_a = 1   # 做多A
        signal_b = -1  # 做空B
    
    return signal_a, signal_b
核心要点:统计套利的关键是找到稳定的配对关系。我一般用协整检验(Cointegration Test)来验证两个品种是否真的「有亲戚关系」。如果协整检验不通过,千万别用。

3.3 策略参数与信号生成

参数和信号,是策略的「灵魂」和「手脚」。参数决定了策略的性格,信号决定了策略的行动。

3.3.1 参数选择:别过度优化

参数优化是门学问。我见过有人用网格搜索把参数优化到小数点后两位,结果实盘一塌糊涂。为什么?因为过度优化等于在拟合噪音

我个人习惯的做法是:

  • 先定范围:比如均线周期,我一般只试5-60之间的整数
  • 再定步长:步长不要太小,5或10就够
  • 最后验证:用样本外数据验证,如果样本外表现和样本内差距很大,说明过拟合了

3.3.2 信号生成:从数据到决策

信号生成的过程,其实就是把策略逻辑翻译成「买、卖、持有」三个动作。我一般用-1、0、1来表示。

信号生成有几个关键点:

  1. 信号要明确:不能模棱两可。是买就是买,是卖就是卖
  2. 信号要可执行:比如收盘价信号,你只能在收盘时交易
  3. 信号要防未来函数:绝对不能用到未来的数据
避坑指南:我曾经犯过一个低级错误——用当天的收盘价生成信号,然后用当天的开盘价交易。这看起来没问题,但实际上收盘价是在开盘之后才产生的。这就是典型的未来函数。后来我改用前一天的收盘价生成信号,当天的开盘价执行交易。

3.4 知识体系总览

为了让你更直观地理解这一章的内容,我画了一张结构图。它把策略设计、策略类型、参数和信号的关系串起来了。

交易策略基础:知识体系 交易策略 策略设计原则 可解释性 | 稳健性 | 简洁性 策略类型 趋势跟踪(均线交叉) 均值回归(布林带) 统计套利(配对交易) 参数与信号生成 参数选择(避免过拟合) 信号生成(-1, 0, 1) 防未来函数 核心:逻辑清晰 + 参数简洁 + 信号可靠 三者缺一不可,否则实盘必亏

这张图把咱们这一章的核心内容串起来了。你想想看,策略设计原则是「道」,策略类型是「法」,参数和信号是「术」。道、法、术三者结合,才能做出靠谱的策略。

好了,这一章就聊到这儿。记住:好的策略不是靠参数堆出来的,而是靠逻辑赢出来的。下一章咱们聊聊回测系统的搭建,到时候我会分享一些我在实际项目中踩过的坑。