//+------------------------------------------------------------------+
//|                                        Internal OrderFlow EA.mq4 |
//| Enhanced with dynamic stops, trend filtering                     |
//| and trading time filter                                          |
//+------------------------------------------------------------------+
#property strict

// Input parameters
extern int    TickWindow         = 30;    // Number of ticks to analyze (increased)
extern int    Threshold          = 30;     // Higher imbalance threshold
extern double LotSize            = 0.1;
extern int    Slippage           = 3;
extern int    ATR_Period         = 14;     // Period for ATR calculation
extern double ATR_SL_Multiplier  = 2.0;    // SL multiplier for ATR
extern double ATR_TP_Multiplier  = 3.0;    // TP multiplier for ATR
extern bool   UseTrailingStop    = true;   // Enable trailing stop
extern int    TrailingStopPoints = 50;     // Trailing stop distance in points
extern bool   UseMATrendFilter   = false;   // Enable MA trend filter
extern int    MATrendPeriod      = 50;     // MA period for trend filter
extern int    MATrendTimeframe   = PERIOD_H1; // MA timeframe

// Trading Time Filter Parameters
extern bool   UseTradingTimeFilter = false; // Enable trading time filter
extern int    TradingStartHour    = 8;     // Start hour for trading (server time)
extern int    TradingStartMinute  = 0;     // Start minute for trading
extern int    TradingEndHour      = 16;    // End hour for trading (server time)
extern int    TradingEndMinute    = 0;     // End minute for trading

// Global variables
double prevPrice = 0.0;
int    tickBuffer[];
int    bufferIndex = 0;
int    rollingSum = 0;
bool   firstTick = true;
int    magicNumber = 12345;

//+------------------------------------------------------------------+
//| Check if any trade with our magic number is already open         |
//+------------------------------------------------------------------+
bool IsTradeOpen()
{
   for(int i = 0; i < OrdersTotal(); i++)
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         if(OrderSymbol() == Symbol() && OrderMagicNumber() == magicNumber)
            return true;
      }
   }
   return false;
}

//+------------------------------------------------------------------+
//| Trend Filter using Moving Average                               |
//+------------------------------------------------------------------+
bool IsTrendInDirection(int direction)
{
   if(!UseMATrendFilter) return true;
   
   double ma = iMA(Symbol(), MATrendTimeframe, MATrendPeriod, 0, MODE_SMA, PRICE_CLOSE, 0);
   
   if(direction == OP_BUY)
      return Bid > ma;
   else if(direction == OP_SELL)
      return Ask < ma;
   
   return false;
}

//+------------------------------------------------------------------+
//| Check if current time is within trading hours                   |
//+------------------------------------------------------------------+
bool IsTradingTime()
{
   if(!UseTradingTimeFilter) return true; // If filter is disabled, always allow trading

   datetime currentTime = TimeCurrent();
   int currentHour = TimeHour(currentTime);
   int currentMinute = TimeMinute(currentTime);

   // Convert trading hours to minutes since midnight for easier comparison
   int startTime = TradingStartHour * 60 + TradingStartMinute;
   int endTime = TradingEndHour * 60 + TradingEndMinute;
   int nowTime = currentHour * 60 + currentMinute;

   // Handle cases where trading period crosses midnight
   if(startTime < endTime)
   {
      return (nowTime >= startTime && nowTime < endTime);
   }
   else
   {
      return (nowTime >= startTime || nowTime < endTime);
   }
}

//+------------------------------------------------------------------+
//| Update trailing stops                                            |
//+------------------------------------------------------------------+
void UpdateTrailingStop()
{
   for(int i = OrdersTotal()-1; i >= 0; i--)
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
      {
         if(OrderSymbol() == Symbol() && OrderMagicNumber() == magicNumber)
         {
            int type = OrderType();
            double newStop = 0;
            
            if(type == OP_BUY)
            {
               newStop = Bid - TrailingStopPoints * Point;
               if(newStop > OrderStopLoss() || OrderStopLoss() == 0)
               {
                  if(newStop > OrderOpenPrice()) // Only trail in profit
                     OrderModify(OrderTicket(), OrderOpenPrice(), newStop, 
                                OrderTakeProfit(), 0, clrNONE);
               }
            }
            else if(type == OP_SELL)
            {
               newStop = Ask + TrailingStopPoints * Point;
               if(newStop < OrderStopLoss() || OrderStopLoss() == 0)
               {
                  if(newStop < OrderOpenPrice()) // Only trail in profit
                     OrderModify(OrderTicket(), OrderOpenPrice(), newStop, 
                                OrderTakeProfit(), 0, clrNONE);
               }
            }
         }
      }
   }
}

//+------------------------------------------------------------------+
//| Initialization function                                          |
//+------------------------------------------------------------------+
int init()
{
   ArrayResize(tickBuffer, TickWindow);
   ArrayInitialize(tickBuffer, 0);
   bufferIndex = 0;
   rollingSum = 0;
   firstTick = true;
   return(0);
}

//+------------------------------------------------------------------+
//| Main function                                                    |
//+------------------------------------------------------------------+
int start()
{
   if(firstTick)
   {
      prevPrice = Bid;
      firstTick = false;
      return(0);
   }

   // Check if trading is allowed at this time
   if(!IsTradingTime())
      return(0);

   // Update tick direction
   int tickDirection = 0;
   if(Bid > prevPrice) tickDirection = 1;
   else if(Bid < prevPrice) tickDirection = -1;
   prevPrice = Bid;

   // Update rolling window
   rollingSum -= tickBuffer[bufferIndex];
   tickBuffer[bufferIndex] = tickDirection;
   rollingSum += tickDirection;
   bufferIndex = (bufferIndex + 1) % TickWindow;

   // Check for trading signals
   if(!IsTradeOpen())
   {
      double atr = iATR(Symbol(), 0, ATR_Period, 0);
      
      // Buy signal
      if(rollingSum >= Threshold && IsTrendInDirection(OP_BUY))
      {
         double buyPrice = Ask;
         double sl = buyPrice - atr * ATR_SL_Multiplier;
         double tp = buyPrice + atr * ATR_TP_Multiplier;
         OrderSend(Symbol(), OP_BUY, LotSize, buyPrice, Slippage, 
                  NormalizeDouble(sl, Digits), NormalizeDouble(tp, Digits),
                  "Enhanced Order Flow EA - Buy", magicNumber, 0, clrGreen);
      }
      // Sell signal
      else if(rollingSum <= -Threshold && IsTrendInDirection(OP_SELL))
      {
         double sellPrice = Bid;
         double sl = sellPrice + atr * ATR_SL_Multiplier;
         double tp = sellPrice - atr * ATR_TP_Multiplier;
         OrderSend(Symbol(), OP_SELL, LotSize, sellPrice, Slippage,
                  NormalizeDouble(sl, Digits), NormalizeDouble(tp, Digits),
                  "Enhanced Order Flow EA - Sell", magicNumber, 0, clrRed);
      }
   }

   // Update trailing stops
   if(UseTrailingStop && OrdersTotal() > 0)
      UpdateTrailingStop();

   return(0);
}