Summary: 完整的基于Trading Rush 87%胜率策略的三级MACD趋势跟踪MT4 EA。包含MACD-EMA信号过滤、三级加仓、虚拟止损止盈系统和灵活的风险管理。




三级MACD趋势跟踪EA - 完整MQL4源码(基于Trading Rush策略)



本文提供一个基于Trading Rush视频中广为流传的"87%胜率策略"的完整自动交易EA。该策略在2025年初引发广泛关注,其核心是纪律化的"三试"方法,每个交易信号最多允许三次分批入场,以改善平均入场价格并提高整体胜率。

策略逻辑



该EA将MACD金叉死叉信号与长期EMA趋势过滤相结合。当有效信号出现时,EA可以在预设的价格水平最多入场三次,随着价格有利方向移动而分批加仓。这种"金字塔式"或"分批"入场方法旨在改善平均入场价格,同时保持有利的风险回报比。

核心组件



  • <strong>信号生成</strong>:MACD(12,26,9)金叉死叉,配合价格相对于200周期EMA的位置确认

  • <strong>三级加仓系统</strong>:每个信号最多三次入场,间隔为用户定义的距离

  • <strong>虚拟止损/止盈</strong>:内部追踪精确的出场水平,避免经纪商止损猎杀

  • <strong>两步下单法</strong>:避免常见的MT4 OrderSend错误130


  • 完整MQL4代码



    ``mql4
    //+------------------------------------------------------------------+
    //| ThreeTier_MACD_Trend_EA.mq4 |
    //| 自主编译 |
    //| Based on Trading Rush Strategy |
    //+------------------------------------------------------------------+
    #property copyright "AI助手"
    #property link ""
    #property version "1.00"
    #property strict

    //--- 输入参数 - 信号设置
    input int FastMACD = 12; // MACD快线周期
    input int SlowMACD = 26; // MACD慢线周期
    input int SignalMACD = 9; // MACD信号线周期
    input int TrendEMAPeriod = 200; // 趋势过滤EMA周期
    input int SignalValidityBars = 5; // 信号有效K线数

    //--- 输入参数 - 三级加仓
    input bool UseThreeTier = true; // 启用三级加仓
    input double Tier1Distance = 0; // 第一级距离点数(0=市价)
    input double Tier2Distance = 25; // 第二级距离点数
    input double Tier3Distance = 50; // 第三级距离点数

    //--- 输入参数 - 风险管理
    input double RiskPercent = 1.0; // 每完整系列风险%(0=使用固定手数)
    input double FixedLotSize = 0.1; // 固定手数(RiskPercent=0时)
    input double RiskRewardRatio = 1.5; // 盈亏比(止盈/止损)
    input int BaseStopLoss = 60; // 基础止损点数
    input int MaxSpread = 35; // 最大允许点差
    input int Slippage = 10; // 最大滑点

    //--- 输入参数 - 虚拟止损/止盈
    input bool UseVirtualSLTP = true; // 启用虚拟止损止盈管理
    input int VirtualBuffer = 15; // 经纪商止损止盈缓冲点数

    //--- 输入参数 - 交易管理
    input int MagicNumber = 202608; // EA魔术号
    input bool CloseOnOpposite = true; // 反向信号时平仓反向单
    input bool UseTimeFilter = false; // 启用时间过滤
    input int StartHour = 8; // 开始交易小时
    input int EndHour = 20; // 结束交易小时

    //--- 全局变量
    double emaTrend = 0;
    double macdMain = 0, macdSignal = 0;
    double macdMainPrev = 0, macdSignalPrev = 0;
    datetime signalCandleTime = 0;
    int signalDirection = 0; // 1=做多, -1=做空
    int currentTier = 0; // 0=无持仓, 1=第一级, 2=第二级, 3=第三级
    int pointMultiplier = 10;
    double virtualStopLoss = 0;
    double virtualTakeProfit = 0;
    double weightedAvgPrice = 0;
    double totalLots = 0;
    datetime lastBarTime = 0;

    //+------------------------------------------------------------------+
    //| EA初始化函数 |
    //+------------------------------------------------------------------+
    int OnInit()
    {
    // 检测平台报价格式
    if(Digits == 3 || Digits == 5)
    pointMultiplier = 10;
    else if(Digits == 2 || Digits == 4)
    pointMultiplier = 1;

    if(FastMACD >= SlowMACD)
    {
    Print("错误: MACD快线周期必须小于慢线周期");
    return(INIT_PARAMETERS_INCORRECT);
    }

    Print("三级MACD EA初始化成功");
    Print("每系列风险: ", RiskPercent, "% | 盈亏比: ", RiskRewardRatio);

    return(INIT_SUCCEEDED);
    }

    //+------------------------------------------------------------------+
    //| EA反初始化函数 |
    //+------------------------------------------------------------------+
    void OnDeinit(const int reason)
    {
    Print("EA已移除. 原因: ", reason);
    }

    //+------------------------------------------------------------------+
    //| 检测新K线 |
    //+------------------------------------------------------------------+
    bool IsNewBar()
    {
    datetime currentBarTime = iTime(Symbol(), 0, 0);
    if(currentBarTime != lastBarTime)
    {
    lastBarTime = currentBarTime;
    return true;
    }
    return false;
    }

    //+------------------------------------------------------------------+
    //| 检查点差是否在限制范围内 |
    //+------------------------------------------------------------------+
    bool IsSpreadOK()
    {
    if(MaxSpread <= 0) return true;
    int currentSpread = (int)((Ask - Bid) / Point / pointMultiplier);
    return (currentSpread <= MaxSpread);
    }

    //+------------------------------------------------------------------+
    //| 检查交易时间 |
    //+------------------------------------------------------------------+
    bool IsTradingTime()
    {
    if(!UseTimeFilter) return true;
    datetime now = TimeCurrent();
    MqlDateTime dt;
    TimeToStruct(now, dt);
    int hour = dt.hour;
    return (hour >= StartHour && hour < EndHour);
    }

    //+------------------------------------------------------------------+
    //| 计算指标值 |
    //+------------------------------------------------------------------+
    void CalculateIndicators()
    {
    emaTrend = iMA(Symbol(), 0, TrendEMAPeriod, 0, MODE_EMA, PRICE_CLOSE, 0);

    macdMain = iMACD(Symbol(), 0, FastMACD, SlowMACD, SignalMACD, PRICE_CLOSE, MODE_MAIN, 0);
    macdSignal = iMACD(Symbol(), 0, FastMACD, SlowMACD, SignalMACD, PRICE_CLOSE, MODE_SIGNAL, 0);
    macdMainPrev = iMACD(Symbol(), 0, FastMACD, SlowMACD, SignalMACD, PRICE_CLOSE, MODE_MAIN, 1);
    macdSignalPrev = iMACD(Symbol(), 0, FastMACD, SlowMACD, SignalMACD, PRICE_CLOSE, MODE_SIGNAL, 1);
    }

    //+------------------------------------------------------------------+
    //| 检查MACD交叉信号 |
    //+------------------------------------------------------------------+
    void CheckForNewSignal()
    {
    bool buySignal = false;
    bool sellSignal = false;

    // 做多信号:MACD金叉 AND 价格在EMA200上方
    if(Close[0] > emaTrend && macdMainPrev <= macdSignalPrev && macdMain > macdSignal)
    {
    buySignal = true;
    }

    // 做空信号:MACD死叉 AND 价格在EMA200下方
    if(Close[0] < emaTrend && macdMainPrev >= macdSignalPrev && macdMain < macdSignal)
    {
    sellSignal = true;
    }

    if(buySignal || sellSignal)
    {
    datetime currentCandle = iTime(Symbol(), 0, 0);
    if(currentCandle != signalCandleTime)
    {
    signalCandleTime = currentCandle;
    signalDirection = buySignal ? 1 : -1;
    Print("检测到新信号: ", signalDirection == 1 ? "做多" : "做空");
    }
    }
    }

    //+------------------------------------------------------------------+
    //| 基于风险百分比计算手数 |
    //+------------------------------------------------------------------+
    double CalculatePositionSize()
    {
    if(RiskPercent <= 0)
    return FixedLotSize;

    double accountBalance = AccountBalance();
    double riskAmount = accountBalance RiskPercent / 100.0;
    double stopDistance = BaseStopLoss
    pointMultiplier;
    double tickValue = MarketInfo(Symbol(), MODE_TICKVALUE);
    double lotStep = MarketInfo(Symbol(), MODE_LOTSTEP);

    if(tickValue <= 0 || lotStep <= 0)
    return FixedLotSize;

    double calculatedLot = riskAmount / (stopDistance tickValue);
    calculatedLot = MathFloor(calculatedLot / lotStep)
    lotStep;

    double minLot = MarketInfo(Symbol(), MODE_MINLOT);
    double maxLot = MarketInfo(Symbol(), MODE_MAXLOT);

    if(calculatedLot < minLot) calculatedLot = minLot;
    if(calculatedLot > maxLot) calculatedLot = maxLot;

    return NormalizeDouble(calculatedLot, 2);
    }

    //+------------------------------------------------------------------+
    //| 计算虚拟止损止盈 |
    //+------------------------------------------------------------------+
    void CalculateVirtualLevels(int direction, double entryPrice)
    {
    double stopPips = BaseStopLoss Point pointMultiplier;
    double tpPips = stopPips RiskRewardRatio;

    if(direction == 1) // 做多
    {
    virtualStopLoss = entryPrice - stopPips;
    virtualTakeProfit = entryPrice + tpPips;
    }
    else // 做空
    {
    virtualStopLoss = entryPrice + stopPips;
    virtualTakeProfit = entryPrice - tpPips;
    }
    }

    //+------------------------------------------------------------------+
    //| 两步法开仓(避免错误130) |
    //+------------------------------------------------------------------+
    bool OpenOrderTwoStep(int cmd, double lot, double price)
    {
    // 第一步:无止损止盈开仓
    int ticket = OrderSend(Symbol(), cmd, lot, price, Slippage, 0, 0, "3Tier MACD", MagicNumber, 0, clrNONE);

    if(ticket < 0)
    {
    Print("第一步开仓失败. 错误码: ", GetLastError());
    return false;
    }

    // 第二步:修改订单添加止损止盈
    if(OrderSelect(ticket, SELECT_BY_TICKET))
    {
    double sl = 0, tp = 0;
    double buffer = VirtualBuffer
    Point pointMultiplier;

    if(cmd == OP_BUY)
    {
    sl = virtualStopLoss - buffer;
    tp = virtualTakeProfit + buffer;
    }
    else
    {
    sl = virtualStopLoss + buffer;
    tp = virtualTakeProfit - buffer;
    }

    if(!OrderModify(ticket, OrderOpenPrice(), sl, tp, 0, clrNONE))
    {
    Print("修改订单失败 订单号", ticket, ". 错误码: ", GetLastError());
    }
    }

    Print("开仓成功. 订单号: ", ticket, " | 手数: ", lot, " | 方向: ", cmd == OP_BUY ? "做多" : "做空");
    return true;
    }

    //+------------------------------------------------------------------+
    //| 开仓指定级别的入场 |
    //+------------------------------------------------------------------+
    void OpenTierEntry(int tier)
    {
    if(signalDirection == 0) return;

    double lotSize = CalculatePositionSize();
    double entryPrice = 0;

    if(tier == 1)
    {
    entryPrice = (signalDirection == 1) ? Ask : Bid;
    }
    else if(tier == 2)
    {
    double distance = Tier2Distance
    Point pointMultiplier;
    entryPrice = (signalDirection == 1) ? weightedAvgPrice + distance : weightedAvgPrice - distance;
    }
    else if(tier == 3)
    {
    double distance = Tier3Distance
    Point pointMultiplier;
    entryPrice = (signalDirection == 1) ? weightedAvgPrice + distance : weightedAvgPrice - distance;
    }

    // 第二、三级使用半仓
    if(tier > 1 && UseThreeTier)
    {
    lotSize = lotSize / 2;
    }

    if(lotSize <= 0) return;

    bool success = OpenOrderTwoStep(signalDirection == 1 ? OP_BUY : OP_SELL, lotSize, entryPrice);

    if(success)
    {
    currentTier = tier;
    UpdateWeightedAverage();
    }
    }

    //+------------------------------------------------------------------+
    //| 更新加权平均价格和总手数 |
    //+------------------------------------------------------------------+
    void UpdateWeightedAverage()
    {
    double totalPrice = 0;
    totalLots = 0;

    for(int i = 0; i < OrdersTotal(); i++)
    {
    if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
    {
    if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
    {
    totalPrice += OrderOpenPrice()
    OrderLots();
    totalLots += OrderLots();
    }
    }
    }

    if(totalLots > 0)
    weightedAvgPrice = totalPrice / totalLots;

    // 基于加权平均价格更新虚拟水平
    if(weightedAvgPrice > 0)
    CalculateVirtualLevels(signalDirection, weightedAvgPrice);
    }

    //+------------------------------------------------------------------+
    //| 检查虚拟止损止盈 |
    //+------------------------------------------------------------------+
    void CheckVirtualLevels()
    {
    if(!UseVirtualSLTP) return;
    if(virtualStopLoss == 0 || virtualTakeProfit == 0) return;

    double currentPrice = (signalDirection == 1) ? Bid : Ask;
    bool shouldClose = false;
    string reason = "";

    if(signalDirection == 1) // 做多持仓
    {
    if(currentPrice <= virtualStopLoss)
    {
    shouldClose = true;
    reason = "虚拟止损";
    }
    else if(currentPrice >= virtualTakeProfit)
    {
    shouldClose = true;
    reason = "虚拟止盈";
    }
    }
    else // 做空持仓
    {
    if(currentPrice >= virtualStopLoss)
    {
    shouldClose = true;
    reason = "虚拟止损";
    }
    else if(currentPrice <= virtualTakeProfit)
    {
    shouldClose = true;
    reason = "虚拟止盈";
    }
    }

    if(shouldClose)
    {
    CloseAllPositions();
    Print("仓位已由", reason, "平仓,价格: ", currentPrice);
    ResetSignalState();
    }
    }

    //+------------------------------------------------------------------+
    //| 检查加仓条件 |
    //+------------------------------------------------------------------+
    void CheckTierEntries()
    {
    if(!UseThreeTier) return;
    if(signalDirection == 0) return;
    if(currentTier >= 3) return;

    double currentPrice = (signalDirection == 1) ? Bid : Ask;
    double priceDiff = MathAbs(currentPrice - weightedAvgPrice) / Point / pointMultiplier;

    if(currentTier == 1 && priceDiff >= Tier2Distance)
    {
    OpenTierEntry(2);
    }
    else if(currentTier == 2 && priceDiff >= Tier3Distance)
    {
    OpenTierEntry(3);
    }
    }

    //+------------------------------------------------------------------+
    //| 平仓所有持仓 |
    //+------------------------------------------------------------------+
    void CloseAllPositions()
    {
    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
    if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
    {
    if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
    {
    double closePrice = (OrderType() == OP_BUY) ? Bid : Ask;
    OrderClose(OrderTicket(), OrderLots(), closePrice, Slippage, clrNONE);
    }
    }
    }
    }

    //+------------------------------------------------------------------+
    //| 平仓反向持仓 |
    //+------------------------------------------------------------------+
    void CloseOppositePositions()
    {
    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
    if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
    {
    if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
    {
    bool isOpposite = (signalDirection == 1 && OrderType() == OP_SELL) ||
    (signalDirection == -1 && OrderType() == OP_BUY);
    if(isOpposite)
    {
    double closePrice = (OrderType() == OP_BUY) ? Bid : Ask;
    OrderClose(OrderTicket(), OrderLots(), closePrice, Slippage, clrNONE);
    }
    }
    }
    }
    }

    //+------------------------------------------------------------------+
    //| 统计持仓数量 |
    //+------------------------------------------------------------------+
    int CountPositions()
    {
    int count = 0;
    for(int i = 0; i < OrdersTotal(); i++)
    {
    if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
    {
    if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
    count++;
    }
    }
    return count;
    }

    //+------------------------------------------------------------------+
    //| 重置信号状态 |
    //+------------------------------------------------------------------+
    void ResetSignalState()
    {
    signalDirection = 0;
    currentTier = 0;
    virtualStopLoss = 0;
    virtualTakeProfit = 0;
    weightedAvgPrice = 0;
    totalLots = 0;
    }

    //+------------------------------------------------------------------+
    //| 检查信号是否仍然有效 |
    //+------------------------------------------------------------------+
    bool IsSignalValid()
    {
    if(signalCandleTime == 0) return false;

    datetime currentCandle = iTime(Symbol(), 0, 0);
    int candlesPassed = (int)((currentCandle - signalCandleTime) / PeriodSeconds());

    return (candlesPassed <= SignalValidityBars);
    }

    //+------------------------------------------------------------------+
    //| EA报价处理函数 |
    //+------------------------------------------------------------------+
    void OnTick()
    {
    // 基础检查
    if(!IsSpreadOK()) return;
    if(!IsTradingTime()) return;

    // 每个tick计算指标
    CalculateIndicators();

    // 检查现有持仓的虚拟水平
    if(CountPositions() > 0)
    {
    CheckVirtualLevels();
    if(UseThreeTier && signalDirection != 0)
    CheckTierEntries();
    return;
    }

    // 仅在新K线时检测新信号
    if(!IsNewBar()) return;

    // 检测新信号
    CheckForNewSignal();

    // 信号有效时执行初始入场
    if(signalDirection != 0 && IsSignalValid())
    {
    if(CloseOnOpposite)
    CloseOppositePositions();

    if(CountPositions() == 0)
    {
    double entryPrice = (signalDirection == 1) ? Ask : Bid;
    CalculateVirtualLevels(signalDirection, entryPrice);
    OpenTierEntry(1);
    }
    }
    else if(!IsSignalValid() && signalDirection != 0)
    {
    Print("信号已失效,经过了", SignalValidityBars, "根K线");
    ResetSignalState();
    }
    }
    //+------------------------------------------------------------------+
    ``

    参数详解



    | 参数 | 说明 | 推荐值 |
    |------|------|--------|
    | MACD快线周期 | MACD快线EMA周期 | 12 |
    | MACD慢线周期 | MACD慢线EMA周期 | 26 |
    | MACD信号线周期 | MACD信号线周期 | 9 |
    | 趋势EMA周期 | 趋势过滤EMA周期 | 200 |
    | 信号有效K线数 | 信号保持有效的K线数量 | 5-10 |
    | 启用三级加仓 | 启用/禁用三级分批加仓 | true |
    | 第二级距离 | 从平均价到第二级入场的点数 | 20-30 |
    | 第三级距离 | 从平均价到第三级入场的点数 | 40-60 |
    | 风险百分比 | 每完整系列风险(账户余额%) | 1.0-2.0 |
    | 固定手数 | 固定交易手数(RiskPercent=0时) | 0.01-0.1 |
    | 盈亏比 | 目标盈利相对于风险的比例 | 1.5-2.0 |
    | 基础止损 | 基础止损点数 | 50-80 |
    | 最大点差 | 允许的最大点差 | 30-40 |
    | 虚拟止损止盈 | 启用虚拟止损止盈管理 | true |
    | 虚拟缓冲 | 经纪商止损止盈缓冲点数 | 10-20 |
    | 反向平仓 | 新信号时平仓反向持仓 | true |

    安装步骤



  • 复制代码到MT4的MetaEditor(按F4)

  • 点击编译(F7)- 确保无错误

  • 将EA附加到图表(推荐EURUSD,M15时间周期)

  • 在输入参数选项卡中调整参数

  • 启用自动交易(Alt+T)


  • 三级加仓系统工作原理



    "三试"策略旨在改善平均入场价格:

  • <strong>第一级入场</strong>:MACD交叉信号出现时立即开仓

  • <strong>第二级入场</strong>:价格从平均入场价有利移动Tier2Distance点数时开仓

  • <strong>第三级入场</strong>:价格继续有利移动Tier3Distance点数时开仓


  • 这种金字塔式加仓方法允许EA在盈利持仓上加仓,同时保持基于成交量加权平均入场价的单一止损水平。

    虚拟止损止盈系统



    本EA的关键特性是两步下单法结合虚拟止损止盈管理:

  • 订单首先以"裸单"形式开仓(无止损止盈),避免OrderSend错误130

  • 然后修改订单添加带缓冲的经纪商级止损作为安全网

  • EA内部追踪精确的虚拟止损止盈水平,触发时主动平仓


  • 这种方法提供更精确的出场控制,并有助于避免经纪商止损猎杀。

    编译与修改技巧



    主要修改方向:
  • 将SignalValidityBars改为3可获得更激进的信号失效时间

  • 修改RiskRewardRatio为2.0可获得更高的盈利目标

  • 禁用UseThreeTier可只进行单次入场不加仓

  • 如果遇到订单修改错误,增加VirtualBuffer


  • 最佳时间周期和品种:
  • 推荐:EURUSD、GBPUSD,M15时间周期

  • 可调整参数后适用于M30或H1


  • 参考来源



    本文EA源码为自主编译,基于Forex Factory论坛2025年5月帖子"EA based on Trading Rush Video"中记载的策略。三级加仓方法和虚拟止损止盈系统改编自该社区资源中讨论的原则。

    如需更专业的优化版EA策略(含多周期分析、AI市场状态检测、完整回测报告和专业技术支持),请查看我们的付费EA合集。订阅后可每周获取更新和独家交易工具。