Summary: Gold Structural Edge EA is an MQL4 expert advisor for XAUUSD that identifies H1 pivot zone breakouts confirmed by multi-EMA trend filter. Features hard drawdown limits, daily loss caps, and pure structure logic.
Gold Structural Edge EA is engineered based on the principle that successful gold trading requires structural clarity rather than signal noise. The EA identifies H1 pivot zones — swing highs and lows that define market structure — and waits for price to break these levels with confirmation from a multi-EMA trend filter (Vegas Tunnel: 144, 288, 576 EMAs). No martingale, no grid, no hedging. Every trade carries a hard stop loss placed beyond the pivot zone and a take profit based on ATR reward ratio. The EA includes hard-coded risk limits that actually trigger: daily loss limit halts trading, total drawdown protection stops new positions, and an emergency brake closes all trades when volatility exceeds 2.5x ATR. These limits are not decorative — they are the reason the strategy maintains controlled drawdowns across full market cycles.
Recommended Timeframe: H1
Trading Logic:
1. Pivot Zone Detection: Identify the highest high and lowest low of the last 20 H1 candles as structural pivot levels.
2. Trend Filter: Vegas Tunnel (EMAs 144, 288, 576) on H1 must align — all three EMAs sloping in the same direction.
3. Breakout Confirmation: Price closes above pivot high (bullish) or below pivot low (bearish) with a momentum candle (body > 0.7x range).
4. Entry: At market open of the next candle after confirmation.
5. Risk Management: Hard stop at 1.5x ATR beyond pivot zone; take profit at 2.2x ATR; trailing stop after 0.8x ATR profit.
```mql4
//+------------------------------------------------------------------+
//| GoldStructuralEdgeEA.mq4 |
//| |
//+------------------------------------------------------------------+
#property copyright ""
#property link ""
#property version "1.00"
#property strict
//--- input parameters with comments
input double LotSize = 0.01; // Fixed lot size (0.01 for XAUUSD)
input int PivotLookback = 20; // Bars for pivot zone detection
input int VegasFastEMA = 144; // Vegas Tunnel fast EMA
input int VegasMidEMA = 288; // Vegas Tunnel mid EMA
input int VegasSlowEMA = 576; // Vegas Tunnel slow EMA
input double MinBodyRangeRatio = 0.7; // Minimum body/range ratio for momentum confirmation
input int ATRPeriod = 14; // ATR period for stop/take calculation
input double ATRStopMultiplier = 1.5; // Stop loss as multiple of ATR
input double ATRTakeMultiplier = 2.2; // Take profit as multiple of ATR
input double TrailingStartATR = 0.8; // Trailing activates at profit (x ATR)
input double TrailingStepATR = 0.4; // Trailing step (x ATR)
input double MaxDailyLossPercent = 3.0; // Hard daily loss limit (trading stops)
input double MaxDrawdownPercent = 8.0; // Hard total drawdown limit
input int MaxConsecutiveLosses = 5; // Max consecutive losses before pause
input double EmergencyATRMultiplier = 2.5; // Emergency brake: close all if ATR exceeds avgATR * this
input int MagicNumber = 202502; // Unique EA identifier
input int MaxSpread = 35; // Maximum allowed spread in points
//--- global variables
double dailyStartBalance = 0;
double peakEquity = 0;
datetime lastBarTime = 0;
int consecutiveLosses = 0;
datetime lastLossTime = 0;
double avgATR = 0;
bool drawdownStop = false;
bool dailyStop = false;
double pivotHigh = 0;
double pivotLow = 0;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
dailyStartBalance = AccountBalance();
peakEquity = AccountEquity();
lastBarTime = 0;
consecutiveLosses = 0;
drawdownStop = false;
dailyStop = false;
avgATR = iATR(Symbol(), PERIOD_H1, ATRPeriod, 1);
if(avgATR <= 0) avgATR = 250 * Point;
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
Comment("");
}
//+------------------------------------------------------------------+
//| Get Vegas Tunnel trend direction (all EMAs aligned) |
//+------------------------------------------------------------------+
int GetVegasTrend()
{
double emaFast = iMA(Symbol(), PERIOD_H1, VegasFastEMA, 0, MODE_EMA, PRICE_CLOSE, 1);
double emaMid = iMA(Symbol(), PERIOD_H1, VegasMidEMA, 0, MODE_EMA, PRICE_CLOSE, 1);
double emaSlow = iMA(Symbol(), PERIOD_H1, VegasSlowEMA, 0, MODE_EMA, PRICE_CLOSE, 1);
double emaFastPrev = iMA(Symbol(), PERIOD_H1, VegasFastEMA, 0, MODE_EMA, PRICE_CLOSE, 2);
double emaMidPrev = iMA(Symbol(), PERIOD_H1, VegasMidEMA, 0, MODE_EMA, PRICE_CLOSE, 2);
double emaSlowPrev = iMA(Symbol(), PERIOD_H1, VegasSlowEMA, 0, MODE_EMA, PRICE_CLOSE, 2);
bool bullishAlign = (emaFast > emaMid && emaMid > emaSlow);
bool bearishAlign = (emaFast < emaMid && emaMid < emaSlow);
bool bullishSlope = (emaFast > emaFastPrev && emaMid > emaMidPrev && emaSlow > emaSlowPrev);
bool bearishSlope = (emaFast < emaFastPrev && emaMid < emaMidPrev && emaSlow < emaSlowPrev);
if(bullishAlign && bullishSlope) return 1;
if(bearishAlign && bearishSlope) return -1;
return 0;
}
//+------------------------------------------------------------------+
//| Detect pivot zone levels (swing highs/lows) |
//+------------------------------------------------------------------+
void DetectPivotZone()
{
int highestIdx = iHighest(Symbol(), PERIOD_H1, MODE_HIGH, PivotLookback, 1);
int lowestIdx = iLowest(Symbol(), PERIOD_H1, MODE_LOW, PivotLookback, 1);
if(highestIdx > 0)
pivotHigh = iHigh(Symbol(), PERIOD_H1, highestIdx);
if(lowestIdx > 0)
pivotLow = iLow(Symbol(), PERIOD_H1, lowestIdx);
}
//+------------------------------------------------------------------+
//| Check momentum candle quality |
//+------------------------------------------------------------------+
bool IsMomentumCandle(int direction)
{
double open = iOpen(Symbol(), PERIOD_H1, 1);
double close = iClose(Symbol(), PERIOD_H1, 1);
double high = iHigh(Symbol(), PERIOD_H1, 1);
double low = iLow(Symbol(), PERIOD_H1, 1);
double range = high - low;
double body = MathAbs(close - open);
if(range <= 0) return false;
if(body / range < MinBodyRangeRatio) return false;
if(direction == 1) // bullish momentum
return (close > open && close > pivotHigh);
else if(direction == -1) // bearish momentum
return (close < open && close < pivotLow);
return false;
}
//+------------------------------------------------------------------+
//| Check breakout entry condition |
//+------------------------------------------------------------------+
bool CheckBreakoutEntry(int trendDir, double &entryPrice, double &sl, double &tp, double atr)
{
if(trendDir == 0) return false;
if(pivotHigh <= 0 || pivotLow <= 0) return false;
double close1 = iClose(Symbol(), PERIOD_H1, 1);
if(trendDir == 1 && close1 > pivotHigh && IsMomentumCandle(1))
{
entryPrice = Ask;
sl = entryPrice - (atr * ATRStopMultiplier);
tp = entryPrice + (atr * ATRTakeMultiplier);
return true;
}
else if(trendDir == -1 && close1 < pivotLow && IsMomentumCandle(-1))
{
entryPrice = Bid;
sl = entryPrice + (atr * ATRStopMultiplier);
tp = entryPrice - (atr * ATRTakeMultiplier);
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| Update consecutive loss counter |
//+------------------------------------------------------------------+
void UpdateLossCounter()
{
static int prevOrders = 0;
static double prevEquity = 0;
int currentOrders = CountPositions();
double currentEquity = AccountEquity();
if(prevOrders > 0 && currentOrders == 0)
{
double equityChange = currentEquity - prevEquity;
if(equityChange < 0)
{
consecutiveLosses++;
lastLossTime = TimeCurrent();
}
else if(equityChange > 0)
{
consecutiveLosses = 0;
}
}
if(currentOrders > 0)
prevEquity = currentEquity;
prevOrders = currentOrders;
}
//+------------------------------------------------------------------+
//| Check and enforce hard risk limits |
//+------------------------------------------------------------------+
bool CheckHardRiskLimits()
{
double currentEquity = AccountEquity();
double dailyLossPercent = (dailyStartBalance - currentEquity) / dailyStartBalance * 100;
double totalDrawdownPercent = (peakEquity - currentEquity) / peakEquity * 100;
// Update peak equity
if(currentEquity > peakEquity)
peakEquity = currentEquity;
// Daily loss limit
if(dailyLossPercent >= MaxDailyLossPercent)
{
if(!dailyStop)
{
CloseAllOrders();
dailyStop = true;
Comment("Daily loss limit reached. Trading halted for today.");
}
return false;
}
// Total drawdown limit
if(totalDrawdownPercent >= MaxDrawdownPercent)
{
if(!drawdownStop)
{
CloseAllOrders();
drawdownStop = true;
Comment("Max drawdown reached. EA paused.");
}
return false;
}
// Consecutive losses cooldown
if(consecutiveLosses >= MaxConsecutiveLosses)
{
if(TimeCurrent() - lastLossTime < 3600) // 1 hour cooldown
{
Comment("Consecutive loss cooldown active. ", consecutiveLosses, " losses.");
return false;
}
else
{
consecutiveLosses = 0;
}
}
return true;
}
//+------------------------------------------------------------------+
//| Emergency brake: close all if volatility explosion |
//+------------------------------------------------------------------+
void CheckEmergencyBrake()
{
double atr = iATR(Symbol(), PERIOD_H1, ATRPeriod, 1);
if(atr > avgATR * EmergencyATRMultiplier && avgATR > 0)
{
CloseAllOrders();
Comment("Emergency brake triggered. Extreme volatility: ATR ", atr);
}
if(atr > 0) avgATR = (avgATR * 0.95) + (atr * 0.05);
}
//+------------------------------------------------------------------+
//| Manage trailing stop |
//+------------------------------------------------------------------+
void ManageTrailingStop(double atr)
{
for(int i = OrdersTotal()-1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
{
double activate = atr * TrailingStartATR;
double step = atr * TrailingStepATR;
double newSL = 0;
if(OrderType() == OP_BUY)
{
double profit = Bid - OrderOpenPrice();
if(profit >= activate)
{
newSL = Bid - step;
if(newSL > OrderStopLoss())
OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrNONE);
}
}
else if(OrderType() == OP_SELL)
{
double profit = OrderOpenPrice() - Ask;
if(profit >= activate)
{
newSL = Ask + step;
if(newSL < OrderStopLoss() || OrderStopLoss() == 0)
OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrNONE);
}
}
break;
}
}
}
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// Update loss counter for market memory
UpdateLossCounter();
// Check emergency brake first
CheckEmergencyBrake();
// Check hard risk limits
if(!CheckHardRiskLimits())
return;
// Reset daily stop at new day
datetime currentTime = TimeCurrent();
static datetime lastDay = 0;
if(TimeDayOfYear(currentTime) != TimeDayOfYear(lastDay))
{
dailyStartBalance = AccountBalance();
dailyStop = false;
lastDay = currentTime;
}
// Friday close protection (optional, can be param)
if(TimeDayOfWeek(currentTime) == 5 && TimeHour(currentTime) >= 21)
{
if(CountPositions() > 0)
CloseAllOrders();
return;
}
// Spread filter
if(MarketInfo(Symbol(), MODE_SPREAD) > MaxSpread)
{
Comment("Spread too high: ", MarketInfo(Symbol(), MODE_SPREAD));
return;
}
// New bar logic (H1)
if(Time[0] == lastBarTime)
return;
lastBarTime = Time[0];
// Manage existing position
int posCount = CountPositions();
if(posCount > 0)
{
double atr = iATR(Symbol(), PERIOD_H1, ATRPeriod, 1);
if(atr > 0) ManageTrailingStop(atr);
return;
}
// Get ATR for volatility context
double atr = iATR(Symbol(), PERIOD_H1, ATRPeriod, 1);
if(atr <= 0) atr = avgATR;
// Detect pivot zone levels
DetectPivotZone();
// Get Vegas Tunnel trend direction
int trendDir = GetVegasTrend();
if(trendDir == 0)
{
Comment("Vegas Tunnel no clear alignment");
return;
}
// Check breakout entry
double entryPrice = 0, sl = 0, tp = 0;
if(CheckBreakoutEntry(trendDir, entryPrice, sl, tp, atr))
{
int cmd = (trendDir == 1) ? OP_BUY : OP_SELL;
int ticket = OrderSend(Symbol(), cmd, LotSize, entryPrice, 5, sl, tp, "Structural Edge", MagicNumber, 0, clrNONE);
if(ticket < 0)
Print("OrderSend failed: ", GetLastError());
else
Print("Pivot breakout entry. Direction: ", cmd==OP_BUY?"BUY":"SELL");
}
}
//+------------------------------------------------------------------+
//| Count open positions with this MagicNumber |
//+------------------------------------------------------------------+
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;
}
//+------------------------------------------------------------------+
//| Close all orders for this symbol and magic |
//+------------------------------------------------------------------+
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);
}
}
}
}
//+------------------------------------------------------------------+
```
Reference: Original MQL4 code inspired by structural principles from Gold BullBear Structure Trader and Vegas Tunnel-based systems (MQL5 Market, 2025-2026) .
Disclaimer: Gold trading involves significant risk due to high volatility and leverage. This EA is provided as-is without any guarantee of profit. Test thoroughly on a demo account for at least 3 months before live deployment. Past performance does not guarantee future results.