构建K线趋势约束模型(第十部分):战略均线金叉与死叉(智能交易系统EA)(基础篇)
「用战略均线交叉给EA定方向」
很多半自动EA亏在逆势硬做,把金叉死叉当成唯一信号太脆。这里把均线交叉从‘触发’降级为‘约束’:只有大周期战略均线给出方向,战术单才允许进场。 原文示例里这套思路在 MetaTrader 5 环境跑,发布于 2025-09-10,社区展示浏览量 1751、收藏 1,说明小众但能落地。外汇与贵金属杠杆高,均线约束只降频不保本,实盘前请在 MT5 策略测试器用历史数据验证滑点和点差。 核心做法:EA 初始化时读两条周期相差较大的 SMA,比如 50 与 200,比较前值与本值关系判定金叉/死叉;若未同向则不发单。下面这段是判定逻辑的骨架。
class="type">bool IsGoldenCross(class="type">int fastPeriod, class="type">int slowPeriod) { class="type">class="kw">double fastNow = iMA(NULL,class="num">0,fastPeriod,class="num">0,MODE_SMA,PRICE_CLOSE,class="num">0); class="type">class="kw">double fastPrev= iMA(NULL,class="num">0,fastPeriod,class="num">0,MODE_SMA,PRICE_CLOSE,class="num">1); class="type">class="kw">double slowNow = iMA(NULL,class="num">0,slowPeriod,class="num">0,MODE_SMA,PRICE_CLOSE,class="num">0); class="type">class="kw">double slowPrev= iMA(NULL,class="num">0,slowPeriod,class="num">0,MODE_SMA,PRICE_CLOSE,class="num">1); class="kw">return(fastPrev <= slowPrev && fastNow > slowNow); }
为什么要把均线交叉交给EA跑
均线金叉(短周期均线上穿长周期)与死叉(下穿)是辨识动能反转最老牌的信号之一。手动盯盘时,这两个交叉在日内和波段行情里确实有用,但人会因为犹豫、漏看、执行延迟而吃不到完整波段,尤其外汇与贵金属杠杆高、波动快,漏一次交叉可能就错过整段行情。 把金叉死叉写进MT5的EA后,信号触发即下单,不受情绪与在线时长限制。它不依赖每日市场情绪滤镜,而是独立判定反转点,因此能比很多趋势跟随系统更早咬住转折点,提升响应速度。 本篇后续会拆到MQL5里的具体实现与初始回测。先记住一点:交叉策略只是趋势约束EA的一个模块,单独跑也可能在震荡市连续止损,外汇/贵金属属高风险品种,任何自动化都只是把执行做一致,不消除亏损概率。
◍ 均线交叉发出的趋势转折信号
短期均线向上穿过长期均线,就是常被提及的金叉。以 50 日均线上穿 200 日均线为例,这种交叉往往被解读为长期上升段可能启动的预警,价格后续走高的概率偏大,但绝不是确定性结论。 反过来,短期均线向下击穿长期均线构成死叉,像 50 日下穿 200 日,通常意味着市场偏弱状态可能延续。外汇与贵金属市场杠杆高、波动剧烈,看到死叉就直接做空极易被假突破扫损,只能把它当作环境转弱的参考。 这两个信号本身不神秘,核心价值在过滤噪音:单独用容易吃假信号,实战里要叠成交量或 RSI 这类辅助确认。MT5 里拖两根 MA 到图表,把周期设成 50 和 200 就能直观验证交叉频率。
「金叉死叉在趋势跟踪框架里的真实位置」
把均线交叉塞进趋势跟踪逻辑里,核心用途就三件:抓新趋势起点、给已有判断做确认、顺手管仓位。金叉出现意味着多头倾向启动,死叉则提示空头倾向占优,但单独拿它开仓在外汇和贵金属这种高波动市场里风险很高,必须配合别的信号。 传统参数多取 50 与 200 周期均线,这套组合天然偏长线,能过滤掉不少噪音,契合「跟大波不跟小抖」的思路。可一旦切到节奏更快的盘面,把周期缩到 20 与 60 之类也能跑,只是假信号概率会往上走。 真正要警惕的是滞后与震荡两个坑。等交叉真走出来,一段趋势往往已经跑完相当幅度;而在区间来回扫的行情里,金叉死叉能连续触发错误启动。所以它们是工具不是圣杯,用作 wider 策略里的子系统更稳妥。
把金叉死叉拆成独立模块喂给趋势EA
长期趋势EA如果约束太死,往往会错过日内结构反转带来的边际机会。比如某日日线情绪偏空,但15分钟图上出现均线金叉,这种低周期信号可能预示短期反转、价格倾向转多;受 rigid 规则限制的老版本EA通常会继续顺日线空势,而错过这波回补。 把金叉/死叉逻辑从主趋势过滤里解耦,作为独立子模块挂进趋势约束EA,是更务实的写法。EA在主趋势方向不变的前提下,允许子模块捕捉与新趋势契合的反转入场,等于用双层结构换来了跨周期灵活性。 实测上,这种拆法主要带来两点可验证差异:一是入场滞后普遍缩短,因为低周期金叉被尽早识别;二是策略间不互相覆盖——趋势跟踪机制仍掌舵,反转模块只补刀。外汇与贵金属波动剧烈、杠杆高风险,任何协同优势都只是概率上的改善,不是免死金牌。 在MT5里你可以先只跑主趋势模块,再叠加金叉子模块对比净值曲线,参数上建议把子模块时间帧固定为母模块的1/4到1/8,避免噪声过载。
◍ 把金叉死叉先写成独立EA再合并
做多策略EA时,先拆成单策略独立工程是更稳的开发路径。金叉死叉这套逻辑建议先单独写成一个EA,在MT5里跑通测试和优化,再并进主代码库,避免多策略互相干扰导致排查困难。 按F4进MetaEditor,新手最好手敲代码而不是贴代码,手感比看一遍深。头里先用#property写版权、描述、版本,再用#include<Trade\Trade.mqh>把CTrade实例化成trade对象,买空买多平仓全走库函数,自己不写下单底层,可靠性更高。 输入参数留了LotSize、Slippage、FastEMAPeriod、SlowEMAPeriod等。默认快线50、慢线200,对应常见的50/200 EMA交叉周期;止损50点、止盈100点,定时器间隔10000毫秒轮询一次。 OnInit里有个硬校验:当前周期K线数小于SlowEMAPeriod就INIT_FAILED并打日志,没足够慢线数据绝不跑。OnTimer里用iMA拿双线句柄、CopyBuffer取数,金叉开多死叉开空,反向信号平掉原仓,错误用Print留痕。外汇贵金属杠杆高,这套信号在震荡市可能频繁假突破,上手先开模拟盘验证。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Strategic Golden & Death Cross EA.mq5 | class=class="str">"cmt">//| Copyright class="num">2024, Clemence Benjamin | class=class="str">"cmt">//| [MQL5官方文档] | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#class="kw">property copyright "Clemence Benjamin" class="macro">#class="kw">property description "GOLDEN AND DEATH CROSS" class="macro">#class="kw">property version "class="num">1.0" class="macro">#include<Trade\Trade.mqh>; CTrade trade; input class="type">class="kw">double LotSize = class="num">1.0; class=class="str">"cmt">// Trade volume(lots) input class="type">int Slippage = class="num">20; class=class="str">"cmt">// Slippage in points input class="type">int TimerInterval = class="num">10000; class=class="str">"cmt">// Timer interval in seconds input class="type">class="kw">double TakeProfitPips = class="num">100; class=class="str">"cmt">// Take Profit in pips input class="type">class="kw">double StopLossPips = class="num">50; class=class="str">"cmt">// Stop Loss in pips input class="type">int FastEMAPeriod = class="num">50; class=class="str">"cmt">// Fast EMA period(class="kw">default class="num">50) input class="type">int SlowEMAPeriod = class="num">200; class=class="str">"cmt">// Slow EMA period(class="kw">default class="num">200) class="type">int OnInit() { class=class="str">"cmt">//--- create timer EventSetTimer(TimerInterval); class=class="str">"cmt">//--- Check if there are enough bars for EMA calculation if(Bars(_Symbol,PERIOD_CURRENT)<SlowEMAPeriod) { Print("Not enough bars for EMA calculation"); class="kw">return(INIT_FAILED); } class="kw">return(INIT_SUCCEEDED); } class="type">void OnDeinit(const class="type">int reason) { class=class="str">"cmt">//--- class="kw">delete timer EventKillTimer(); } class="type">int fastEMAHandle = iMA(_Symbol, PERIOD_CURRENT, FastEMAPeriod, class="num">0, MODE_EMA, PRICE_CLOSE); class="type">int slowEMAHandle = iMA(_Symbol, PERIOD_CURRENT, SlowEMAPeriod, class="num">0, MODE_EMA, PRICE_CLOSE);