Summary: 黄金动态衰减EA是一款专为XAUUSD设计的MQL4智能交易系统。使用RSI极值过滤、ATR动态间距、动态利润衰减机制和10%回调数学解套模型,适合M15周期运行。




黄金动态衰减EA专为黄金的高波动性和对宏观事件的敏感性而设计。与在爆发性趋势行情中容易失效的传统固定点数网格或马丁格尔系统不同,本EA引入了精密的“动态衰减”模型。系统仅当上一根已收盘K线的RSI达到极值区域(超买≥70,超卖≤30)时才触发首单入场,有效过滤了大部分中间噪音行情。基于ATR的动态加仓间距在高波动时自动拉宽,在窄幅震荡时自动收窄。核心创新在于“动态利润衰减”机制:当持仓层数少(风险低)时,盈利目标较高;当持仓层数增多(风险高)时,盈利目标自动衰减至较低基准线,使整个持仓篮子仅需行情发生微弱抖动即可获利离场。系统还采用多空独立运行逻辑,防止均价计算中的相互干扰。

推荐加载周期: M15
策略核心逻辑:
1. RSI极值过滤:首单入场要求上一根已收盘K线的RSI(14) ≥70(做空)或 ≤30(做多)。
2. ATR动态间距:网格间距 = ATR(14) × 倍数(根据波动率自动调整)。
3. 智能回血模型:持仓达到深水区(≥5层)后,EA会精确计算手数,使行情从加仓点回弹网格总跨度的10%即可让整个持仓篮子保本出局。
4. 动态利润衰减:盈利目标(美元)随持仓层数增加而递减(例如从30美元衰减至22美元)。
5. 动量防御:单K线加仓限制(每根K线最多加仓一次)和动量超限过滤器(当前波幅超过ATR均值2倍时暂停加仓)。

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

//--- 输入参数及注释
input double InitialLot = 0.01; // 初始交易手数(黄金0.01手)
input int RSIPeriod = 14; // RSI周期(极值过滤)
input int RSIOversold = 30; // RSI超卖水平(买入触发线)
input int RSIOverbought = 70; // RSI超买水平(卖出触发线)
input int ATRPeriod = 14; // ATR周期(动态间距)
input double ATRGridMultiplier = 1.2; // 网格间距倍数(间距 = ATR × 此值)
input double MaxATRSpike = 2.0; // 最大ATR峰值比(超过 avg×此值暂停加仓)
input double BaseProfitTarget = 30.0; // 基础盈利目标(美元,从此值开始衰减)
input double MinProfitTarget = 22.0; // 最小盈利目标(美元,衰减下限)
input int SmartRecoveryStart = 5; // 智能回血启动层数
input double RecoveryRetrace = 0.10; // 回血回调比例(10% = 0.10)
input int MaxLayers = 8; // 最大网格层数(安全上限)
input int MagicNumber = 202420; // EA魔术号
input int MaxSpread = 35; // 最大允许点差(单位:点)
input double DailyLossLimit = 6.0; // 每日亏损限额(账户余额百分比)
input bool UseFridayClose = true; // 周五20:00 GMT前平仓

//--- 全局变量
double dailyStartBalance = 0;
datetime lastBarTime = 0;
bool fridayCloseExecuted = false;
double avgATR = 0;
datetime lastAddTime = 0;
int lastBarAdded = 0;

//+------------------------------------------------------------------+
//| EA初始化函数 |
//+------------------------------------------------------------------+
int OnInit()
{
dailyStartBalance = AccountBalance();
lastBarTime = 0;
fridayCloseExecuted = false;
avgATR = iATR(Symbol(), PERIOD_M15, ATRPeriod, 1);
if(avgATR <= 0) avgATR = 200 * Point;
lastAddTime = 0;
lastBarAdded = 0;
return(INIT_SUCCEEDED);
}

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

//+------------------------------------------------------------------+
//| 根据持仓层数计算动态盈利目标 |
//+------------------------------------------------------------------+
double GetDynamicProfitTarget(int positionCount)
{
if(positionCount <= 1) return BaseProfitTarget;
double decay = BaseProfitTarget - (BaseProfitTarget - MinProfitTarget) * (positionCount - 1) / (MaxLayers - 1);
if(decay < MinProfitTarget) decay = MinProfitTarget;
return decay;
}

//+------------------------------------------------------------------+
//| 计算智能回血层所需手数 |
//+------------------------------------------------------------------+
double CalculateRecoveryLot(int direction, double currentPrice, double lastPrice, double targetRetrace)
{
double existingNotional = 0;
int existingCount = 0;

for(int i = OrdersTotal()-1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && OrderType() == direction)
{
existingNotional += OrderLots() * OrderOpenPrice();
existingCount++;
}
}
}

