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




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

推荐加载周期: M15
策略核心逻辑:
1. 入场过滤:已收盘K线的RSI(14)必须达到≥70(做空)或≤30(做多)才触发首单。
2. 网格间距:ATR(14) × 倍数计算动态网格层间距。
3. 利润衰减:目标利润随网格层数增加而递减(深度浮亏时更易安全退出)。
4. 智能解套:层数超过阈值后,通过算法使行情仅回调10%即可解套。
5. 动量保护:单根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个月。历史表现不代表未来结果。
```