//+------------------------------------------------------------------+
//|     XAUUSD SMA Crossover EA with TP, SL, Trailing Stop, Volume  |
//+------------------------------------------------------------------+
#property strict
#include <Trade\Trade.mqh>
CTrade trade;

input int fastPeriod = 2;
input int slowPeriod = 5;
input double lotSize = 0.01;
input double slippage = 0.03;
input double maxLossUSD = 10.0;
input double takeProfitUSD = 10.0;
input bool debugLogs = true;

int fastHandle, slowHandle;
double fastBuffer[], slowBuffer[];
long volume[];

double PointSize, TickValue;
int DigitsCount;
double SL_Points, TP_Points;

//+------------------------------------------------------------------+
int OnInit()
  {
   fastHandle = iMA(_Symbol, _Period, fastPeriod, 0, MODE_SMA, PRICE_CLOSE);
   slowHandle = iMA(_Symbol, _Period, slowPeriod, 0, MODE_SMA, PRICE_OPEN);

   if(fastHandle == INVALID_HANDLE || slowHandle == INVALID_HANDLE)
     {
      Print("Indicator creation failed.");
      return INIT_FAILED;
     }

   ArraySetAsSeries(fastBuffer, true);
   ArraySetAsSeries(slowBuffer, true);
   ArraySetAsSeries(volume, true);

   SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE, TickValue);
   SymbolInfoDouble(_Symbol, SYMBOL_POINT, PointSize);
   DigitsCount = (int)SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);

   SL_Points = NormalizeDouble((maxLossUSD / (TickValue * lotSize)) / PointSize, 0);
   TP_Points = NormalizeDouble((takeProfitUSD / (TickValue * lotSize)) / PointSize, 0);

   return INIT_SUCCEEDED;
  }

//+------------------------------------------------------------------+
void OnTick()
  {
   if(Bars(_Symbol, _Period) < 25) return;

   // Apply trailing stop if there's a position
   if(PositionSelect(_Symbol))
      ManageTrailingStop();

   if(CopyBuffer(fastHandle, 0, 0, 3, fastBuffer) < 3 ||
      CopyBuffer(slowHandle, 0, 0, 3, slowBuffer) < 3 ||
      CopyTickVolume(_Symbol, 0, 0, 25, volume) < 25)
     {
      Print("Failed to copy data.");
      return;
     }

   // Volume filter check
   double avgVol = 0;
   for(int i = 3; i < 23; i++) avgVol += volume[i];
   avgVol /= 20;

   if(volume[1] <= avgVol || volume[2] <= avgVol)
     {
      if(debugLogs)
         Print("Low volume — no trade. V1:", volume[1], " V2:", volume[2], " AVG:", avgVol);
      return;
     }

   // Crossover
   bool bullish = fastBuffer[1] < slowBuffer[1] && fastBuffer[0] > slowBuffer[0];
   bool bearish = fastBuffer[1] > slowBuffer[1] && fastBuffer[0] < slowBuffer[0];

   bool hasPosition = PositionSelect(_Symbol);
   long posType = hasPosition ? PositionGetInteger(POSITION_TYPE) : -1;

   double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);

   // Exit on reverse crossover
   if(hasPosition)
     {
      if((posType == POSITION_TYPE_BUY && bearish) ||
         (posType == POSITION_TYPE_SELL && bullish))
        {
         trade.PositionClose(_Symbol);
         Print("Closed due to reverse crossover.");
         return;
        }
     }

   // Entry
   if(!hasPosition)
     {
      if(bullish)
        {
         double sl = NormalizeDouble(bid - SL_Points * PointSize, DigitsCount);
         double tp = NormalizeDouble(bid + TP_Points * PointSize, DigitsCount);
         if(trade.Buy(lotSize, _Symbol, ask, slippage, sl, tp))
            Print("BUY @ ", ask, " SL: ", sl, " TP: ", tp);
         else
            Print("BUY failed: ", trade.ResultRetcodeDescription());
        }
      else if(bearish)
        {
         double sl = NormalizeDouble(ask + SL_Points * PointSize, DigitsCount);
         double tp = NormalizeDouble(ask - TP_Points * PointSize, DigitsCount);
         if(trade.Sell(lotSize, _Symbol, bid, slippage, sl, tp))
            Print("SELL @ ", bid, " SL: ", sl, " TP: ", tp);
         else
            Print("SELL failed: ", trade.ResultRetcodeDescription());
        }
     }
  }

//+------------------------------------------------------------------+
//| Trailing Stop Management                                         |
//+------------------------------------------------------------------+
void ManageTrailingStop()
  {
   double currentPrice = 0.0;
   long type = PositionGetInteger(POSITION_TYPE);
   double entry = PositionGetDouble(POSITION_PRICE_OPEN);
   double sl = PositionGetDouble(POSITION_SL);
   double tp = PositionGetDouble(POSITION_TP);

   if(type == POSITION_TYPE_BUY)
     {
      currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
      double newSL = NormalizeDouble(currentPrice - SL_Points * PointSize, DigitsCount);
      if(newSL > sl)
         trade.PositionModify(_Symbol, newSL, tp);
     }
   else if(type == POSITION_TYPE_SELL)
     {
      currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
      double newSL = NormalizeDouble(currentPrice + SL_Points * PointSize, DigitsCount);
      if(newSL < sl || sl == 0.0)
         trade.PositionModify(_Symbol, newSL, tp);
     }
  }

//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   if(fastHandle != INVALID_HANDLE) IndicatorRelease(fastHandle);
   if(slowHandle != INVALID_HANDLE) IndicatorRelease(slowHandle);
  }
//+------------------------------------------------------------------+