//+------------------------------------------------------------------+
//|                                                 ZERO_V2.mq4      |
//|   Example EA with ATR-based SL/TP, trailing stops (from initial    |
//|   stop), exit filters, and selectable trade direction              |
//+------------------------------------------------------------------+
#property strict

//----- Trade and ATR parameters
extern double Lots = 0.1;
extern int Slippage = 3;
extern int MagicNumber = 12345;
extern int ATRPeriod = 14;
extern double StopLossATRPercent = 10.0;    // e.g. 10% of ATR (if ATR=200 then 20 points)
extern double TakeProfitATRPercent = 20.0;  // e.g. 20% of ATR (if ATR=200 then 40 points)
extern double TrailingATRPercent = 60.0;    // e.g. 60% of ATR profit threshold (if ATR=200 then 120 points)

//----- New parameter: TrailBy multiplier
extern double TrailBy = 1.0; // 1 = point-for-point trailing; 3 = 3 points for every 1 point profit beyond threshold

//----- Volatility filter parameters (ATR trade filter)
extern int ATRTradeFilter = 1;    // 1 = true, 2 = false
extern int ATRTradePeriod = 14;
extern double ATRTradeMaxLevel = 250.0;
extern double ATRTradeMinLevel = 50.0;

//----- Indicator inputs (for custom indicator "Zero Lag Recalc")
extern string IndicatorName = "Zero Lag Recalc";
extern int IndicatorLength = 70;
extern double IndicatorMult = 1.2;
extern int IndicatorArrowSize = 2;
extern int IndicatorEntrySize = 1;
extern int IndicatorBandShiftPips = 5;
extern double IndicatorBandFactor = 1.5;

//----- Indicator buffer indices
// Entry signals: Buffer 5 (long) and Buffer 6 (short)
// Exit signals (inverse): For BUY exit use buffer 4, for SELL exit use buffer 3
int BufferEntryLong  = 5;
int BufferEntryShort = 6;
int BufferExitLong   = 4;  // For BUY orders, inverse signal from buffer 4
int BufferExitShort  = 3;  // For SELL orders, inverse signal from buffer 3

//----- Exit filter parameters
extern int ExitOnOppositeSignal = 1;        // Immediate exit on inverse signal (1=true, 2=false)
extern int ExitOnOppositeSignalBreakeven = 1; // Wait for break even on inverse signal (1=true, 2=false)

//----- New Trade Mode parameter
// 1 = Buy Only, 2 = Sell Only, 3 = Both Buy/Sell
extern int TradeMode = 3;

//----- Global variables for trailing and inverse signal handling
double gInitialStop = EMPTY_VALUE;          // Stores the initial SL of the open trade
bool gInverseSignalTriggered = false;       // Flag for inverse signal for breakeven exit

//+------------------------------------------------------------------+
//| Count open orders for the current symbol and magic number        |
//+------------------------------------------------------------------+
int CountOpenOrders()
{
   int count = 0;
   for (int i = 0; i < OrdersTotal(); i++)
   {
      if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         if(OrderMagicNumber() == MagicNumber && OrderSymbol() == Symbol())
            count++;
      }
   }
   return count;
}

//+------------------------------------------------------------------+
//| Open a trade based on order type (OP_BUY or OP_SELL)             |
//+------------------------------------------------------------------+
void OpenTrade(int opType)
{
   double atr = iATR(Symbol(), 0, ATRPeriod, 1);
   if(atr <= 0) return;
   
   double entryPrice, SL, TP;
   
   if(opType == OP_BUY)
   {
      entryPrice = Ask;
      SL = entryPrice - (StopLossATRPercent / 100.0 * atr);
      TP = entryPrice + (TakeProfitATRPercent / 100.0 * atr);
      int ticket = OrderSend(Symbol(), OP_BUY, Lots, entryPrice, Slippage, SL, TP, "Long Order", MagicNumber, 0, clrBlue);
      if(ticket >= 0)
      {
         Print("Buy order opened successfully. Ticket:", ticket);
         gInitialStop = SL; // Store initial stop for trailing calculations
         gInverseSignalTriggered = false;
      }
      else
         Print("Buy OrderSend failed with error #", GetLastError());
   }
   else if(opType == OP_SELL)
   {
      entryPrice = Bid;
      SL = entryPrice + (StopLossATRPercent / 100.0 * atr);
      TP = entryPrice - (TakeProfitATRPercent / 100.0 * atr);
      int ticket = OrderSend(Symbol(), OP_SELL, Lots, entryPrice, Slippage, SL, TP, "Sell Order", MagicNumber, 0, clrRed);
      if(ticket >= 0)
      {
         Print("Sell order opened successfully. Ticket:", ticket);
         gInitialStop = SL; // Store initial stop for trailing calculations
         gInverseSignalTriggered = false;
      }
      else
         Print("Sell OrderSend failed with error #", GetLastError());
   }
}

