Summary: BTC Volatility Shield EA is a low-risk MQL4 expert advisor for Bitcoin (BTCUSD). It uses ATR volatility bands, ADX trend filter, and dynamic stop loss. Suitable for H4 timeframe.




BTC Volatility Shield EA is designed specifically for Bitcoin (BTCUSD) to handle its extreme volatility and erratic price behavior. The EA combines ATR-based volatility bands with ADX trend strength filter to avoid ranging and low-volatility chop zones. A unique dynamic position sizing reduces lot size during high volatility periods. Each trade is protected by a trailing stop mechanism that locks in profits as price moves favorably. The EA also includes a weekly drawdown limit and a post-loss cooldown timer.

Recommended Timeframe: H4
Trading Logic:
  • Volatility Regime: ATR(14) calculates current volatility; if ATR > ATR_Max_Threshold, skip trading.

  • Trend Strength: ADX(14) > ADX_Min (25) ensures trending market, no trades in ranging markets.

  • Entry Signal: Price touches lower ATR band (MA20 - ATR<em>BandMultiplier) for buys, or upper band for sells, with ADX confirming direction.

  • Risk Control: Dynamic trailing stop starts at 5x ATR, trailing step 2x ATR. Maximum 1 trade, weekly loss limit 8%.


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

    //--- input parameters with comments
    input double BaseLotSize = 0.01; // Base lot size (0.01 BTC)
    input int ATRPeriod = 14; // Period for ATR volatility indicator
    input double ATRMaxMultiplier = 2.5; // Max ATR multiplier (skip if ATR > avgATR this)
    input double BandMultiplier = 1.8; // ATR band multiplier for entry levels
    input int ADXPeriod = 14; // Period for ADX trend strength
    input int ADXMinThreshold = 25; // Minimum ADX value to allow trading
    input int MAPeriod = 20; // MA period for band center
    input int TrailingStart = 5; // Trailing stop start in ATR multiples
    input int TrailingStep = 2; // Trailing stop step in ATR multiples
    input int MagicNumber = 202413; // Unique EA identifier
    input int MaxSpread = 150; // Maximum allowed spread (in points, BTC is wide)
    input double WeeklyLossLimit = 8.0; // Weekly loss limit in percentage of balance
    input int CooldownMinutes = 60; // Cooldown after a losing trade (minutes)
    input bool UseCloseOnSunday = true; // Close all trades before Sunday 22:00

    //--- global variables
    double weeklyStartBalance = 0;
    datetime lastBarTime = 0;
    bool isSundayCloseExecuted = false;
    datetime lastLossTime = 0;
    double avgATR = 0;
    double currentTrailingSL = 0;

    //+------------------------------------------------------------------+
    //| Expert initialization function |
    //+------------------------------------------------------------------+
    int OnInit()
    {
    weeklyStartBalance = AccountBalance();
    lastBarTime = 0;
    isSundayCloseExecuted = false;
    lastLossTime = 0;
    avgATR = iATR(Symbol(), PERIOD_H4, ATRPeriod, 1);
    if(avgATR <= 0) avgATR = 500;
    return(INIT_SUCCEEDED);
    }

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

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

    // Sunday close before weekend gap (Bitcoin trades 24/7 but broker may have gaps)
    if(UseCloseOnSunday && !isSundayCloseExecuted)
    {
    datetime currentTime = TimeCurrent();
    if(TimeDayOfWeek(currentTime) == 0 && TimeHour(currentTime) >= 22)
    {
    CloseAllOrders();
    isSundayCloseExecuted = true;
    return;
    }
    if(TimeDayOfWeek(currentTime) != 0)
    isSundayCloseExecuted = false;
    }

    // Cooldown after losing trade
    if(lastLossTime > 0 && TimeCurrent() - lastLossTime < CooldownMinutes
    60)
    {
    Comment("Cooldown period active after loss");
    return;
    }

    // Spread filter (Bitcoin spread is wider)
    if(MarketInfo(Symbol(), MODE_SPREAD) > MaxSpread)
    {
    Comment("Spread too high for BTC");
    return;
    }

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

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

    // Get ATR and update average
    double atr = iATR(Symbol(), PERIOD_H4, ATRPeriod, 1);
    double atrThreshold = avgATR ATRMaxMultiplier;
    if(atr > atrThreshold && atrThreshold > 0)
    {
    Comment("Extreme volatility, no trade. ATR: ", atr);
    return;
    }
    avgATR = (avgATR
    0.95) + (atr 0.05);

    // ADX trend strength filter
    double adx = iADX(Symbol(), PERIOD_H4, ADXPeriod, PRICE_CLOSE, MODE_MAIN, 1);
    if(adx < ADXMinThreshold)
    {
    Comment("No strong trend, ADX: ", adx);
    return;
    }

    // Moving average center for ATR bands
    double ma = iMA(Symbol(), PERIOD_H4, MAPeriod, 0, MODE_SMA, PRICE_CLOSE, 1);
    double close1 = iClose(Symbol(), PERIOD_H4, 1);

    double lowerBand = ma - (atr
    BandMultiplier);
    double upperBand = ma + (atr BandMultiplier);

    int cmd = -1;
    double sl = 0, tp = 0;
    double dynamicLot = BaseLotSize;

    // Reduce lot size if ATR is above average
    if(atr > avgATR)
    dynamicLot = BaseLotSize
    (avgATR / atr);
    if(dynamicLot < 0.01) dynamicLot = 0.01;

    // Buy signal: price touched lower band, ADX confirms upward trend (DI+ > DI-)
    double diPlus = iADX(Symbol(), PERIOD_H4, ADXPeriod, PRICE_CLOSE, MODE_PLUSDI, 1);
    double diMinus = iADX(Symbol(), PERIOD_H4, ADXPeriod, PRICE_CLOSE, MODE_MINUSDI, 1);

    if(close1 <= lowerBand && diPlus > diMinus)
    {
    cmd = OP_BUY;
    sl = SymbolInfoDouble(Symbol(), SYMBOL_BID) - (atr TrailingStart);
    tp = SymbolInfoDouble(Symbol(), SYMBOL_BID) + (atr
    TrailingStart 2);
    }
    // Sell signal: price touched upper band, ADX confirms downward trend (DI- > DI+)
    else if(close1 >= upperBand && diMinus > diPlus)
    {
    cmd = OP_SELL;
    sl = SymbolInfoDouble(Symbol(), SYMBOL_ASK) + (atr
    TrailingStart);
    tp = SymbolInfoDouble(Symbol(), SYMBOL_ASK) - (atr TrailingStart 2);
    }

    if(cmd != -1)
    {
    int ticket = OrderSend(Symbol(), cmd, dynamicLot, (cmd==OP_BUY?Ask:Bid), 3, sl, tp, "BTC Volatility EA", MagicNumber, 0, clrNONE);
    if(ticket < 0)
    {
    Print("OrderSend failed: ", GetLastError());
    }
    else
    {
    currentTrailingSL = (cmd==OP_BUY) ? sl : sl;
    }
    }
    }

    //+------------------------------------------------------------------+
    //| 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 atr = iATR(Symbol(), PERIOD_H4, ATRPeriod, 1);
    if(atr <= 0) atr = avgATR;

    double newSL = 0;
    if(OrderType() == OP_BUY)
    {
    newSL = Bid - (atr TrailingStep);
    if(newSL > OrderStopLoss())
    {
    if(OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrNONE))
    Print("Trailing stop updated for BUY #", OrderTicket());
    }
    }
    else if(OrderType() == OP_SELL)
    {
    newSL = Ask + (atr
    TrailingStep);
    if(newSL < OrderStopLoss() || OrderStopLoss() == 0)
    {
    if(OrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit(), 0, clrNONE))
    Print("Trailing stop updated for 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;
    }

    //+------------------------------------------------------------------+
    //| 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, 3, clrNONE);
    else if(OrderType() == OP_SELL)
    OrderClose(OrderTicket(), OrderLots(), Ask, 3, clrNONE);
    }
    }
    }
    }

    //+------------------------------------------------------------------+
    //| Record loss time when order closes in loss (call from external) |
    //+------------------------------------------------------------------+
    void RecordLoss()
    {
    lastLossTime = TimeCurrent();
    }
    //+------------------------------------------------------------------+
    ``
    Reference: Original MQL4 code for educational purposes.
    Disclaimer: Bitcoin trading carries extremely high risk due to volatility. This EA is provided as-is without any guarantee of profit. Test thoroughly on demo before live trading. Past performance does not guarantee future results.