AlphaFeed Blog

如何用 Python 给双均线策略加趋势过滤减少假信号?(长期均线过滤回测)

策略与回测 · 代码验证于 2026-10-01

如何用 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%}")

关键坑与注意事项

常见问题(FAQ)

Q:趋势过滤一定能提高收益吗? A:不一定提高总收益,但通常减少交易次数与最大回撤、提升信号质量。在震荡市效果明显,在单边强趋势里可能和基础版接近。要用回测看。

Q:趋势均线用 120 还是 200? A:120(约半年)、200(约一年)都常用。越长越稳、越滞后。可多测几组看稳健性。

Q:为什么只过滤做多、不过滤平仓? A:平仓(死叉)要尽快离场控制风险,不宜被趋势条件拖延;过滤主要用于进场,避免逆势做多。

Q:需要付费吗? A:单只历史日线有免费额度;多标的批量回测(klines.batch + universes)需 Starter 及以上。详见定价页。

小结

给双均线策略加「长期均线趋势过滤」,只在大趋势向上时接受金叉做多,是减少震荡市假信号的经典改进。用 AlphaFeed 取前复权日线,把基础版与带过滤版并列回测,就能看清过滤对交易次数、回撤的实际影响。关键是避免未来函数、前复权、扣手续费、别过拟合参数。

相关链接:


免责声明:本文仅为技术与数据接口使用示例,代码与策略仅供学习研究,不构成投资建议。市场有风险,历史数据不代表未来表现。