//+------------------------------------------------------------------+
//|                                      RSIMidPointHijackStrategy.mqh |
//+------------------------------------------------------------------+

bool IsNewBar(string symbol)
{
   datetime time[];
   if(CopyTime(symbol, RM_InpTimeframe, 0, 1, time) > 0)
   {
      if(time[0] != rmData.lastBarTime)
      {
         rmData.lastBarTime = time[0];
         return true;
      }
   }
   return false;
}

bool IsWithinTradingHours(int startHour, int endHour)
{
   MqlDateTime currentTime;
   TimeToStruct(TimeCurrent(), currentTime);
   
   if(startHour <= endHour)
      return (currentTime.hour >= startHour && currentTime.hour < endHour);
   else
      return (currentTime.hour >= startHour || currentTime.hour < endHour);
}

bool HasPosition(string symbol, int magic)
{
   return PositionExistsByMagic(symbol, magic);
}

bool HasProfitablePosition(int excludeMagic)
{
   bool hasProfitable = false;
   for(int i = PositionsTotal() - 1; i >= 0; i--)
   {
      if(rmData.positionInfo.SelectByIndex(i))
      {
         if(rmData.positionInfo.Magic() != excludeMagic)
         {
            double profit = rmData.positionInfo.Profit();
            if(profit > RM_InpLockProfitThreshold * _Point)
            {
               hasProfitable = true;
               if(RM_InpCloseOppositeTrades)
               {
                  if((excludeMagic == RM_InpMagicNumberRSIFollow && rmData.positionInfo.Magic() == RM_InpMagicNumberRSIReverse) ||
                     (excludeMagic == RM_InpMagicNumberRSIReverse && rmData.positionInfo.Magic() == RM_InpMagicNumberRSIFollow) ||
                     (excludeMagic == RM_InpMagicNumberEMACross && (rmData.positionInfo.Magic() == RM_InpMagicNumberRSIReverse || rmData.positionInfo.Magic() == RM_InpMagicNumberRSIFollow)) ||
                     ((excludeMagic == RM_InpMagicNumberRSIFollow || excludeMagic == RM_InpMagicNumberRSIReverse) && rmData.positionInfo.Magic() == RM_InpMagicNumberEMACross))
                  {
                     ClosePosition(rmData.symbol, (int)rmData.positionInfo.Magic());
                  }
               }
            }
         }
      }
   }
   return hasProfitable;
}

bool IsRSIReverseInCooldown(string symbol)
{
   if(RM_InpRSIReverseCooldownBars <= 0)
      return false;
      
   if(!rmData.rsiReverseInCooldown)
      return false;
      
   datetime time[];
   if(CopyTime(symbol, RM_InpTimeframe, 0, 1, time) > 0)
   {
      datetime currentBarTime = time[0];
      datetime cooldownEndTime = rmData.rsiReverseLastCloseTime + RM_InpRSIReverseCooldownBars * PeriodSeconds(RM_InpTimeframe);
      
      if(currentBarTime >= cooldownEndTime)
      {
         rmData.rsiReverseInCooldown = false;
         return false;
      }
   }
   
   return true;
}

void CheckRSIFollowStrategy(string symbol)
{
   if(!IsWithinTradingHours(RM_InpRSIFollowStartHour, RM_InpRSIFollowEndHour))
   {
      if(RM_InpRSIFollowCloseOutsideHours)
      {
         if(HasPosition(symbol, RM_InpMagicNumberRSIFollow))
            ClosePosition(symbol, RM_InpMagicNumberRSIFollow);
      }
      return;
   }
   
   if(RM_InpEnableStrategyLock && HasProfitablePosition(RM_InpMagicNumberRSIFollow))
      return;
   
   if(rmData.lastBarRSI > RM_InpRSIOverbought)
      rmData.rsiOverbought = true;
   else if(rmData.lastBarRSI < RM_InpRSIOversold)
      rmData.rsiOversold = true;
   
   if(rmData.rsiOverbought && rmData.lastBarRSI < RM_InpRSIExitLevel)
   {
      if(!HasPosition(symbol, RM_InpMagicNumberRSIFollow))
      {
         rmData.trade.SetExpertMagicNumber(RM_InpMagicNumberRSIFollow);
         rmData.trade.Sell(g_RM_LotSize, symbol, 0, 0, 0, "RSI Follow");
      }
      rmData.rsiOverbought = false;
   }
   else if(rmData.rsiOversold && rmData.lastBarRSI > RM_InpRSIExitLevel)
   {
      if(!HasPosition(symbol, RM_InpMagicNumberRSIFollow))
      {
         rmData.trade.SetExpertMagicNumber(RM_InpMagicNumberRSIFollow);
         rmData.trade.Buy(g_RM_LotSize, symbol, 0, 0, 0, "RSI Follow");
      }
      rmData.rsiOversold = false;
   }
}

