#include <Trade\Trade.
mqh> // Include trade library for CTrade class
CTrade trade;              // Instantiate CTrade object
// Input parameters
input int MagicNumber = 12345;           //   Unique identifier for trades
input int RangeBars = 24;                //   Number of bars to calculate range
input double OrderOffsetPips = 5.0;      //   Offset for breakout orders in pips
input double SLOffsetPips = 0.0;         //   Stop loss offset in pips
input int TPType = 0;                    //   0 = fixed pips, 1 = risk-reward
input double TPValue = 100.0;            //   Take profit value (pips or ratio)
input double TrailingStopPips = 0.0;     //   Trailing stop in pips
input int TradingStartHour = 0;          //   Start hour for trading (0-23)
input int TradingStartMinute = 0;        //   Start minute for trading (0-59)
input int TradingEndHour = 23;           //   End hour for trading (0-23)
input int TradingEndMinute = 0;          //   End minute for trading (0-59)
input double MinRangePercent = 10.0;     //   Minimum range as % of ADR
input double MaxRangePercent = 40.0;     //   Maximum range as % of ADR
input int ADRPeriod = 14;                //   Period for ADR calculation
input int LotSizeType = 0;               //   0 = fixed, 1 = % risk
input double LotSizeValue = 0.1;         //   Lot size (fixed) or risk %
input double MaxSpreadPips = 2.0;        //   Maximum allowable spread in pips
// Target equity parameters
input bool UseTargetEquity = false;      // Enable/disable target equity feature
input double StartingEquity = 0;         // Starting equity amount
input double TargetEquity = 0;           // Target equity amount to stop the EA
// Global variables
datetime lastBarTime = 0;                //   Track the last processed bar
bool targetReached = false;              //   Flag to indicate if target is reached
double initialEquity = 0;                //   Initial equity value stored at start
double lotSizingInitialEquity;           //   Initial equity for lot sizing
// Initialization function
void OnInit()
{
   trade.SetExpertMagicNumber(MagicNumber); // Set magic number for trade
operations
   // Initialize starting equity if not set manually
   if(UseTargetEquity)
   {
      if(StartingEquity <= 0)
      {
         initialEquity = AccountInfoDouble(ACCOUNT_EQUITY);
         Print("Initial equity automatically set to current equity: ",
initialEquity);
      }
      else
      {
         initialEquity = StartingEquity;
         Print("Initial equity manually set to: ", initialEquity);
      }
       Print("Target equity set to: ", TargetEquity);
   }
   // Set initial equity for lot sizing
   lotSizingInitialEquity = AccountInfoDouble(ACCOUNT_EQUITY);
   Print("Lot sizing initial equity set to: ", lotSizingInitialEquity);
}
// Main tick event handler
void OnTick()
{
   // Check if target equity has been reached
   if(UseTargetEquity && TargetEquity > 0)
   {
      double currentEquity = AccountInfoDouble(ACCOUNT_EQUITY);
      // If target reached, set flag and close all positions
      if(currentEquity >= TargetEquity && !targetReached)
      {
         targetReached = true;
         Print("TARGET EQUITY REACHED! Current equity: ", currentEquity, " Target:
", TargetEquity);
         CloseAllPositions();
         DeletePendingOrders();
         return; // Exit function to prevent further trading
      }
        // If target already reached, don't process anything else
        if(targetReached)
        {
           return;
        }
    }
    if (IsNewBar())
    {
       if (!HasOpenPositions())
       {
          DeletePendingOrders(); // Remove existing pending orders
           // Calculate breakout range
           double rangeHigh, rangeLow;
           CalculateRange(RangeBars, rangeHigh, rangeLow);
           double rangeSize = rangeHigh - rangeLow;
           // Calculate Average Daily Range (ADR)
           double adr = CalculateADR(ADRPeriod);
           double minRange = adr * (MinRangePercent / 100.0);
           double maxRange = adr * (MaxRangePercent / 100.0);
         // Validate trading conditions
         if (rangeSize >= minRange && rangeSize <= maxRange)
         {
            if (IsTradingTime(TradingStartHour, TradingStartMinute, TradingEndHour,
TradingEndMinute))
            {
                double spreadPoints = (double)SymbolInfoInteger(_Symbol,
SYMBOL_SPREAD);
                double maxSpreadPoints = MaxSpreadPips * 10; // 1 pip = 10 points
for 5-digit brokers
                if (spreadPoints <= maxSpreadPoints)
                {
                   PlaceBreakoutOrders(rangeHigh, rangeLow);
                }
            }
           }
        }
        else
        {
           DeletePendingOrders(); // Clear pending orders if a position is open
        }
    }
    // Apply trailing stop if enabled
    if (TrailingStopPips > 0)
    {
       ApplyTrailingStop();
    }
}
// Close all open positions with our magic number
void CloseAllPositions()
{
   for (int i = PositionsTotal() - 1; i >= 0; i--)
   {
      if (PositionSelectByTicket(PositionGetTicket(i)) &&
PositionGetInteger(POSITION_MAGIC) == MagicNumber)
      {
         trade.PositionClose(PositionGetTicket(i));
      }
   }
}
// Check for a new bar
bool IsNewBar()
{
   datetime currentBarTime = iTime(_Symbol, PERIOD_CURRENT, 0);
   if (currentBarTime != lastBarTime)
   {
      lastBarTime = currentBarTime;
      return true;
   }
   return false;
}
// Calculate the high and low of the last N bars
void CalculateRange(int bars, double &high, double &low)
{
   double highArray[], lowArray[];
   ArraySetAsSeries(highArray, true);
   ArraySetAsSeries(lowArray, true);
   CopyHigh(_Symbol, PERIOD_CURRENT, 1, bars, highArray);
   CopyLow(_Symbol, PERIOD_CURRENT, 1, bars, lowArray);
   high = highArray[ArrayMaximum(highArray)];
   low = lowArray[ArrayMinimum(lowArray)];
}
// Calculate Average Daily Range (ADR)
double CalculateADR(int period)
{
   double sum = 0;
   for (int i = 1; i <= period; i++)
   {
      double dailyHigh = iHigh(_Symbol, PERIOD_D1, i);
       double dailyLow = iLow(_Symbol, PERIOD_D1, i);
       sum += dailyHigh - dailyLow;
    }
    return sum / period;
}
// Check if current time is within trading hours and minutes
bool IsTradingTime(int startHour, int startMinute, int endHour, int endMinute)
{
   MqlDateTime timeStruct;
   TimeToStruct(TimeCurrent(), timeStruct);
   int currentHour = timeStruct.hour;
   int currentMinute = timeStruct.min;
   int currentMinutes = currentHour * 60 + currentMinute;
   int startMinutes = startHour * 60 + startMinute;
   int endMinutes = endHour * 60 + endMinute;
    if (startMinutes < endMinutes) // Trading window within the same day
    {
       return currentMinutes >= startMinutes && currentMinutes < endMinutes;
    }
    else // Trading window spans midnight
    {
       return currentMinutes >= startMinutes || currentMinutes < endMinutes;
    }
}
// Place breakout buy stop and sell stop orders
void PlaceBreakoutOrders(double rangeHigh, double rangeLow)
{
   double pipFactor = 10.0 * _Point; // 1 pip = 10 points for 5-digit brokers
   double orderOffset = OrderOffsetPips * pipFactor;
   double slOffset = SLOffsetPips * pipFactor;
    double   buyStopPrice = rangeHigh + orderOffset;
    double   sellStopPrice = rangeLow - orderOffset;
    double   buySL = rangeLow - slOffset;
    double   sellSL = rangeHigh + slOffset;
    // Calculate take profit levels
    double buyTP = 0, sellTP = 0;
    if (TPType == 0) // Fixed pips
    {
       double tpDistance = TPValue * pipFactor;
       buyTP = buyStopPrice + tpDistance;
       sellTP = sellStopPrice - tpDistance;
    }
    else // Risk-reward ratio
    {
       double buySLDistance = buyStopPrice - buySL;
       double sellSLDistance = sellSL - sellStopPrice;
       buyTP = buyStopPrice + (buySLDistance * TPValue);
       sellTP = sellStopPrice - (sellSLDistance * TPValue);
    }
    // Determine lot size
    double lotSize;
    if (LotSizeType == 0)
    {
       double currentEquity = AccountInfoDouble(ACCOUNT_EQUITY);
       if (lotSizingInitialEquity > 0)
       {
          lotSize = LotSizeValue * (currentEquity / lotSizingInitialEquity);
       }
       else
       {
          lotSize = LotSizeValue;
       }
       // Normalize lot size
       double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
       double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
       if (lotStep > 0)
       {
          lotSize = MathRound(lotSize / lotStep) * lotStep;
       }
       lotSize = MathMax(lotSize, minLot);
    }
    else
    {
       lotSize = CalculateLotSize(buyStopPrice - buySL);
    }
    // Place pending orders
    trade.BuyStop(lotSize, buyStopPrice, _Symbol, buySL, buyTP);
    trade.SellStop(lotSize, sellStopPrice, _Symbol, sellSL, sellTP);
}
// Calculate lot size based on risk percentage
double CalculateLotSize(double slDistance)
{
   double riskPercent = LotSizeValue;
   double equity = AccountInfoDouble(ACCOUNT_EQUITY);
   double riskAmount = equity * (riskPercent / 100.0);
   double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE);
   double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE);
   double slPoints = slDistance / tickSize;
   double lotSize = riskAmount / (slPoints * tickValue);
   // Normalize lot size
   double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
   double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
   double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
   if (lotStep > 0)
   {
      lotSize = MathRound(lotSize / lotStep) * lotStep;
   }
   lotSize = MathMax(lotSize, minLot);
   lotSize = MathMin(lotSize, maxLot);
   return lotSize;
}
// Apply trailing stop to open positions
void ApplyTrailingStop()
{
   double trailingStop = TrailingStopPips * 10.0 * _Point;
   for (int i = PositionsTotal() - 1; i >= 0; i--)
   {
      if (PositionSelectByTicket(PositionGetTicket(i)) &&
PositionGetInteger(POSITION_MAGIC) == MagicNumber)
      {
         if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
         {
            double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
            double newSL = NormalizeDouble(bid - trailingStop, _Digits);
            if (newSL > PositionGetDouble(POSITION_SL) && bid -
PositionGetDouble(POSITION_PRICE_OPEN) > trailingStop)
            {
               trade.PositionModify(PositionGetTicket(i), newSL,
PositionGetDouble(POSITION_TP));
            }
         }
         else if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
         {
            double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
            double newSL = NormalizeDouble(ask + trailingStop, _Digits);
            if (newSL < PositionGetDouble(POSITION_SL) &&
PositionGetDouble(POSITION_PRICE_OPEN) - ask > trailingStop)
            {
               trade.PositionModify(PositionGetTicket(i), newSL,
PositionGetDouble(POSITION_TP));
            }
         }
      }
   }
}
// Check if there are open positions with our magic number
bool HasOpenPositions()
{
   for (int i = 0; i < PositionsTotal(); i++)
   {
      if (PositionGetInteger(POSITION_MAGIC) == MagicNumber) return true;
   }
   return false;
}
// Delete all pending orders with our magic number
void DeletePendingOrders()
{
   for (int i = OrdersTotal() - 1; i >= 0; i--)
   {
      if (OrderSelect(OrderGetTicket(i)) && OrderGetInteger(ORDER_MAGIC) ==
MagicNumber)
      {
         trade.OrderDelete(OrderGetTicket(i));
      }
   }
}