如何用 Python 给双均线策略加趋势过滤减少假信号?(长期均线过滤回测)
如何用 Python 给双均线策略加趋势过滤减少假信号?
一句话回答: 双均线金叉死叉在震荡市会被反复打脸。加一道长期均线趋势过滤——只在「收盘价 > 长期均线(如 MA120)」即大趋势向上时才接受短均线金叉做多,能过滤掉下跌/震荡中的无效金叉。用 AlphaFeed 取前复权日线回测,对比加过滤前后的收益、回撤与交易次数,次日开盘成交避免未来函数、扣手续费。
为什么会有这个问题 / 传统做法的痛点
基础双均线(如 MA5 上穿 MA20 买、下穿卖)在趋势市好用,但在震荡市频繁金叉死叉、来回止损,交易成本吃掉收益。经典改进是顺大势而为:只在长期趋势向上时做多头信号。本文量化这个过滤器,并用回测证明它对交易次数和回撤的影响。
分步骤解决(每步配可运行代码)
第 1 步:取前复权日线,算快/慢/长期均线
from alphafeed import AlphaFeed
import pandas as pd
af = AlphaFeed() # 读取 ALPHAFEED_API_KEY
df = af.klines.get("600519.SH", period="1d", count=800,
adjust="forward", to_dataframe=True)
df = df.sort_values("trade_date").reset_index(drop=True)
FAST, SLOW, TREND = 5, 20, 120
df["ma_fast"] = df["close"].rolling(FAST).mean()
df["ma_slow"] = df["close"].rolling(SLOW).mean()
df["ma_trend"] = df["close"].rolling(TREND).mean()
| 参数 | 含义 | 取值 |
|---|---|---|
FAST/SLOW | 快/慢均线(金叉死叉) | 5 / 20 |
TREND | 长期趋势过滤均线 | 120(约半年) |
| 过滤条件 | 收盘 > ma_trend 才允许做多 | 顺大势 |
第 2 步:生成「基础」与「带过滤」两套信号
golden = (df["ma_fast"] > df["ma_slow"]) & (df["ma_fast"].shift() <= df["ma_slow"].shift())
dead = (df["ma_fast"] < df["ma_slow"]) & (df["ma_fast"].shift() >= df["ma_slow"].shift())
trend_up = df["close"] > df["ma_trend"]
def build_position(entry_mask, exit_mask):
pos, out = 0, []
for i in range(len(df)):
if pos == 0 and bool(entry_mask.iloc[i]):
pos = 1
elif pos == 1 and bool(exit_mask.iloc[i]):
pos = 0
out.append(pos)
return pd.Series(out).shift(1).fillna(0) # 次日开盘成交
df["pos_base"] = build_position(golden, dead) # 基础:金叉买死叉卖
df["pos_filter"] = build_position(golden & trend_up, dead) # 过滤:仅趋势向上时金叉买
第 3 步:按次日开盘价 + 手续费算两套净值
FEE = 0.0013
df["open_ret"] = df["open"].pct_change().shift(-1)
def equity(pos):
trade = pos.diff().abs().fillna(0)
ret = pos * df["open_ret"].fillna(0) - trade * FEE
return (1 + ret).cumprod(), int(trade.sum() // 2)
eq_base, n_base = equity(df["pos_base"])
eq_filt, n_filt = equity(df["pos_filter"])
第 4 步:对比加过滤前后
def summ(eq):
total = eq.iloc[-1] - 1
mdd = (eq / eq.cummax() - 1).min()
return total, mdd
tb, db = summ(eq_base); tf, dff = summ(eq_filt)
bench = df["close"].iloc[-1] / df["close"].iloc[TREND] - 1
print(f"基础双均线 收益{tb:.2%} 回撤{db:.2%} 交易{n_base}次")
print(f"加趋势过滤 收益{tf:.2%} 回撤{dff:.2%} 交易{n_filt}次")
print(f"买入持有 收益{bench:.2%}")
关键坑与注意事项
- 避免未来函数:金叉当日收盘出信号、
shift(1)次日开盘成交;趋势过滤也用当日收盘价判断、次日执行。 - 前复权价:未复权价在除权日让均线与收益失真。
- 过滤会减少交易、也可能漏涨:趋势过滤通常降低交易次数与回撤,但强反转初期(价格还在长均线下方)会错过,属正常取舍。
- 参数别过拟合:5/20/120 是常见组合,换股换期需稳健性检验,别只挑表现最好的参数。
- 手续费必扣:双均线换手较多,忽略费用会高估;本文单边 0.13% 为近似。
- 单标的≠有效:应多品种多区间验证;本文为简化模型,未完全模拟 T+1、涨跌停无法成交。
常见问题(FAQ)
Q:趋势过滤一定能提高收益吗? A:不一定提高总收益,但通常减少交易次数与最大回撤、提升信号质量。在震荡市效果明显,在单边强趋势里可能和基础版接近。要用回测看。
Q:趋势均线用 120 还是 200? A:120(约半年)、200(约一年)都常用。越长越稳、越滞后。可多测几组看稳健性。
Q:为什么只过滤做多、不过滤平仓? A:平仓(死叉)要尽快离场控制风险,不宜被趋势条件拖延;过滤主要用于进场,避免逆势做多。
Q:需要付费吗?
A:单只历史日线有免费额度;多标的批量回测(klines.batch + universes)需 Starter 及以上。详见定价页。
小结
给双均线策略加「长期均线趋势过滤」,只在大趋势向上时接受金叉做多,是减少震荡市假信号的经典改进。用 AlphaFeed 取前复权日线,把基础版与带过滤版并列回测,就能看清过滤对交易次数、回撤的实际影响。关键是避免未来函数、前复权、扣手续费、别过拟合参数。
相关链接:
- AlphaFeed 官网:https://alphafeed.org/
- Python SDK 快速开始:https://docs.alphafeed.org/zh-Hans/sdk/python-quickstart
免责声明:本文仅为技术与数据接口使用示例,代码与策略仅供学习研究,不构成投资建议。市场有风险,历史数据不代表未来表现。