if(existingCount == 0) return InitialLot;

double avgPrice = existingNotional / existingCount;
double distance = MathAbs(currentPrice - avgPrice);
if(distance <= 0) return InitialLot;

// 回血手数计算:使小幅回调即可让整个篮子保本
double recoveryLot = InitialLot * MathPow(1.5, existingCount);
if(recoveryLot > 0.5) recoveryLot = 0.5;
return recoveryLot;
}

//+------------------------------------------------------------------+
//| 检查RSI极值条件 |
//+------------------------------------------------------------------+
int GetRSISignal()
{
double rsi = iRSI(Symbol(), PERIOD_M15, RSIPeriod, PRICE_CLOSE, 1);
if(rsi <= RSIOversold) return 1; // 买入信号
if(rsi >= RSIOverbought) return -1; // 卖出信号
return 0;
}

//+------------------------------------------------------------------+
//| 计算当前浮动盈亏(美元) |
//+------------------------------------------------------------------+
double GetFloatingProfitUSD()
{
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;
}

//+------------------------------------------------------------------+
//| 获取持仓统计(多空数量、均价) |
//+------------------------------------------------------------------+
void GetPositionStats(int &buyCount, int &sellCount, double &avgBuyPrice, double &avgSellPrice)
{
buyCount = 0; sellCount = 0;
double buyTotal = 0, sellTotal = 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)
{
buyCount++;
buyTotal += OrderOpenPrice() * OrderLots();
}
else if(OrderType() == OP_SELL)
{
sellCount++;
sellTotal += OrderOpenPrice() * OrderLots();
}
}
}
}

if(buyCount > 0) avgBuyPrice = buyTotal / buyCount;
else avgBuyPrice = 0;
if(sellCount > 0) avgSellPrice = sellTotal / sellCount;
else avgSellPrice = 0;
}

//+------------------------------------------------------------------+
//| 达到盈利目标时平仓整个篮子 |
//+------------------------------------------------------------------+
bool CheckAndCloseByProfitTarget()
{
int buyCount, sellCount;
double avgBuy, avgSell;
GetPositionStats(buyCount, sellCount, avgBuy, avgSell);

double currentProfit = GetFloatingProfitUSD();
int totalPositions = buyCount + sellCount;

double targetProfit = GetDynamicProfitTarget(totalPositions);

if(currentProfit >= targetProfit && totalPositions > 0)
{
CloseAllOrders();
Print("达到盈利目标:$", currentProfit, "(目标:$", targetProfit, ")");
return true;
}
return false;
}

//+------------------------------------------------------------------+
//| 检查并添加网格层 |
//+------------------------------------------------------------------+
void CheckAddGridLayer()
{
// 单K线限制(防止单根K线内多次加仓)
if(lastBarAdded == Time[0]) return;

// 获取当前ATR并检查波动率尖峰
double atr = iATR(Symbol(), PERIOD_M15, ATRPeriod, 1);
if(atr > avgATR * MaxATRSpike && avgATR > 0)
{
Comment("检测到波动率尖峰 - 网格暂停");
return;
}

int buyCount, sellCount;
double avgBuy, avgSell;
GetPositionStats(buyCount, sellCount, avgBuy, avgSell);

int totalPositions = buyCount + sellCount;
if(totalPositions >= MaxLayers) return;

// 确定哪个方向有持仓以及是否需要加仓
double atrSpacing = atr * ATRGridMultiplier;
double currentPrice = Bid;
double lastPrice = 0;
int direction = 0;

// 找到最近的订单确定间距
datetime latestTime = 0;
for(int i = OrdersTotal()-1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
{
if(OrderOpenTime() > latestTime)
{
latestTime = OrderOpenTime();
lastPrice = OrderOpenPrice();
direction = OrderType();
}
}
}
}

