3. 移动平均线(MA)策略:单均线策略、双均线交叉策略、均线排列策略、参数优化与实战技巧
移动平均线,简称均线,是我个人最常用的技术指标之一。说白了,它就是过去N根K线收盘价的平均值连线。别看它简单,在趋势跟踪里,均线是绝对的基石。我刚开始做量化那会儿,觉得这玩意儿太基础,总想搞点复杂的。后来发现,很多复杂策略的底层逻辑,其实都绕不开均线。
今天咱们就把均线策略聊透。从最简单的单均线,到经典的双均线交叉,再到机构常用的均线排列,最后聊聊参数优化和实战中的坑。嗯,这里要注意,代码我会给,但更重要的是背后的逻辑。
3.1 单均线策略:最简单的趋势过滤器
单均线策略的逻辑极其简单:价格在均线之上就做多,在均线之下就做空。它本质上是一个趋势过滤器,帮你判断当前市场的大方向。
核心逻辑:
- 当收盘价 > 均线值 → 开多/平空
- 当收盘价 < 均线值 → 开空/平多
我在项目中遇到过一个问题:单均线策略在震荡市里会被反复打脸。价格在均线上下穿来穿去,手续费和滑点能把利润吃光。所以,我一般会加一个「过滤带」——价格必须超过均线一定百分比才触发信号。
实战经验:单均线适合大周期(日线以上),小周期里噪音太多。我个人习惯用20日均线做日线级别的趋势判断。
# 单均线策略回测代码片段
import pandas as pd
import numpy as np
def single_ma_strategy(df, ma_period=20, filter_pct=0.01):
"""
df: 包含'close'列的DataFrame
ma_period: 均线周期
filter_pct: 过滤带百分比
"""
df['MA'] = df['close'].rolling(window=ma_period).mean()
df['signal'] = 0
# 加入过滤带,避免频繁交易
df.loc[df['close'] > df['MA'] * (1 + filter_pct), 'signal'] = 1
df.loc[df['close'] < df['MA'] * (1 - filter_pct), 'signal'] = -1
# 信号只取变化点
df['position'] = df['signal'].shift(1)
df['position'] = df['position'].fillna(0)
return df
3.2 双均线交叉策略:经典中的经典
双均线交叉,说白了就是一根快线和一根慢线。快线上穿慢线叫「金叉」,做多;快线下穿慢线叫「死叉」,做空。这是期货市场里流传最广的策略之一。
为什么双均线比单均线好?
单均线只看价格和一条线的关系,双均线看的是两条线的关系。两条线交叉,本质上是在衡量短期趋势和长期趋势的「相对强弱」。当短期趋势强于长期趋势,说明上涨动能足。
我记得有一次做螺纹钢的回测,用(5,20)双均线组合,年化收益能做到15%左右,但最大回撤也接近20%。后来我调整成(10,30),收益降了但回撤也小了。这里没有绝对最优,只有适合不适合。
# 双均线交叉策略回测代码
def dual_ma_cross(df, fast=5, slow=20):
df['MA_fast'] = df['close'].rolling(window=fast).mean()
df['MA_slow'] = df['close'].rolling(window=slow).mean()
# 金叉=1,死叉=-1,其他=0
df['signal'] = 0
df.loc[df['MA_fast'] > df['MA_slow'], 'signal'] = 1
df.loc[df['MA_fast'] < df['MA_slow'], 'signal'] = -1
# 取信号变化点
df['position'] = df['signal'].diff()
df['position'] = df['position'].fillna(0)
return df
小技巧:不要直接用原始信号开仓。我习惯在信号出现后,等下一根K线开盘再入场。这样可以避免盘中假突破带来的损失。
3.3 均线排列策略:机构视角的趋势判断
均线排列,就是看多条均线的相对位置。当短期均线 > 中期均线 > 长期均线,这叫「多头排列」,是强趋势信号。反过来就是「空头排列」。
我个人习惯用三根均线:5日、20日、60日。当5>20>60,说明短期、中期、长期趋势一致向上,这时候做多胜率最高。你想想看,如果连60日均线都拐头向上了,那说明大资金已经进场了。
均线排列的量化定义:
- 多头排列: MA5 > MA20 > MA60
- 空头排列: MA5 < MA20 < MA60
- 交叉排列: 其他情况(震荡市)
避坑指南:我曾经在股指期货上吃过亏。均线排列策略在趋势明确时很赚钱,但在均线粘合期(所有均线纠缠在一起)会频繁开仓。后来我加了一个条件:必须所有均线都朝同一方向运行(斜率>0),才确认趋势成立。
# 均线排列策略
def ma_arrangement(df, periods=[5, 20, 60]):
for p in periods:
df[f'MA{p}'] = df['close'].rolling(window=p).mean()
# 判断排列状态
df['arrangement'] = 'other'
cond_bull = (df['MA5'] > df['MA20']) & (df['MA20'] > df['MA60'])
cond_bear = (df['MA5'] < df['MA20']) & (df['MA20'] < df['MA60'])
df.loc[cond_bull, 'arrangement'] = 'bull'
df.loc[cond_bear, 'arrangement'] = 'bear'
# 只在排列状态变化时交易
df['signal'] = 0
df.loc[df['arrangement'] == 'bull', 'signal'] = 1
df.loc[df['arrangement'] == 'bear', 'signal'] = -1
return df
3.4 参数优化与实战技巧
参数优化,说白了就是找一组「最好」的均线参数。但这里有个大坑:过拟合。你回测时参数调得越精细,实盘时死得越惨。
我的参数优化原则:
- 不要用太短的周期: 5以下的基本是噪音,我一般从10开始试
- 参数要「钝」一点: 比如(10,30)比(9,31)更稳健,因为整数参数被更多人使用,市场会自我实现
- 做参数敏感性分析: 看参数变化时,收益和回撤是否稳定。如果参数变一点,收益就大起大落,那这个策略不可靠
实战技巧总结:
- 大周期用长均线(日线用20/60),小周期用短均线(小时线用10/30)
- 趋势强时用均线,震荡市用布林带或RSI
- 永远加一个过滤条件:比如成交量放大、ATR突破等
- 回测时一定要算滑点和手续费,不然实盘会亏到怀疑人生
最后说一句,均线策略不是万能的。它最大的弱点就是滞后性——等均线给出信号时,行情可能已经走了一半。但反过来想,正因为滞后,它过滤掉了大量假突破。这就像开车,你不可能在弯道加速,但直道上你可以放心踩油门。均线就是帮你识别「直道」的工具。
最后的小建议:别把均线当圣杯。它只是一个工具,帮你识别趋势。真正的盈利,来自于你对市场的理解、资金管理,以及严格执行纪律。我见过太多人,策略回测漂亮,实盘一塌糊涂,就是因为管不住手。