Gold Cascade EA is engineered for stable gold trading using a disciplined "trend grid" approach. Unlike traditional grid systems that trade blindly in both directions, this EA only grids in the direction of the primary trend (H1 EMA50). It uses a multi-layer position structure (max 5 layers) with controlled dynamic lot sizing that increases gradually (not martingale). The EA includes ADX(14) trend strength filter (>25) to avoid ranging markets, ATR-based volatility guard, spread control, daily loss limit, and Friday close protection. The basket take profit mechanism closes all positions when the total floating profit reaches a configurable target, locking in accumulated gains.
Recommended Timeframe: H1
Trading Logic:
GridStepPoints (default 200 points) in trend direction, lot size increases by LotIncrement (default 0.01 per level).BasketTargetProfit (default $15 for 0.01 starting lot), close all positions.``
mql4
//+------------------------------------------------------------------+
//| GoldCascadeEA.mq4 |
//+------------------------------------------------------------------+
#property copyright ""
#property link ""
#property version "1.00"
#property strict
//--- input parameters with comments
input double StartLot = 0.01; // Starting lot size (0.01 for XAUUSD)
input double LotIncrement = 0.01; // Lot increment per grid level (0.01 add each level)
input int MaxGridLevels = 5; // Maximum grid levels (positions)
input int GridStepPoints = 200; // Grid step in points (200 points between levels)
input int TrendMAPeriod = 50; // EMA period for trend direction filter
input int ADXPeriod = 14; // ADX period for trend strength
input int ADXThreshold = 25; // Minimum ADX for trending market
input double ATRStopMultiplier = 1.5; // Stop loss as multiple of ATR
input double BasketTargetProfit = 15.0; // Basket take profit in dollars (for 0.01 start lot)
input double DailyLossLimit = 5.0; // Daily loss limit as percentage of balance
input int MaxSpread = 35; // Maximum allowed spread in points
input bool UseFridayClose = true; // Close trades before Friday 21:00 GMT
input int MagicNumber = 202502; // Unique EA identifier
//--- global variables
double dailyStartBalance = 0;
datetime lastBarTime = 0;
bool fridayCloseExecuted = false;
double avgATR = 0;
int consecutiveLosses = 0;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
dailyStartBalance = AccountBalance();
lastBarTime = 0;
fridayCloseExecuted = false;
avgATR = iATR(Symbol(), PERIOD_H1, 14, 1);
if(avgATR <= 0) avgATR = 250 Point;
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
Comment("");
}
//+------------------------------------------------------------------+
//| Get trend direction from EMA |
//+------------------------------------------------------------------+
int GetTrendDirection()
{
double close1 = iClose(Symbol(), PERIOD_H1, 1);
double ema = iMA(Symbol(), PERIOD_H1, TrendMAPeriod, 0, MODE_EMA, PRICE_CLOSE, 1);
if(close1 > ema) return 1; // Bullish trend
if(close1 < ema) return -1; // Bearish trend
return 0;
}
//+------------------------------------------------------------------+
//| Check ADX trend strength |
//+------------------------------------------------------------------+
bool IsTrendStrong()
{
double adx = iADX(Symbol(), PERIOD_H1, ADXPeriod, PRICE_CLOSE, MODE_MAIN, 1);
return (adx >= ADXThreshold);
}
//+------------------------------------------------------------------+
//| Calculate current grid level count for given direction |
//+------------------------------------------------------------------+
int CountGridPositions(int direction)
{
int count = 0;
for(int i = OrdersTotal()-1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
{
if((direction == 1 && OrderType() == OP_BUY) ||
(direction == -1 && OrderType() == OP_SELL))
count++;
}
}
}
return count;
}
//+------------------------------------------------------------------+
//| Get last order price for grid direction |
//+------------------------------------------------------------------+
double GetLastOrderPrice(int direction)
{
double lastPrice = 0;
datetime lastTime = 0;
for(int i = OrdersTotal()-1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
{
if((direction == 1 && OrderType() == OP_BUY) ||
(direction == -1 && OrderType() == OP_SELL))
{
if(OrderOpenTime() > lastTime)
{
lastTime = OrderOpenTime();
lastPrice = OrderOpenPrice();
}
}
}
}
}
return lastPrice;
}
//+------------------------------------------------------------------+
//| Calculate total floating profit of all grid positions |
//+------------------------------------------------------------------+
double CalculateBasketProfit()
{
double totalProfit = 0;
for(int i = OrdersTotal()-1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
{
totalProfit += OrderProfit() + OrderSwap() + OrderCommission();
}
}
}
return totalProfit;
}
//+------------------------------------------------------------------+
//| Close all grid positions (basket close) |
//+------------------------------------------------------------------+
void CloseAllGridOrders()
{
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);
}
}
}
}
//+------------------------------------------------------------------+
//| Calculate lot size for next grid level |
//+------------------------------------------------------------------+
double GetNextLotSize(int currentLevel)
{
// Lot = StartLot + (currentLevel LotIncrement)
// Level 0 (first position): StartLot
// Level 1: StartLot + LotIncrement
// Level 2: StartLot + 2 LotIncrement
double lot = StartLot + (currentLevel LotIncrement);
if(lot < 0.01) lot = 0.01;
if(lot > 1.0) lot = 1.0;
return NormalizeDouble(lot, 2);
}
//+------------------------------------------------------------------+
//| Check if we should add a new grid layer |
//+------------------------------------------------------------------+
bool ShouldAddGridLayer(int direction, int currentLevel, double lastPrice)
{
if(currentLevel >= MaxGridLevels) return false;
double currentPrice = (direction == 1) ? Bid : Ask;
double step = GridStepPoints Point;
double distance = MathAbs(currentPrice - lastPrice);
return (distance >= step);
}
//+------------------------------------------------------------------+
//| Open first position (trend entry) |
//+------------------------------------------------------------------+
bool OpenFirstPosition(int direction, double atr)
{
double entryPrice = 0, sl = 0, tp = 0;
int cmd = (direction == 1) ? OP_BUY : OP_SELL;
if(direction == 1)
{
entryPrice = Ask;
sl = entryPrice - (atr ATRStopMultiplier);
// No take profit for individual positions - basket take profit manages exits
tp = 0;
}
else
{
entryPrice = Bid;
sl = entryPrice + (atr ATRStopMultiplier);
tp = 0;
}
double lot = StartLot;
int ticket = OrderSend(Symbol(), cmd, lot, entryPrice, 5, sl, tp, "Cascade L1", MagicNumber, 0, clrNONE);
if(ticket > 0)
{
Print("First position opened. Direction: ", direction==1?"BUY":"SELL");
return true;
}
else
{
Print("Failed to open first position. Error: ", GetLastError());
return false;
}
}
//+------------------------------------------------------------------+
//| Add grid layer position |
//+------------------------------------------------------------------+
bool AddGridLayer(int direction, int currentLevel)
{
double entryPrice = 0, sl = 0;
int cmd = (direction == 1) ? OP_BUY : OP_SELL;
double atr = iATR(Symbol(), PERIOD_H1, 14, 1);
if(atr <= 0) atr = avgATR;
if(direction == 1)
{
entryPrice = Ask;
sl = entryPrice - (atr ATRStopMultiplier);
}
else
{
entryPrice = Bid;
sl = entryPrice + (atr ATRStopMultiplier);
}
double lot = GetNextLotSize(currentLevel);
int ticket = OrderSend(Symbol(), cmd, lot, entryPrice, 5, sl, 0, "Cascade L" + string(currentLevel+1), MagicNumber, 0, clrNONE);
if(ticket > 0)
{
Print("Grid layer ", currentLevel+1, " added. Lot: ", lot);
return true;
}
else
{
Print("Failed to add grid layer. Error: ", GetLastError());
return false;
}
}
//+------------------------------------------------------------------+
//| Check for pullback to EMA for first entry |
//+------------------------------------------------------------------+
bool IsPullbackEntry(int direction)
{
double close1 = iClose(Symbol(), PERIOD_H1, 1);
double low1 = iLow(Symbol(), PERIOD_H1, 1);
double high1 = iHigh(Symbol(), PERIOD_H1, 1);
double ema = iMA(Symbol(), PERIOD_H1, TrendMAPeriod, 0, MODE_EMA, PRICE_CLOSE, 1);
double open1 = iOpen(Symbol(), PERIOD_H1, 1);
if(direction == 1) // Bullish: price pulled back to or below EMA, then closed above
{
bool touchedEMA = (low1 <= ema);
bool closedAbove = (close1 > ema);
bool bullishCandle = (close1 > open1);
return (touchedEMA && closedAbove && bullishCandle);
}
else if(direction == -1) // Bearish: price pulled back to or above EMA, then closed below
{
bool touchedEMA = (high1 >= ema);
bool closedBelow = (close1 < ema);
bool bearishCandle = (close1 < open1);
return (touchedEMA && closedBelow && bearishCandle);
}
return false;
}
//+------------------------------------------------------------------+
//| Check daily loss limit |
//+------------------------------------------------------------------+
bool IsDailyLossExceeded()
{
double currentEquity = AccountEquity();
double lossPercent = (dailyStartBalance - currentEquity) / dailyStartBalance 100;
return (lossPercent >= DailyLossLimit);
}
//+------------------------------------------------------------------+
//| Manage basket take profit |
//+------------------------------------------------------------------+
bool CheckBasketTakeProfit()
{
double basketProfit = CalculateBasketProfit();
if(basketProfit >= BasketTargetProfit)
{
CloseAllGridOrders();
Print("Basket take profit triggered. Profit: $", basketProfit);
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
// Daily loss protection
if(IsDailyLossExceeded())
{
Comment("Daily loss limit reached. No new trades.");
return;
}
// Friday close protection
if(UseFridayClose && !fridayCloseExecuted)
{
datetime currentTime = TimeCurrent();
if(TimeDayOfWeek(currentTime) == 5 && TimeHour(currentTime) >= 21)
{
CloseAllGridOrders();
fridayCloseExecuted = true;
return;
}
if(TimeDayOfWeek(currentTime) != 5)
fridayCloseExecuted = false;
}
// 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];
// Update average ATR
double atr = iATR(Symbol(), PERIOD_H1, 14, 1);
if(atr > 0) avgATR = (avgATR 0.95) + (atr 0.05);
// Check existing positions
int posCount = CountGridPositions(1) + CountGridPositions(-1);
if(posCount > 0)
{
// Check basket take profit first
if(CheckBasketTakeProfit())
return;
// Determine direction from existing positions
int direction = 0;
if(CountGridPositions(1) > 0) direction = 1;
else if(CountGridPositions(-1) > 0) direction = -1;
if(direction != 0)
{
int currentLevel = CountGridPositions(direction);
double lastPrice = GetLastOrderPrice(direction);
if(ShouldAddGridLayer(direction, currentLevel, lastPrice))
{
AddGridLayer(direction, currentLevel);
}
}
return;
}
// No positions - check for new entry
// Get trend direction and strength
int trendDir = GetTrendDirection();
if(trendDir == 0)
{
Comment("No clear trend direction");
return;
}
if(!IsTrendStrong())
{
Comment("ADX below threshold. No strong trend.");
return;
}
// Check pullback entry
if(IsPullbackEntry(trendDir))
{
OpenFirstPosition(trendDir, atr);
}
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
``Reference: Original MQL4 code inspired by institutional trend grid principles observed in professional gold trading systems.
Disclaimer: Gold trading involves significant risk due to high volatility and leverage. Grid strategies can amplify losses in strong trending markets. 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.