//+------------------------------------------------------------------+
//| Improved trailing stop logic using the initial stop as baseline    |
//| and a "TrailBy" multiplier                                         |
//+------------------------------------------------------------------+
void TrailStop()
{
   double currentATR = iATR(Symbol(), 0, ATRPeriod, 1);
   if(currentATR <= 0) return;
   
   // Define trailing threshold as a price value (e.g., 60% of ATR)
   double trailingThreshold = (TrailingATRPercent / 100.0 * currentATR);
   
   for (int i = OrdersTotal()-1; i >= 0; i--)
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         if(OrderMagicNumber() != MagicNumber || OrderSymbol() != Symbol())
            continue;
         
         // For BUY orders:
         if(OrderType() == OP_BUY)
         {
            double profit = Bid - OrderOpenPrice();
            if(profit > trailingThreshold)
            {
               double extra = profit - trailingThreshold;
               double newStop = gInitialStop + (extra * TrailBy); // trail from the initial SL
               if(newStop > OrderStopLoss() && newStop < OrderTakeProfit())
               {
                  if(OrderModify(OrderTicket(), OrderOpenPrice(), newStop, OrderTakeProfit(), 0, clrBlue))
                     Print("Modified Buy order trailing stop for ticket:", OrderTicket());
                  else
                     Print("Error modifying Buy order trailing stop:", GetLastError());
               }
            }
         }
         // For SELL orders:
         else if(OrderType() == OP_SELL)
         {
            double profit = OrderOpenPrice() - Ask;
            if(profit > trailingThreshold)
            {
               double extra = profit - trailingThreshold;
               double newStop = gInitialStop - (extra * TrailBy); // trail from the initial SL for SELL orders
               if(newStop < OrderStopLoss() && newStop > OrderTakeProfit())
               {
                  if(OrderModify(OrderTicket(), OrderOpenPrice(), newStop, OrderTakeProfit(), 0, clrRed))
                     Print("Modified Sell order trailing stop for ticket:", OrderTicket());
                  else
                     Print("Error modifying Sell order trailing stop:", GetLastError());
               }
            }
         }
      }
   }
}

