//+------------------------------------------------------------------+
//|                                               Gadi_OBV_EA_v1_2.mq4 |
//|                                                            imaxi |
//|                                                                  |
//+------------------------------------------------------------------+

#define SIGNAL_NONE 0
#define SIGNAL_BUY   1
#define SIGNAL_SELL  2
#define SIGNAL_CLOSEBUY 3
#define SIGNAL_CLOSESELL 4

extern int MagicNumber = 0;
extern int StartHour = 0;
extern int StartMinute = 0;
extern int EndHour = 7;
extern int EndMinute = 0;
extern bool ExactVolume = False;
extern double PercentIncrease = 0.5;
extern bool EachTickMode = True;
extern double Lots = 1.0;
extern int Slippage = 3;
extern bool UseStopLoss = True;
extern int StopLoss = 300;
extern bool UseTakeProfit = True;
extern int TakeProfit = 200;
extern bool UseTrailingStop = True;
extern int TrailingStop = 45;

int Order;
int BarCount;
int Current;
bool TickCheck = False;
bool TradeShort, TradeLong;
double ChannelHigh, ChannelLow;

//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
  {
//----
   BarCount = Bars;

   if (EachTickMode) Current = 0; else Current = 1;   
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
  {
   return(0);
  }
//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
  {
//---- 

   //Print("Current Time ", TimeToStr(TimeCurrent(),TIME_DATE|TIME_SECONDS));

   if(canTrade(StartHour, EndHour) == false) return(0);

   Order = SIGNAL_NONE;
   int Total, Ticket;
   double StopLossLevel, TakeProfitLevel;

   if (EachTickMode && Bars != BarCount) TickCheck = False;
   Total = OrdersTotal();
   Order = SIGNAL_NONE;
    
   //Check position
   bool IsTrade = False;   
   bool IsInLongTrade   = False;
   bool IsInShortTrade  = False;
   
   for (int i = 0; i < Total; i ++) {
      OrderSelect(i, SELECT_BY_POS, MODE_TRADES);
      if(OrderType() <= OP_SELL &&  OrderSymbol() == Symbol()) {
         //IsTrade = True;
         if(OrderType() == OP_BUY) {
            IsInLongTrade  = True;
            TradeLong      = True;
            //Close
            //+------------------------------------------------------------------+
            //| Signal Begin(Exit Buy)                                           |
            //+------------------------------------------------------------------+   
                           int durationBuy = TimeCurrent() - OrderOpenTime();
                           //Order = SIGNAL_CLOSEBUY;
            //+------------------------------------------------------------------+
            //| Signal End(Exit Buy)                                             |
            //+------------------------------------------------------------------+

            if (Order == SIGNAL_CLOSEBUY && ((EachTickMode && !TickCheck) || (!EachTickMode && (Bars != BarCount)))) {
               OrderClose(OrderTicket(), OrderLots(), Bid, Slippage, MediumSeaGreen);
               if (!EachTickMode) BarCount = Bars;
               IsTrade = False;
               IsInLongTrade = False; 
               TradeShort = True;               
               continue;
            }
            //Trailing stop
            if(UseTrailingStop && TrailingStop > 0) {                 
               if(Bid - OrderOpenPrice() > Point * TrailingStop) {
                  if(OrderStopLoss() < Bid - Point * TrailingStop) {
                     OrderModify(OrderTicket(), OrderOpenPrice(), Bid - Point * TrailingStop, OrderTakeProfit(), 0, MediumSeaGreen);
                     if (!EachTickMode) BarCount = Bars;
                     continue;
                  }
               }
            }
         } else {
            IsInShortTrade = True;
            TradeShort     = True;
            //Close
            //+------------------------------------------------------------------+
            //| Signal Begin(Exit Sell)                                          |
            //+------------------------------------------------------------------+
                           int durationSell = TimeCurrent() - OrderOpenTime();
                           //Order = SIGNAL_CLOSEBUY;                          
            //+------------------------------------------------------------------+
            //| Signal End(Exit Sell)                                            |
            //+------------------------------------------------------------------+

            if (Order == SIGNAL_CLOSESELL && ((EachTickMode && !TickCheck) || (!EachTickMode && (Bars != BarCount)))) {
               OrderClose(OrderTicket(), OrderLots(), Ask, Slippage, DarkOrange);
               if (!EachTickMode) BarCount = Bars;
               IsTrade = False;
               IsInShortTrade = False;
               continue;
            }
            //Trailing stop
            if(UseTrailingStop && TrailingStop > 0) {                 
               if((OrderOpenPrice() - Ask) > (Point * TrailingStop)) {
                  if((OrderStopLoss() > (Ask + Point * TrailingStop)) || (OrderStopLoss() == 0)) {
                     OrderModify(OrderTicket(), OrderOpenPrice(), Ask + Point * TrailingStop, OrderTakeProfit(), 0, DarkOrange);
                     if (!EachTickMode) BarCount = Bars;
                     continue;
                  }
               }
            }
         }
      }
   }
   
   //+------------------------------------------------------------------+
   //| Signal Begin(Entry)                                              |
   //+------------------------------------------------------------------+
            channelZone();
   //+------------------------------------------------------------------+
   //| Signal End                                                       |
   //+------------------------------------------------------------------+

   //Buy
   if (Order == SIGNAL_BUY && ((EachTickMode && !TickCheck) || (!EachTickMode && (Bars != BarCount)))) {
      if(!IsInLongTrade) {
         //Check free margin
         if (AccountFreeMargin() < (100 * Lots)) {
            Print("We have no money. Free Margin = ", AccountFreeMargin());
            return(0);
         }

         if (UseStopLoss) StopLossLevel = Ask - StopLoss * Point; else StopLossLevel = 0.0;
         if (UseTakeProfit) TakeProfitLevel = Ask + TakeProfit * Point; else TakeProfitLevel = 0.0;

         Ticket = OrderSend(Symbol(), OP_BUY, Lots, Ask, Slippage, StopLossLevel, TakeProfitLevel, "Buy(#" + MagicNumber + ")", MagicNumber, 0, DodgerBlue);
         if(Ticket > 0) {
            if (OrderSelect(Ticket, SELECT_BY_TICKET, MODE_TRADES)) {
				Print("BUY order opened : ", OrderOpenPrice());
				TradeLong = True;
			} else {
				Print("Error opening BUY order : ", GetLastError());
			}
         }
         if (EachTickMode) TickCheck = True;
         if (!EachTickMode) BarCount = Bars;
         return(0);
      }
   }   
      
   //Sell
   if (Order == SIGNAL_SELL && ((EachTickMode && !TickCheck) || (!EachTickMode && (Bars != BarCount)))) {
      if(!IsInShortTrade) {
         //Check free margin
         if (AccountFreeMargin() < (100 * Lots)) {
            Print("We have no money. Free Margin = ", AccountFreeMargin());
            return(0);
         }

         if (UseStopLoss) StopLossLevel = Bid + StopLoss * Point; else StopLossLevel = 0.0;
         if (UseTakeProfit) TakeProfitLevel = Bid - TakeProfit * Point; else TakeProfitLevel = 0.0;

         Ticket = OrderSend(Symbol(), OP_SELL, Lots, Bid, Slippage, StopLossLevel, TakeProfitLevel, "Sell(#" + MagicNumber + ")", MagicNumber, 0, DeepPink);
         if(Ticket > 0) {
            if (OrderSelect(Ticket, SELECT_BY_TICKET, MODE_TRADES)) {
				Print("SELL order opened : ", OrderOpenPrice());
				TradeShort = True;
			} else {
				Print("Error opening SELL order : ", GetLastError());
			}
         }
         if (EachTickMode) TickCheck = True;
         if (!EachTickMode) BarCount = Bars;
         return(0);
      }
   }

   if (!EachTickMode) BarCount = Bars;   
//----
   return(0);
  }
//+------------------------------------------------------------------+

bool canTrade(int start, int end) {
   if(start <= Hour() && Hour() < end) {
      TradeLong = False;
      TradeShort = False;
      return(False);
   }
   return(True);
}

void channelZone() {
   int start = 0;
   int end = 0;

   for (int i = 0; i <= 1440; i++) {
      if (TimeHour(Time[i]) == StartHour && TimeMinute(Time[i]) == StartMinute) start = i;
      if (TimeHour(Time[i]) == EndHour && TimeMinute(Time[i]) == EndMinute) end = i;
      if (start > 0) break;
   }
   
   if (end > 0) {
   
      double NumArray[1440];  
      
      for (int ii = end+1; ii <= start; ii++) {
         NumArray[ii] = iCustom(Symbol(), Period(), "Gadi_OBV_v2.2", 0, ii); 
      }
       
      ChannelHigh = ChannelHighest(end, start, NumArray);
      ChannelLow  = ChannelLowest(end, start, NumArray);
      
      if(ExactVolume != True) {
         ChannelHigh = ChannelHigh + MathAbs(ChannelHigh * PercentIncrease / 100.0);
         ChannelLow  = ChannelLow - MathAbs(ChannelLow * PercentIncrease / 100.0);      
      }
      
      Print("ChannelHigh ", ChannelHigh); 
      Print("ChannelLow  ", ChannelLow);      
      
      double gadiChannelVolume = iCustom(Symbol(), Period(), "Gadi_OBV_v2.2", 0, 0);
      
      bool isPositiveVolume      = gadiChannelVolume > 0;
      bool isChannelHighNegative = ChannelHigh  < 0;
      bool isChannelLowNegative  = ChannelLow   < 0;
      
      Print("isPositiveVolume ",       isPositiveVolume);
      Print("isChannelHighNegative ",  isChannelHighNegative);
      Print("isChannelLowNegative ",   isChannelLowNegative);
   
      if(TradeLong != True) {
         if(isPositiveVolume) {
            if(gadiChannelVolume > ChannelHigh) {
               if(!isChannelHighNegative) {
                  Order = SIGNAL_BUY;
               }
            }         
         }
         else {
            if(MathAbs(gadiChannelVolume) <  MathAbs(ChannelHigh)) {
               if(isChannelHighNegative && isPositiveVolume != True) {
                  Order = SIGNAL_BUY; 
               }
            }                     
         } 
      }
      
      if(TradeShort != True) { 
         if(isPositiveVolume) {
            if(gadiChannelVolume < ChannelLow) {
               if(!isChannelLowNegative) {
                  Order = SIGNAL_SELL;  
               }
            }         
         }
         else {
            if(MathAbs(gadiChannelVolume) > MathAbs(ChannelLow)) {
               Order = SIGNAL_SELL;  
            }          
         }
      }  
   }         
}

double ChannelHighest(int end, int start, double inputData[]) {
   double highest = -9999999999.0;
   for(int i = end+1; i <= start; i++) {
      if(inputData[i] > highest) highest = inputData[i];
   }
   return(highest);
}

double ChannelLowest(int end, int start, double inputData[]) {
   double lowest = 9999999999.0;
   for(int i = end+1; i <= start; i++) {
      if(inputData[i] < lowest) lowest = inputData[i];
   }
   return(lowest);
}