void CheckRSIReverseStrategy(string symbol)
{
   if(!IsWithinTradingHours(RM_InpRSIReverseStartHour, RM_InpRSIReverseEndHour))
   {
      if(RM_InpRSIReverseCloseOutsideHours)
      {
         if(HasPosition(symbol, RM_InpMagicNumberRSIReverse))
            ClosePosition(symbol, RM_InpMagicNumberRSIReverse);
      }
      return;
   }
   
   if(RM_InpEnableStrategyLock && HasProfitablePosition(RM_InpMagicNumberRSIReverse))
      return;
      
   if(IsRSIReverseInCooldown(symbol))
      return;
   
   if(rmData.lastBarRSIReverse > RM_InpRSIReverseOverbought)
      rmData.rsiReverseOverbought = true;
   else if(rmData.lastBarRSIReverse < RM_InpRSIReverseOversold)
      rmData.rsiReverseOversold = true;
   
   if(rmData.rsiReverseOverbought && rmData.lastBarRSIReverse < RM_InpRSIReverseCrossLevel)
   {
      if(!HasPosition(symbol, RM_InpMagicNumberRSIReverse))
      {
         rmData.trade.SetExpertMagicNumber(RM_InpMagicNumberRSIReverse);
         rmData.trade.Sell(g_RM_LotSize, symbol, 0, 0, 0, "RSI Reverse");
      }
      rmData.rsiReverseOverbought = false;
   }
   else if(rmData.rsiReverseOversold && rmData.lastBarRSIReverse > RM_InpRSIReverseCrossLevel)
   {
      if(!HasPosition(symbol, RM_InpMagicNumberRSIReverse))
      {
         rmData.trade.SetExpertMagicNumber(RM_InpMagicNumberRSIReverse);
         rmData.trade.Buy(g_RM_LotSize, symbol, 0, 0, 0, "RSI Reverse");
      }
      rmData.rsiReverseOversold = false;
   }
}

void CheckEMACrossStrategy(string symbol)
{
   if(!IsWithinTradingHours(RM_InpEMACrossStartHour, RM_InpEMACrossEndHour))
   {
      if(RM_InpEMACrossCloseOutsideHours)
      {
         if(HasPosition(symbol, RM_InpMagicNumberEMACross))
            ClosePosition(symbol, RM_InpMagicNumberEMACross);
      }
      return;
   }
   
   if(RM_InpEnableStrategyLock && HasProfitablePosition(RM_InpMagicNumberEMACross))
      return;
   
   if(rmData.lastBarEMAPrev < rmData.lastBarClosePrev && rmData.lastBarEMA > rmData.lastBarClose)
   {
      rmData.emaCrossBuySignal = true;
      rmData.emaCrossSellSignal = false;
      rmData.emaCrossSignalBar = 0;
   }
   else if(rmData.lastBarEMAPrev > rmData.lastBarClosePrev && rmData.lastBarEMA < rmData.lastBarClose)
   {
      rmData.emaCrossSellSignal = true;
      rmData.emaCrossBuySignal = false;
      rmData.emaCrossSignalBar = 0;
   }
   
   if(RM_InpUseEMADistanceEntry)
   {
      if(rmData.emaCrossBuySignal)
      {
         bool distanceConditionMet = true;
         double emaHistory[], closeHistory[];
         ArraySetAsSeries(emaHistory, true);
         ArraySetAsSeries(closeHistory, true);
         
         if(CopyBuffer(rmData.emaHandle, 0, 0, RM_InpEMADistancePeriod, emaHistory) > 0 &&
            CopyClose(symbol, RM_InpTimeframe, 0, RM_InpEMADistancePeriod, closeHistory) > 0)
         {
            double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
            for(int i = 0; i < RM_InpEMADistancePeriod; i++)
            {
               double distance = (closeHistory[i] - emaHistory[i]) / point;
               if(distance < RM_InpEMADistancePips)
               {
                  distanceConditionMet = false;
                  break;
               }
            }
            
            if(distanceConditionMet && !HasPosition(symbol, RM_InpMagicNumberEMACross))
            {
               rmData.trade.SetExpertMagicNumber(RM_InpMagicNumberEMACross);
               rmData.trade.Buy(g_RM_LotSize, symbol, 0, 0, 0, "EMA Cross Distance");
               rmData.emaCrossBuySignal = false;
            }
         }
      }
      else if(rmData.emaCrossSellSignal)
      {
         bool distanceConditionMet = true;
         double emaHistory[], closeHistory[];
         ArraySetAsSeries(emaHistory, true);
         ArraySetAsSeries(closeHistory, true);
         
         if(CopyBuffer(rmData.emaHandle, 0, 0, RM_InpEMADistancePeriod, emaHistory) > 0 &&
            CopyClose(symbol, RM_InpTimeframe, 0, RM_InpEMADistancePeriod, closeHistory) > 0)
         {
            double point = SymbolInfoDouble(symbol, SYMBOL_POINT);
            for(int i = 0; i < RM_InpEMADistancePeriod; i++)
            {
               double distance = (emaHistory[i] - closeHistory[i]) / point;
               if(distance < RM_InpEMADistancePips)
               {
                  distanceConditionMet = false;
                  break;
               }
            }
            
            if(distanceConditionMet && !HasPosition(symbol, RM_InpMagicNumberEMACross))
            {
               rmData.trade.SetExpertMagicNumber(RM_InpMagicNumberEMACross);
               rmData.trade.Sell(g_RM_LotSize, symbol, 0, 0, 0, "EMA Cross Distance");
               rmData.emaCrossSellSignal = false;
            }
         }
      }
   }
   else
   {
      if(rmData.lastBarEMAPrev < rmData.lastBarClosePrev && rmData.lastBarEMA > rmData.lastBarClose)
      {
         if(!HasPosition(symbol, RM_InpMagicNumberEMACross))
         {
            rmData.trade.SetExpertMagicNumber(RM_InpMagicNumberEMACross);
            rmData.trade.Buy(g_RM_LotSize, symbol, 0, 0, 0, "EMA Cross");
         }
      }
      else if(rmData.lastBarEMAPrev > rmData.lastBarClosePrev && rmData.lastBarEMA < rmData.lastBarClose)
      {
         if(!HasPosition(symbol, RM_InpMagicNumberEMACross))
         {
            rmData.trade.SetExpertMagicNumber(RM_InpMagicNumberEMACross);
            rmData.trade.Sell(g_RM_LotSize, symbol, 0, 0, 0, "EMA Cross");
         }
      }
   }
   
   if(rmData.emaCrossBuySignal || rmData.emaCrossSellSignal)
   {
      rmData.emaCrossSignalBar++;
      if(rmData.emaCrossSignalBar > RM_InpEMADistancePeriod * 2)
      {
         rmData.emaCrossBuySignal = false;
         rmData.emaCrossSellSignal = false;
      }
   }
}