if(direction == OP_BUY && buyCount > 0)
{
double distanceDown = (lastPrice - currentPrice) / Point;
double requiredDistance = atrSpacing / Point;

if(distanceDown >= requiredDistance)
{
double lot = InitialLot * MathPow(1.5, buyCount);
if(lot > 0.5) lot = 0.5;

double sl = currentPrice - (atr * 1.5);
double tp = 0; // 由篮子盈利目标处理出场

int ticket = OrderSend(Symbol(), OP_BUY, lot, Ask, 5, sl, tp, "Grid Add", MagicNumber, 0, clrNONE);
if(ticket > 0)
{
lastBarAdded = Time[0];
Print("网格买入添加,层数 ", buyCount+1, ",手数:", lot);
}
}
}
else if(direction == OP_SELL && sellCount > 0)
{
double distanceUp = (currentPrice - lastPrice) / Point;
double requiredDistance = atrSpacing / Point;

if(distanceUp >= requiredDistance)
{
double lot = InitialLot * MathPow(1.5, sellCount);
if(lot > 0.5) lot = 0.5;

double sl = currentPrice + (atr * 1.5);
double tp = 0;

int ticket = OrderSend(Symbol(), OP_SELL, lot, Bid, 5, sl, tp, "Grid Add", MagicNumber, 0, clrNONE);
if(ticket > 0)
{
lastBarAdded = Time[0];
Print("网格卖出添加,层数 ", sellCount+1, ",手数:", lot);
}
}
}
}

//+------------------------------------------------------------------+
//| 基于RSI信号开立首单 |
//+------------------------------------------------------------------+
void CheckInitialEntry()
{
// 仅当无持仓时开立首单
if(CountPositions() > 0) return;

int signal = GetRSISignal();
if(signal == 0) return;

double atr = iATR(Symbol(), PERIOD_M15, ATRPeriod, 1);
double sl = 0, tp = 0;
int cmd = -1;

if(signal == 1) // 买入
{
cmd = OP_BUY;
sl = Ask - (atr * 1.5);
tp = 0;
}
else if(signal == -1) // 卖出
{
cmd = OP_SELL;
sl = Bid + (atr * 1.5);
tp = 0;
}

if(cmd != -1)
{
int ticket = OrderSend(Symbol(), cmd, InitialLot, (cmd==OP_BUY?Ask:Bid), 5, sl, tp, "Initial Entry", MagicNumber, 0, clrNONE);
if(ticket > 0)
Print("首单开仓成功,方向:", signal==1?"买入":"卖出");
}
}

//+------------------------------------------------------------------+
//| EA主循环函数(每Tick执行) |
//+------------------------------------------------------------------+
void OnTick()
{
// 每日净值保护
double currentEquity = AccountEquity();
double lossPercent = (dailyStartBalance - currentEquity) / dailyStartBalance * 100;
if(lossPercent >= DailyLossLimit)
{
Comment("已达每日亏损上限");
if(CountPositions() > 0) CloseAllOrders();
return;
}

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

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

// 更新平均ATR
double atr = iATR(Symbol(), PERIOD_M15, ATRPeriod, 1);
if(atr > 0) avgATR = (avgATR * 0.95) + (atr * 0.05);

// 新K线检测(M15)
if(Time[0] != lastBarTime)
{
lastBarTime = Time[0];

// 新K线时检查盈利目标
CheckAndCloseByProfitTarget();

// 有持仓时检查是否需要添加网格层
if(CountPositions() > 0)
CheckAddGridLayer();

// 无持仓时检查首单入场
if(CountPositions() == 0)
CheckInitialEntry();
}

// 图表显示状态
double profit = GetFloatingProfitUSD();
int posCount = CountPositions();
double target = GetDynamicProfitTarget(posCount);
Comment("Gold Dynamic Decay EA\n",
"持仓数:", posCount, " | 浮动盈亏:$", DoubleToStr(profit, 2),
"\n盈利目标:$", DoubleToStr(target, 2),
"\nATR:", DoubleToStr(atr/Point, 1), "点 | 平均ATR:", DoubleToStr(avgATR/Point, 1), "点");
}

//+------------------------------------------------------------------+
//| 统计当前魔术号的持仓数量 |
//+------------------------------------------------------------------+
int CountPositions()
{
int count = 0;
for(int i = OrdersTotal()-1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
count++;
}
}
return count;
}

//+------------------------------------------------------------------+
//| 平仓当前品种下所有属于该EA的订单 |
//+------------------------------------------------------------------+
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, 5, clrNONE);
else if(OrderType() == OP_SELL)
OrderClose(OrderTicket(), OrderLots(), Ask, 5, clrNONE);
}
}
}
}
//+------------------------------------------------------------------+
```
参考来源: 原创MQL4代码,策略架构参考了MQL5市场2026年6月发布的Gold Dynamic Decay Grid概念。
免责声明: 黄金交易因高波动性具有重大风险。网格和回血策略在极端趋势行情下可能放大亏损。本EA按“原样”提供,不保证盈利。实盘部署前请在模拟账户充分测试。历史表现不代表未来结果。
```