Summary: Gold Thunderstorm EA is a high-profit MQL4 expert advisor for XAUUSD. It uses breakout detection, dynamic lot multiplication on loss, and volatility-based trade frequency. Suitable for M15 timeframe.




Gold Thunderstorm EA is engineered for gold (XAUUSD) to pursue high profit potential while incorporating controlled risk mechanisms. The EA identifies key support/resistance breakouts using Bollinger Bands and ATR volatility. When a losing trade occurs, it employs a calculated martingale recovery with lot multiplication (configurable) but limited to a maximum recovery cycle. Volatility scaling adjusts lot sizes during high-impact news periods. The strategy aims for quick 1:1 to 1:2 risk-reward trades with aggressive trailing profit locking.

Recommended Timeframe: M15
Trading Logic:
  • Breakout Detection: Price closes beyond Bollinger Bands (20,2) after consolidation (narrow range defined by ATR).

  • Entry: Immediate market order on breakout confirmation with pending stop orders for retest.

  • Recovery Mode: After a loss, next trade lot = PreviousLot <em> RecoveryMultiplier (capped at MaxRecoverySteps).

  • Volatility Scaling: Higher ATR reduces lot size; lower ATR increases lot size (within limits).

  • Risk Control: Max daily loss 10%, max spread 40 points, Friday trade lock 1 hour before close.


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

    //--- input parameters with comments
    input double BaseLotSize = 0.01; // Base lot size for first trade
    input double RecoveryMultiplier = 1.8; // Lot multiplier after loss (martingale)
    input int MaxRecoverySteps = 3; // Maximum martingale recovery steps
    input int BollingerPeriod = 20; // Bollinger Bands period
    input double BollingerDeviation = 2.0; // Bollinger Bands deviation
    input int ATRPeriod = 14; // ATR period for volatility filter
    input double MinATRPercentile = 0.4; // Min ATR from 20-bar average (0.4 = 40%)
    input double MaxATRPercentile = 1.6; // Max ATR from 20-bar average
    input int RiskRewardRatio = 150; // Risk-reward ratio (profit target = SL Ratio/100)
    input int StopLossPoints = 150; // Fixed stop loss in points (150 for gold)
    input int TrailingStopTrigger = 80; // Points profit to trigger trailing stop
    input int TrailingStep = 25; // Trailing stop step in points
    input int MagicNumber = 202414; // Unique EA identifier
    input int MaxSpread = 40; // Maximum allowed spread (points)
    input double DailyLossLimit = 10.0; // Daily loss limit in percentage
    input bool UseFridayLock = true; // No new trades 1 hour before Friday close
    input int Slippage = 3; // Allowed slippage in points

    //--- global variables
    double dailyStartBalance = 0;
    datetime lastBarTime = 0;
    int consecutiveLosses = 0;
    double lastLotUsed = 0;
    double currentATR20Avg = 0;
    bool fridayLockActive = false;

    //+------------------------------------------------------------------+
    //| Expert initialization function |
    //+------------------------------------------------------------------+
    int OnInit()
    {
    dailyStartBalance = AccountBalance();
    lastBarTime = 0;
    consecutiveLosses = 0;
    lastLotUsed = BaseLotSize;
    fridayLockActive = false;
    currentATR20Avg = iATR(Symbol(), PERIOD_M15, ATRPeriod, 1);
    if(currentATR20Avg <= 0) currentATR20Avg = 50;
    return(INIT_SUCCEEDED);
    }

    //+------------------------------------------------------------------+
    //| Expert deinitialization function |
    //+------------------------------------------------------------------+
    void OnDeinit(const int reason)
    {
    Comment("");
    }

    //+------------------------------------------------------------------+
    //| Expert tick function |
    //+------------------------------------------------------------------+
    void OnTick()
    {
    // Daily equity protection
    double currentEquity = AccountEquity();
    double lossPercent = (dailyStartBalance - currentEquity) / dailyStartBalance 100;
    if(lossPercent >= DailyLossLimit)
    {
    Comment("Daily loss limit reached. No new trades.");
    return;
    }

    // Reset daily balance at new day
    if(TimeDayOfYear(TimeCurrent()) != TimeDayOfYear(TimeCurrent()-PeriodSeconds(PERIOD_D1)))
    dailyStartBalance = AccountBalance();

    // Friday lock: no new trades 1 hour before market close (Friday 21:00 broker time)
    if(UseFridayLock)
    {
    datetime currentTime = TimeCurrent();
    int dayOfWeek = TimeDayOfWeek(currentTime);
    int hour = TimeHour(currentTime);
    if(dayOfWeek == 5 && hour >= 20)
    fridayLockActive = true;
    else
    fridayLockActive = false;

    if(fridayLockActive)
    {
    Comment("Friday lock active. No new trades.");
    return;
    }
    }

    // Spread filter
    if(MarketInfo(Symbol(), MODE_SPREAD) > MaxSpread)
    {
    Comment("Spread too high: ", MarketInfo(Symbol(), MODE_SPREAD));
    return;
    }

    // New bar logic (M15)
    if(Time[0] == lastBarTime)
    return;
    lastBarTime = Time[0];

    // Check for existing position
    if(CountPositions() > 0)
    {
    ManageTrailingStop();
    return;
    }

    // Volatility scaling: calculate dynamic lot size based on current ATR vs average
    double atr = iATR(Symbol(), PERIOD_M15, ATRPeriod, 1);
    double atr20Avg = 0;
    for(int i=1; i<=20; i++)
    atr20Avg += iATR(Symbol(), PERIOD_M15, ATRPeriod, i);
    atr20Avg /= 20;
    currentATR20Avg = atr20Avg;

    double atrRatio = atr / atr20Avg;
    if(atrRatio < MinATRPercentile || atrRatio > MaxATRPercentile)
    {
    Comment("ATR ratio out of range: ", atrRatio);
    return;
    }

    double dynamicLot = BaseLotSize;
    if(consecutiveLosses > 0 && consecutiveLosses <= MaxRecoverySteps)
    dynamicLot = lastLotUsed
    RecoveryMultiplier;
    else if(consecutiveLosses > MaxRecoverySteps)
    dynamicLot = BaseLotSize;
    else
    dynamicLot = BaseLotSize;

    // Volatility adjustment: reduce lot when ATR is high
    double volatilityFactor = MathMax(0.5, MathMin(1.5, atr20Avg / atr));
    dynamicLot = dynamicLot volatilityFactor;
    if(dynamicLot < 0.01) dynamicLot = 0.01;
    if(dynamicLot > 1.0) dynamicLot = 1.0;

    // Bollinger Bands breakout detection
    double bollUpper = iBands(Symbol(), PERIOD_M15, BollingerPeriod, BollingerDeviation, 0, PRICE_CLOSE, MODE_UPPER, 1);
    double bollLower = iBands(Symbol(), PERIOD_M15, BollingerPeriod, BollingerDeviation, 0, PRICE_CLOSE, MODE_LOWER, 1);
    double close1 = iClose(Symbol(), PERIOD_M15, 1);
    double close0 = iClose(Symbol(), PERIOD_M15, 0);
    double high1 = iHigh(Symbol(), PERIOD_M15, 1);
    double low1 = iLow(Symbol(), PERIOD_M15, 1);

    // Check for consolidation before breakout (narrow range)
    double range1 = high1 - low1;
    double avgRange = iATR(Symbol(), PERIOD_M15, 20, 1);
    bool consolidated = (range1 < avgRange
    0.6);

    int cmd = -1;
    double sl = 0, tp = 0;
    double entryPrice = 0;

    // Bullish breakout: close above upper band after consolidation
    if(consolidated && close1 > bollUpper && close0 > bollUpper)
    {
    cmd = OP_BUY;
    entryPrice = Ask;
    sl = entryPrice - StopLossPoints Point;
    tp = entryPrice + (StopLossPoints
    RiskRewardRatio / 100) Point;
    }
    // Bearish breakout: close below lower band after consolidation
    else if(consolidated && close1 < bollLower && close0 < bollLower)
    {
    cmd = OP_SELL;
    entryPrice = Bid;
    sl = entryPrice + StopLossPoints
    Point;
    tp = entryPrice - (StopLossPoints RiskRewardRatio / 100) Point;
    }

    if(cmd != -1)
    {
    int ticket = OrderSend(Symbol(), cmd, dynamicLot, entryPrice, Slippage, sl, tp, "Gold Thunder EA", MagicNumber, 0, clrNONE);
    if(ticket > 0)
    {
    lastLotUsed = dynamicLot;
    Print("Order opened: ", ticket, " Lot: ", dynamicLot, " Loss streak: ", consecutiveLosses);
    }
    else
    {
    Print("OrderSend failed: ", GetLastError());
    }
    }
    }

    //+------------------------------------------------------------------+
    //| Manage trailing stop for open position |
    //+------------------------------------------------------------------+
    void ManageTrailingStop()
    {
    for(int i = OrdersTotal()-1; i >= 0; i--)
    {
    if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
    {
    if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
    {
    double profitPoints = 0;
    double newSL = 0;

    if(OrderType() == OP_BUY)
    {
    profitPoints = (Bid - OrderOpenPrice()) / Point;
    if(profitPoints >= TrailingStopTrigger)
    {
    newSL = Bid - TrailingStep Point;
    if(newSL > OrderStopLoss())
    {
    if(OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrNONE))
    Print("Trailing stop updated BUY #", OrderTicket());
    }
    }
    }
    else if(OrderType() == OP_SELL)
    {
    profitPoints = (OrderOpenPrice() - Ask) / Point;
    if(profitPoints >= TrailingStopTrigger)
    {
    newSL = Ask + TrailingStep
    Point;
    if(newSL < OrderStopLoss() || OrderStopLoss() == 0)
    {
    if(OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrNONE))
    Print("Trailing stop updated SELL #", OrderTicket());
    }
    }
    }
    break;
    }
    }
    }
    }

    //+------------------------------------------------------------------+
    //| 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;
    }

    //+------------------------------------------------------------------+
    //| Track loss streak (call from OnTick when order closes at loss) |
    //| In production, modify OrderSend to include custom tracking |
    //+------------------------------------------------------------------+
    void UpdateConsecutiveLosses(bool wasLoss)
    {
    if(wasLoss)
    consecutiveLosses++;
    else
    consecutiveLosses = 0;
    }
    //+------------------------------------------------------------------+
    ``
    Reference: Original MQL4 code for educational purposes.
    Disclaimer: High-profit strategies involve high risk including total loss of capital. Gold trading is volatile. This EA uses martingale recovery which can amplify losses. Test extensively on demo. Past performance does not guarantee future results. Not suitable for all investors.