void CheckExitConditions(string symbol)
{
   if(RM_InpEnableRSIFollow)
   {
      if(HasPosition(symbol, RM_InpMagicNumberRSIFollow))
      {
         if(PositionSelectByMagic(symbol, RM_InpMagicNumberRSIFollow))
         {
            ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
            if((posType == POSITION_TYPE_BUY && rmData.lastBarRSI < RM_InpRSIExitLevel) ||
               (posType == POSITION_TYPE_SELL && rmData.lastBarRSI > RM_InpRSIExitLevel))
            {
               ClosePosition(symbol, RM_InpMagicNumberRSIFollow);
            }
         }
      }
   }
   
   if(RM_InpEnableRSIReverse)
   {
      if(HasPosition(symbol, RM_InpMagicNumberRSIReverse))
      {
         if(PositionSelectByMagic(symbol, RM_InpMagicNumberRSIReverse))
         {
            ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
            if((posType == POSITION_TYPE_BUY && rmData.lastBarRSIReverse < RM_InpRSIReverseExitLevel) ||
               (posType == POSITION_TYPE_SELL && rmData.lastBarRSIReverse > RM_InpRSIReverseExitLevel))
            {
               ClosePosition(symbol, RM_InpMagicNumberRSIReverse);
            }
         }
      }
   }
   
   if(RM_InpEnableEMACross)
   {
      if(HasPosition(symbol, RM_InpMagicNumberEMACross))
      {
         if(PositionSelectByMagic(symbol, RM_InpMagicNumberEMACross))
         {
            ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
            if((posType == POSITION_TYPE_BUY && rmData.lastBarEMA > rmData.lastBarClose) ||
               (posType == POSITION_TYPE_SELL && rmData.lastBarEMA < rmData.lastBarClose))
            {
               ClosePosition(symbol, RM_InpMagicNumberEMACross);
            }
         }
      }
   }
}

void ClosePosition(string symbol, int magic)
{
   if(!PositionExistsByMagic(symbol, magic))
      return;
   
   ulong ticket = GetPositionTicketByMagic(symbol, magic);
   if(ticket == 0)
      return;
   
   if(magic == RM_InpMagicNumberRSIReverse)
   {
      if(PositionSelectByTicketSymbolAndMagic(ticket, symbol, magic))
      {
         datetime time[];
         if(CopyTime(symbol, RM_InpTimeframe, 0, 1, time) > 0)
         {
            rmData.rsiReverseLastCloseTime = time[0];
            double profit = PositionGetDouble(POSITION_PROFIT);
            if(!RM_InpRSIReverseCooldownOnLoss || profit < 0)
            {
               rmData.rsiReverseInCooldown = true;
            }
         }
      }
   }
   
   ClosePositionByMagic(rmData.trade, symbol, magic);
}