//+------------------------------------------------------------------+
//| Check for exit conditions based on inverse signals               |
//+------------------------------------------------------------------+
void CheckExitFilters()
{
   for (int i = OrdersTotal()-1; i >= 0; i--)
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         if(OrderMagicNumber() != MagicNumber || OrderSymbol() != Symbol())
            continue;
         
         // For BUY orders: Use BufferExitLong (buffer 4) as the inverse signal.
         if(OrderType() == OP_BUY)
         {
            double inverseSignal = iCustom(NULL, 0, IndicatorName, IndicatorLength, IndicatorMult,
                                           IndicatorArrowSize, IndicatorEntrySize, IndicatorBandShiftPips,
                                           IndicatorBandFactor, BufferExitLong, 1);
            if(inverseSignal != EMPTY_VALUE)
            {
               if(ExitOnOppositeSignal == 1)
               {
                  if(OrderClose(OrderTicket(), OrderLots(), Bid, Slippage, clrYellow))
                     Print("Buy order closed immediately due to inverse signal.");
                  else
                     Print("Error closing Buy order immediately:", GetLastError());
               }
               else if(ExitOnOppositeSignalBreakeven == 1)
               {
                  if(!gInverseSignalTriggered)
                  {
                     gInverseSignalTriggered = true;
                     Print("Inverse signal triggered for Buy order, waiting for breakeven exit.");
                  }
               }
            }
            if(gInverseSignalTriggered && Bid >= OrderOpenPrice())
            {
               if(OrderClose(OrderTicket(), OrderLots(), Bid, Slippage, clrYellow))
               {
                  Print("Buy order closed at breakeven due to inverse signal.");
                  gInverseSignalTriggered = false;
               }
               else
                  Print("Error closing Buy order at breakeven:", GetLastError());
            }
         }
         // For SELL orders: Use BufferExitShort (buffer 3) as the inverse signal.
         else if(OrderType() == OP_SELL)
         {
            double inverseSignal = iCustom(NULL, 0, IndicatorName, IndicatorLength, IndicatorMult,
                                           IndicatorArrowSize, IndicatorEntrySize, IndicatorBandShiftPips,
                                           IndicatorBandFactor, BufferExitShort, 1);
            if(inverseSignal != EMPTY_VALUE)
            {
               if(ExitOnOppositeSignal == 1)
               {
                  if(OrderClose(OrderTicket(), OrderLots(), Ask, Slippage, clrYellow))
                     Print("Sell order closed immediately due to inverse signal.");
                  else
                     Print("Error closing Sell order immediately:", GetLastError());
               }
               else if(ExitOnOppositeSignalBreakeven == 1)
               {
                  if(!gInverseSignalTriggered)
                  {
                     gInverseSignalTriggered = true;
                     Print("Inverse signal triggered for Sell order, waiting for breakeven exit.");
                  }
               }
            }
            if(gInverseSignalTriggered && Ask <= OrderOpenPrice())
            {
               if(OrderClose(OrderTicket(), OrderLots(), Ask, Slippage, clrYellow))
               {
                  Print("Sell order closed at breakeven due to inverse signal.");
                  gInverseSignalTriggered = false;
               }
               else
                  Print("Error closing Sell order at breakeven:", GetLastError());
            }
         }
      }
   }
}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
   // Ensure there are enough bars on the chart
   if(Bars < 2) return;
   
   double atr = iATR(Symbol(), 0, ATRPeriod, 1);
   if(atr <= 0) return;
   
   // ENTRY LOGIC: Only trade if no trade is already open.
   if(CountOpenOrders() == 0)
   {
      // Volatility filter check (if enabled)
      if(ATRTradeFilter == 1)
      {
         double atrTradeValue = iATR(Symbol(), 0, ATRTradePeriod, 1);
         if(atrTradeValue < ATRTradeMinLevel || atrTradeValue > ATRTradeMaxLevel)
         {
            Print("No entry: ATR filter not satisfied. ATR =", atrTradeValue);
            return;
         }
      }
      
      // Retrieve entry signals from the indicator (last closed bar, shift=1)
      double signalLong = iCustom(NULL, 0, IndicatorName, IndicatorLength, IndicatorMult, 
                                  IndicatorArrowSize, IndicatorEntrySize, IndicatorBandShiftPips, 
                                  IndicatorBandFactor, BufferEntryLong, 1);
      double signalShort = iCustom(NULL, 0, IndicatorName, IndicatorLength, IndicatorMult, 
                                   IndicatorArrowSize, IndicatorEntrySize, IndicatorBandShiftPips, 
                                   IndicatorBandFactor, BufferEntryShort, 1);
      
      // Use the TradeMode input parameter to determine which signals to consider:
      if(TradeMode == 1 || TradeMode == 3) // Buy Only or Both
      {
         if(signalLong != EMPTY_VALUE)
            OpenTrade(OP_BUY);
      }
      if(TradeMode == 2 || TradeMode == 3) // Sell Only or Both
      {
         if(signalShort != EMPTY_VALUE)
            OpenTrade(OP_SELL);
      }
   }
   
   // Apply the improved trailing stop logic.
   TrailStop();
   
   // Check for inverse signal exit conditions.
   CheckExitFilters();
}
//+------------------------------------------------------------------+
