Summary: 黄金动态衰减网格EA是一款专为XAUUSD设计的MQL4智能交易系统。结合RSI极值过滤、ATR动态波动间距和智能回调解套模型,适合M15周期稳定运行。




黄金动态衰减网格EA专为XAUUSD设计,解决了传统固定间隔网格系统的局限性。它使用RSI极值过滤入场时机,ATR计算动态网格间距,以及智能衰减模型缩短浮亏时间。系统包含双重动量保护,防止在新闻驱动的爆发式行情中过度加仓。

推荐加载周期: M15
策略核心逻辑:
  • 入场过滤:已收盘K线的RSI(14)必须达到≥70(做空)或≤30(做多)才触发首单。

  • 网格间距:ATR(14) × 倍数计算动态网格层间距。

  • 利润衰减:目标利润随网格层数增加而递减(深度浮亏时更易安全退出)。

  • 智能解套:层数超过阈值后,通过算法使行情仅回调10%即可解套。

  • 动量保护:单根K线最多加仓1次;若K线波幅 > 2倍ATR,暂停加仓。


  • ``mql4
    //+------------------------------------------------------------------+
    //| GoldDynamicDecayGrid.mq4 |
    //+------------------------------------------------------------------+
    #property copyright ""
    #property link ""
    #property version "1.00"
    #property strict

    //+------------------------------------------------------------------+
    //| 输入参数及注释 |
    //+------------------------------------------------------------------+
    //=== 基础设置 ===
    input string comment = "GoldDecayGrid"; // 订单注释标识
    input int MagicNumber = 202419; // EA唯一魔术号
    input double InitialLotSize = 0.01; // 初始手数(黄金0.01手)
    input int MaxSpread = 35; // 最大允许点差(单位:点)

    //=== RSI入场过滤器 ===
    input int RSIPeriod = 14; // RSI计算周期
    input int RSIOverbought = 70; // RSI超买水平(做空触发)
    input int RSIOversold = 30; // RSI超卖水平(做多触发)
    input bool UseRSIFilter = true; // 启用RSI极值过滤

    //=== ATR动态网格间距 ===
    input int ATRPeriod = 14; // ATR波动率计算周期
    input double ATRGridMultiplier = 1.2; // 网格间距 = ATR × 倍数

    //=== 利润衰减设置 ===
    input double BaseTargetProfit = 30.0; // 基础利润目标(美元,0.01手)
    input double MinTargetProfit = 15.0; // 最大层数时最低利润目标
    input int DecayStartLevel = 3; // 利润衰减起始层数

    //=== 智能解套(10%回调模型)===
    input bool UseSmartRecovery = true; // 启用智能解套算法
    input int SmartRecoveryStart = 4; // 激活智能解套的最低层数
    input double RecoveryRetracePercent = 0.10; // 回调解套百分比(0.10 = 10%)

    //=== 网格交易参数 ===
    input double LotMultiplier = 1.3; // 每层手数倍数(1.3倍)
    input int MaxGridLevels = 10; // 单方向最大网格层数
    input int MaxTotalPositions = 20; // 双方向最大总持仓数

    //=== 动量保护 ===
    input bool UseMomentumFilter = true; // 启用高波动保护
    input double MaxCandleVolatility = 2.0; // 最大K线波幅倍数(ATR倍数)

    //=== 风险管理 ===
    input double DailyLossLimit = 8.0; // 每日亏损限额(账户余额百分比)
    input double MaxDrawdownPercent = 25.0; // 最大回撤百分比(触发EA停止)
    input bool UseFridayClose = true; // 周五21:00 GMT前平仓

    //=== 时间过滤器(可选)===
    input bool UseTimeFilter = false; // 启用交易时间过滤
    input string StartTime = "08:00"; // 交易开始时间(GMT)
    input string EndTime = "20:00"; // 交易结束时间(GMT)

    //+------------------------------------------------------------------+
    //| 全局变量 |
    //+------------------------------------------------------------------+
    double dailyStartBalance = 0;
    double equityPeak = 0;
    datetime lastBarTime = 0;
    bool fridayCloseExecuted = false;
    bool drawdownStop = false;
    double atrValue = 0;
    double lastGridPriceBuy = 0;
    double lastGridPriceSell = 0;
    int buyLevelCount = 0;
    int sellLevelCount = 0;

    //+------------------------------------------------------------------+
    //| EA初始化函数 |
    //+------------------------------------------------------------------+
    int OnInit()
    {
    dailyStartBalance = AccountBalance();
    equityPeak = AccountEquity();
    lastBarTime = 0;
    fridayCloseExecuted = false;
    drawdownStop = false;
    buyLevelCount = 0;
    sellLevelCount = 0;
    lastGridPriceBuy = 0;
    lastGridPriceSell = 0;
    return(INIT_SUCCEEDED);
    }

    //+------------------------------------------------------------------+
    //| EA退出函数 |
    //+------------------------------------------------------------------+
    void OnDeinit(const int reason)
    {
    Comment("");
    }

    //+------------------------------------------------------------------+
    //| 获取当前ATR值 |
    //+------------------------------------------------------------------+
    double GetATR()
    {
    double atr = iATR(Symbol(), PERIOD_M15, ATRPeriod, 1);
    if(atr <= 0) atr = 200 Point;
    return atr;
    }

    //+------------------------------------------------------------------+
    //| 获取已收盘K线的RSI值 |
    //+------------------------------------------------------------------+
    double GetRSI(int shift)
    {
    return iRSI(Symbol(), PERIOD_M15, RSIPeriod, PRICE_CLOSE, shift);
    }

    //+------------------------------------------------------------------+
    //| 检查是否在交易时间内 |
    //+------------------------------------------------------------------+
    bool IsTradingTime()
    {
    if(!UseTimeFilter) return true;
    datetime now = TimeCurrent();
    int currentHour = TimeHour(now);
    int currentMinute = TimeMinute(now);
    int startHour, startMin, endHour, endMin;
    startHour = (int)StringToInteger(StringSubstr(StartTime, 0, 2));
    startMin = (int)StringToInteger(StringSubstr(StartTime, 3, 2));
    endHour = (int)StringToInteger(StringSubstr(EndTime, 0, 2));
    endMin = (int)StringToInteger(StringSubstr(EndTime, 3, 2));
    int currentTotal = currentHour
    60 + currentMinute;
    int startTotal = startHour 60 + startMin;
    int endTotal = endHour
    60 + endMin;
    if(startTotal <= endTotal)
    return (currentTotal >= startTotal && currentTotal <= endTotal);
    else
    return (currentTotal >= startTotal || currentTotal <= endTotal);
    }

    //+------------------------------------------------------------------+
    //| 根据网格层数计算动态利润目标 |
    //+------------------------------------------------------------------+
    double GetDynamicProfitTarget(int level)
    {
    if(level <= DecayStartLevel)
    return BaseTargetProfit;
    double decayRatio = (double)(MaxGridLevels - level) / (MaxGridLevels - DecayStartLevel);
    double target = BaseTargetProfit - (BaseTargetProfit - MinTargetProfit) (1 - decayRatio);
    if(target < MinTargetProfit) target = MinTargetProfit;
    return target;
    }

    //+------------------------------------------------------------------+
    //| 基于ATR计算网格间距 |
    //+------------------------------------------------------------------+
    double GetGridSpacing()
    {
    atrValue = GetATR();
    return atrValue
    ATRGridMultiplier;
    }

    //+------------------------------------------------------------------+
    //| 计算智能解套手数(基于代数模型,10%回调解套) |
    //+------------------------------------------------------------------+
    double CalculateRecoveryLot(int level, double currentPrice, double avgPrice, double totalLots)
    {
    if(!UseSmartRecovery || level < SmartRecoveryStart)
    return InitialLotSize MathPow(LotMultiplier, level - 1);
    double retraceTarget = RecoveryRetracePercent;
    double priceDistance = MathAbs(currentPrice - avgPrice);
    double requiredDistance = priceDistance
    retraceTarget / (1 - retraceTarget);
    double lotNeeded = (totalLots priceDistance) / requiredDistance;
    lotNeeded = lotNeeded - totalLots;
    if(lotNeeded < InitialLotSize) lotNeeded = InitialLotSize;
    if(lotNeeded > InitialLotSize
    MathPow(LotMultiplier, MaxGridLevels))
    lotNeeded = InitialLotSize MathPow(LotMultiplier, MaxGridLevels);
    return NormalizeDouble(lotNeeded, 2);
    }

    //+------------------------------------------------------------------+
    //| 检查动量保护(防止单边暴涨暴跌时过度加仓) |
    //+------------------------------------------------------------------+
    bool IsMomentumSafe()
    {
    if(!UseMomentumFilter) return true;
    double currentRange = iHigh(Symbol(), PERIOD_M15, 0) - iLow(Symbol(), PERIOD_M15, 0);
    if(currentRange > GetATR()
    MaxCandleVolatility)
    return false;
    return true;
    }

    //+------------------------------------------------------------------+
    //| 平仓所有订单 |
    //+------------------------------------------------------------------+
    void CloseAllOrders()
    {
    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
    if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
    {
    if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
    {
    if(OrderType() == OP_BUY)
    OrderClose(OrderTicket(), OrderLots(), Bid, 30, clrNONE);
    else if(OrderType() == OP_SELL)
    OrderClose(OrderTicket(), OrderLots(), Ask, 30, clrNONE);
    }
    }
    }
    buyLevelCount = 0;
    sellLevelCount = 0;
    lastGridPriceBuy = 0;
    lastGridPriceSell = 0;
    }

    //+------------------------------------------------------------------+
    //| 统计各方向持仓数量 |
    //+------------------------------------------------------------------+
    void CountPositions()
    {
    buyLevelCount = 0;
    sellLevelCount = 0;
    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
    if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
    {
    if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
    {
    if(OrderType() == OP_BUY)
    buyLevelCount++;
    else if(OrderType() == OP_SELL)
    sellLevelCount++;
    }
    }
    }
    }

    //+------------------------------------------------------------------+
    //| 计算总浮动盈亏 |
    //+------------------------------------------------------------------+
    double CalculateFloatingProfit()
    {
    double profit = 0;
    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
    if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
    {
    if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
    profit += OrderProfit() + OrderSwap() + OrderCommission();
    }
    }
    return profit;
    }

    //+------------------------------------------------------------------+
    //| 检查是否达到利润目标 |
    //+------------------------------------------------------------------+
    bool IsProfitTargetReached()
    {
    double floatingProfit = CalculateFloatingProfit();
    int totalLevels = buyLevelCount + sellLevelCount;
    double target = GetDynamicProfitTarget(totalLevels);
    if(floatingProfit >= target)
    return true;
    return false;
    }

    //+------------------------------------------------------------------+
    //| 开立买入网格订单 |
    //+------------------------------------------------------------------+
    void OpenBuyOrder()
    {
    double spacing = GetGridSpacing();
    double entryPrice = Ask;
    if(buyLevelCount > 0 && lastGridPriceBuy > 0)
    {
    double expectedPrice = lastGridPriceBuy - spacing;
    if(entryPrice > expectedPrice)
    return;
    }
    double lotSize = InitialLotSize;
    if(buyLevelCount > 0)
    {
    if(UseSmartRecovery && buyLevelCount >= SmartRecoveryStart)
    {
    double avgPrice = 0, totalLots = 0;
    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
    if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
    if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && OrderType() == OP_BUY)
    { avgPrice += OrderOpenPrice() OrderLots(); totalLots += OrderLots(); }
    }
    if(totalLots > 0) avgPrice /= totalLots;
    lotSize = CalculateRecoveryLot(buyLevelCount + 1, entryPrice, avgPrice, totalLots);
    }
    else
    lotSize = InitialLotSize
    MathPow(LotMultiplier, buyLevelCount);
    }
    if(lotSize < 0.01) lotSize = 0.01;
    if(lotSize > 1.0) lotSize = 1.0;
    int ticket = OrderSend(Symbol(), OP_BUY, lotSize, entryPrice, 30, 0, 0, comment, MagicNumber, 0, clrNONE);
    if(ticket > 0)
    {
    lastGridPriceBuy = entryPrice;
    buyLevelCount++;
    }
    }

    //+------------------------------------------------------------------+
    //| 开立卖出网格订单 |
    //+------------------------------------------------------------------+
    void OpenSellOrder()
    {
    double spacing = GetGridSpacing();
    double entryPrice = Bid;
    if(sellLevelCount > 0 && lastGridPriceSell > 0)
    {
    double expectedPrice = lastGridPriceSell + spacing;
    if(entryPrice < expectedPrice)
    return;
    }
    double lotSize = InitialLotSize;
    if(sellLevelCount > 0)
    {
    if(UseSmartRecovery && sellLevelCount >= SmartRecoveryStart)
    {
    double avgPrice = 0, totalLots = 0;
    for(int i = OrdersTotal() - 1; i >= 0; i--)
    {
    if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
    if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && OrderType() == OP_SELL)
    { avgPrice += OrderOpenPrice() OrderLots(); totalLots += OrderLots(); }
    }
    if(totalLots > 0) avgPrice /= totalLots;
    lotSize = CalculateRecoveryLot(sellLevelCount + 1, entryPrice, avgPrice, totalLots);
    }
    else
    lotSize = InitialLotSize
    MathPow(LotMultiplier, sellLevelCount);
    }
    if(lotSize < 0.01) lotSize = 0.01;
    if(lotSize > 1.0) lotSize = 1.0;
    int ticket = OrderSend(Symbol(), OP_SELL, lotSize, entryPrice, 30, 0, 0, comment, MagicNumber, 0, clrNONE);
    if(ticket > 0)
    {
    lastGridPriceSell = entryPrice;
    sellLevelCount++;
    }
    }

    //+------------------------------------------------------------------+
    //| EA主循环函数(每Tick执行) |
    //+------------------------------------------------------------------+
    void OnTick()
    {
    // 每日亏损保护
    double currentEquity = AccountEquity();
    double lossPercent = (dailyStartBalance - currentEquity) / dailyStartBalance 100;
    if(lossPercent >= DailyLossLimit)
    {
    Comment("已达每日亏损上限,停止开新仓");
    return;
    }

    // 最大回撤保护
    if(currentEquity > equityPeak) equityPeak = currentEquity;
    double drawdownPercent = (equityPeak - currentEquity) / equityPeak
    100;
    if(drawdownPercent >= MaxDrawdownPercent && !drawdownStop)
    {
    CloseAllOrders();
    drawdownStop = true;
    Comment("已达最大回撤阈值,EA已停止");
    return;
    }

    // 周五收盘前平仓(规避周末跳空)
    if(UseFridayClose && !fridayCloseExecuted)
    {
    datetime now = TimeCurrent();
    if(TimeDayOfWeek(now) == 5 && TimeHour(now) >= 21)
    {
    CloseAllOrders();
    fridayCloseExecuted = true;
    return;
    }
    if(TimeDayOfWeek(now) != 5) fridayCloseExecuted = false;
    }

    // 点差过滤
    if(MarketInfo(Symbol(), MODE_SPREAD) > MaxSpread)
    {
    Comment("当前点差过大:", MarketInfo(Symbol(), MODE_SPREAD));
    return;
    }

    // 时间过滤
    if(!IsTradingTime())
    {
    Comment("非交易时段");
    return;
    }

    // 仅在新K线开始时检测入场(M15)
    if(Time[0] == lastBarTime) return;
    lastBarTime = Time[0];

    // 统计当前持仓
    CountPositions();

    // 检查利润目标
    if((buyLevelCount > 0 || sellLevelCount > 0) && IsProfitTargetReached())
    {
    CloseAllOrders();
    Print("达到利润目标,已平仓所有订单。");
    return;
    }

    // 检查总持仓限制
    if(buyLevelCount + sellLevelCount >= MaxTotalPositions)
    return;

    // 动量保护
    if(!IsMomentumSafe())
    {
    Comment("检测到高动量行情,网格暂停");
    return;
    }

    // RSI信号触发新方向首单
    double rsi1 = GetRSI(1);
    double rsi2 = GetRSI(2);
    bool rsiValid = (rsi1 > 0 && rsi1 < 100);

    // 做多信号:RSI超卖
    if(UseRSIFilter)
    {
    if(rsiValid && rsi1 <= RSIOversold && buyLevelCount == 0 && buyLevelCount + sellLevelCount < MaxTotalPositions)
    {
    OpenBuyOrder();
    }
    // 做空信号:RSI超买
    else if(rsiValid && rsi1 >= RSIOverbought && sellLevelCount == 0 && buyLevelCount + sellLevelCount < MaxTotalPositions)
    {
    OpenSellOrder();
    }
    }

    // 网格延续逻辑 - 买单侧
    if(buyLevelCount > 0 && buyLevelCount < MaxGridLevels)
    {
    double spacing = GetGridSpacing();
    double expectedNextPrice = lastGridPriceBuy - spacing;
    if(Bid <= expectedNextPrice)
    OpenBuyOrder();
    }

    // 网格延续逻辑 - 卖单侧
    if(sellLevelCount > 0 && sellLevelCount < MaxGridLevels)
    {
    double spacing = GetGridSpacing();
    double expectedNextPrice = lastGridPriceSell + spacing;
    if(Ask >= expectedNextPrice)
    OpenSellOrder();
    }

    // 显示信息
    Comment("买单层数: ", buyLevelCount, " | 卖单层数: ", sellLevelCount,
    "\nATR: ", DoubleToStr(atrValue, 2), " | 网格间距: ", DoubleToStr(GetGridSpacing(), 2),
    "\n浮动盈亏: $", DoubleToStr(CalculateFloatingProfit(), 2));
    }
    //+------------------------------------------------------------------+
    `
    参考来源: 原创MQL4代码,参考现代黄金网格交易理念编写 。
    免责声明: 网格和马丁策略在单边趋势行情中存在较大浮亏甚至爆仓风险。本EA按“原样”提供,不保证盈利。实盘交易前请在模拟账户测试至少3个月。历史表现不代表未来结果。
    ``