bool InitRSIMidPointHijack(string symbol)
{
   rmData.symbol = symbol;
   rmData.rsiOverbought = false;
   rmData.rsiOversold = false;
   rmData.rsiReverseOverbought = false;
   rmData.rsiReverseOversold = false;
   rmData.emaCrossBuySignal = false;
   rmData.emaCrossSellSignal = false;
   rmData.emaCrossSignalBar = 0;
   rmData.rsiReverseInCooldown = false;
   rmData.lastBarRSI = 0;
   rmData.lastBarRSIReverse = 0;
   rmData.lastBarEMA = 0;
   rmData.lastBarClose = 0;
   rmData.lastBarEMAPrev = 0;
   rmData.lastBarClosePrev = 0;
   
   // Check if symbol exists
   if(!SymbolSelect(symbol, true))
   {
      Print("RSIMidPointHijack: Symbol '", symbol, "' not available in Market Watch. Please add it to Market Watch or check symbol name.");
      return false;
   }
   
   Sleep(100); // Wait for symbol to be ready
   
   rmData.rsiHandle = iRSI(symbol, RM_InpTimeframe, RM_InpRSIPeriod, PRICE_CLOSE);
   rmData.rsiReverseHandle = iRSI(symbol, RM_InpTimeframe, RM_InpRSIReversePeriod, PRICE_CLOSE);
   rmData.emaHandle = iMA(symbol, RM_InpTimeframe, RM_InpEMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
   
   if(rmData.rsiHandle == INVALID_HANDLE || rmData.rsiReverseHandle == INVALID_HANDLE || rmData.emaHandle == INVALID_HANDLE)
   {
      Print("RSIMidPointHijack: Error creating indicators for '", symbol, "'");
      return false;
   }
   
   rmData.trade.SetExpertMagicNumber(RM_InpMagicNumberRSIFollow);
   rmData.trade.SetMarginMode();
   rmData.trade.SetTypeFillingBySymbol(symbol);
   rmData.trade.SetDeviationInPoints(10);
   
   datetime time[];
   if(CopyTime(symbol, RM_InpTimeframe, 0, 1, time) > 0)
      rmData.lastBarTime = time[0];
   
   rmData.isInitialized = true;
   Print("RSIMidPointHijack: Successfully initialized for symbol '", symbol, "'");
   return true;
}

void DeinitRSIMidPointHijack()
{
   if(rmData.rsiHandle != INVALID_HANDLE) IndicatorRelease(rmData.rsiHandle);
   if(rmData.rsiReverseHandle != INVALID_HANDLE) IndicatorRelease(rmData.rsiReverseHandle);
   if(rmData.emaHandle != INVALID_HANDLE) IndicatorRelease(rmData.emaHandle);
}

void ProcessRSIMidPointHijack(string symbol)
{
   // Skip if not initialized (symbol not available)
   if(!rmData.isInitialized)
      return;
      
   rmData.symbol = symbol; // Update symbol in case it changed
   if(!IsNewBar(rmData.symbol))
      return;
      
   double rsi[], rsiReverse[], ema[], close[];
   ArraySetAsSeries(rsi, true);
   ArraySetAsSeries(rsiReverse, true);
   ArraySetAsSeries(ema, true);
   ArraySetAsSeries(close, true);
   
   rmData.lastBarEMAPrev = rmData.lastBarEMA;
   rmData.lastBarClosePrev = rmData.lastBarClose;
   
   if(CopyBuffer(rmData.rsiHandle, 0, 0, 1, rsi) > 0)
      rmData.lastBarRSI = rsi[0];
      
   if(CopyBuffer(rmData.rsiReverseHandle, 0, 0, 1, rsiReverse) > 0)
      rmData.lastBarRSIReverse = rsiReverse[0];
      
   if(CopyBuffer(rmData.emaHandle, 0, 0, 1, ema) > 0)
      rmData.lastBarEMA = ema[0];
      
   if(CopyClose(rmData.symbol, RM_InpTimeframe, 0, 1, close) > 0)
      rmData.lastBarClose = close[0];
      
   if(RM_InpEnableRSIFollow)
      CheckRSIFollowStrategy(rmData.symbol);
   if(RM_InpEnableRSIReverse)
      CheckRSIReverseStrategy(rmData.symbol);
   if(RM_InpEnableEMACross)
      CheckEMACrossStrategy(rmData.symbol);
   
   CheckExitConditions(rmData.symbol);
}

//+------------------------------------------------------------------+
