//+------------------------------------------------------------------+
//|                                                 CBBP_EA_v3-0.mq4 |
//|                                                         Zen Leow |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "Zen Leow"
#property link      ""

#include <stdlib.mqh>
#include <stderror.mqh>
#define PRIMARY_ORDER    1
#define SECONDARY_ORDER  2

extern int       EA_MAGIC_NUM = 3947947;
extern bool      IsECN = true;
extern bool      CheckHourOfAttach = true;
extern string    Session1 = "London Session";
extern int       SessionOpenHour1 = 8;
extern string    Session2 = "New York Session";
extern int       SessionOpenHour2 = 13;
extern int       GraceMinutes = 5;
extern bool      Show_Comments = true;
extern double    UserDefinedSpread = 0;

extern int       Slippage = 3;
extern double    Pip_Distance = 2;
extern double    TakeProfit = 140;
extern double    StopLoss = 5;
extern bool      UseJumpingStop = false;
extern int       TrailingStop = 0;
extern bool      Add_Spread_To_StopLoss = false;
extern bool      Use_Spread_Filtering = true;
extern double    Spread_Filter = 1.0;

extern bool      MoneyManagement = true;
extern double    RiskPercent = 0.25;
extern bool      UseEquity=false;
extern bool      Use_BE=true;
extern double    BreakEven_Pips=5.0;
extern double    CommissionPips = 1.0;
extern double    FixedLots = 0.1;
extern double    MaxLots = 15.0;
extern double    MinLots = 0.01;
extern int       LotsDecimalAllowed = 2;

string msg = "";
double CustomSpread = 0;
int PipFactor = 1;
bool StartupStatusOK = true;
int the_StopLoss = 0;
bool TradeTheSession = true;
bool ProblemLogged = false;
int todayOfYear = 0;
bool SessionIsOn = false;
double theSessionOpenPrice;
string latestSession;
int currentSessionHour;
bool SessionOpenPriceWritten = false;

//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
{
//----
   int currentHour = TimeHour(TimeCurrent());
   if ((currentHour == SessionOpenHour1 || currentHour == SessionOpenHour2) && CheckHourOfAttach)
   {
      Alert ("IMPT: You should not attach this EA during "+Session1+" Open hour or the "+Session2+" Open hour");
      StartupStatusOK = false;
   }
   if (Period() > PERIOD_H1)
   {
      Alert("This EA can only be attached to Charts with timeframe LESS THAN 1 hour");
      StartupStatusOK = false;
   }
   if (MinLots < MarketInfo(Symbol(),MODE_MINLOT))
   {
      Alert("Invalid MinLots: "+MinLots+" | Try: "+MarketInfo(Symbol(),MODE_MINLOT));
      StartupStatusOK = false;
   }
   if (MaxLots > MarketInfo(Symbol(),MODE_MAXLOT))
   {
      Alert("Invalid MaxLots: "+MaxLots+" | Try: "+MarketInfo(Symbol(),MODE_MAXLOT));
      StartupStatusOK = false;
   }
   if (SessionOpenHour1 < 0 || SessionOpenHour1 > 23)
   {
      Alert("Invalid Opening Hour given for "+Session1+": "+SessionOpenHour1);
      StartupStatusOK = false;
   }
   if (SessionOpenHour2 < 0 || SessionOpenHour2 > 23)
   {
      Alert("Invalid Opening Hour given for "+Session2+": "+SessionOpenHour2);
      StartupStatusOK = false;
   }
   if (MoneyManagement && (RiskPercent <= 0 || RiskPercent > 100))
   {
      Alert("Invalid RiskPercent given: "+RiskPercent+"%");
      StartupStatusOK = false;
   }
   if (StartupStatusOK)
   {
      Alert("CBBP EA loaded on "+Symbol()+" with valid inputs");
   }
   WriteToLogFile("Start Of CBBP EA");
   
   GetSpread();
   
   todayOfYear = DayOfYear();
   // Cater for fractional pips
   if (Digits == 3 || Digits == 5)
   {
      PipFactor = 10;
   }
   Slippage = Slippage * PipFactor;
   if (Show_Comments)
   {
      WriteComment();
   }
//----
   return(0);
}

//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
{
//----
   
//----
   return(0);
}


//+------------------------------------------------------------------+
//| Trade Management logic functions                                 |
//+------------------------------------------------------------------+

bool TradeNotPlacedYet()
{
   int total = OrdersTotal();
   if (total > 0)
   {
      for(int cnt=0;cnt<total;cnt++)
      {
         if(OrderSelect(cnt,SELECT_BY_POS))
         {
            if(OrderSymbol()==Symbol() && OrderMagicNumber() == EA_MAGIC_NUM)
            {
               SessionIsOn = false;
               return (false);
            }
         }
      }
   }
   // in case trade has already opened and closed for this session
   int histotal = OrdersHistoryTotal();
   if (histotal > 0)
   {
      for(cnt=0;cnt<histotal;cnt++)
      {
         if(OrderSelect(cnt,SELECT_BY_POS,MODE_HISTORY))
         {
            if(OrderSymbol()==Symbol() && OrderMagicNumber() == EA_MAGIC_NUM)
            {
               datetime LatestSessionStart = iTime(NULL,PERIOD_H1,0);
               datetime LatestSessionGrace = LatestSessionStart + (GraceMinutes * 60);
               datetime CurrentOrderOpenTime = OrderOpenTime();
               if (CurrentOrderOpenTime >= LatestSessionStart && CurrentOrderOpenTime <= LatestSessionGrace)
               {
                  SessionIsOn = false;
                  return (false);
               }
            }
         }
      }
   }
   return (true);
}

bool Should_Buy(int SessionOpenIndex)
{
   if (SessionOpenIndex == -1)
   {
      return (false);
   }
   theSessionOpenPrice = Open[SessionOpenIndex];
   double theSessionCurrentPrice = Close[0];
   if (theSessionCurrentPrice > theSessionOpenPrice)
   {
      double lookoutPrice = theSessionOpenPrice + (Pip_Distance * Point * PipFactor);
      if (theSessionCurrentPrice >= lookoutPrice)
      {
         if (Spread_Still_In_Range())
         {
            return (true);
         }
         else
         {
            if (!ProblemLogged)
            {
               string logmsg = "The spread is "+DoubleToStr(CustomSpread,1)+" when price moved "+DoubleToStr(Pip_Distance,1)+" from this Session Open Price. No Trade for this session";
               WriteToLogFile(logmsg);
               ProblemLogged = true;
               TradeTheSession = false;
            }
         }
      }
   }
   return (false);
}

bool Should_Sell(int SessionOpenIndex)
{
   if (SessionOpenIndex == -1)
   {
      return (false);
   }
   theSessionOpenPrice = Open[SessionOpenIndex];
   double theSessionCurrentPrice = Close[0];
   if (theSessionCurrentPrice < theSessionOpenPrice)
   {
      double lookoutPrice = theSessionOpenPrice - (Pip_Distance * Point * PipFactor);
      if (theSessionCurrentPrice <= lookoutPrice)
      {
         if (Spread_Still_In_Range())
         {
            return (true);
         }
         else
         {
            if (!ProblemLogged)
            {
               string logmsg = "The spread is "+DoubleToStr(CustomSpread,1)+" when price moved "+DoubleToStr(Pip_Distance,1)+" from this Session Open Price. No Trade for this session";
               WriteToLogFile(logmsg);
               ProblemLogged = true;
               TradeTheSession = false;
            }
         }
      }
   }
   return (false);
}

double PositionSizeToOpen(int StopLossPips)
{
   double PositionSize;
   double riskDollars;
   
   if (MoneyManagement && StopLossPips > 0)
   {      
      if (UseEquity)
      {
         riskDollars = (AccountEquity()/100) * RiskPercent;
      }
      else
      {
         riskDollars = (AccountBalance()/100) * RiskPercent;
      }
      PositionSize = (riskDollars / StopLossPips) / (MarketInfo(Symbol(),MODE_TICKVALUE) * PipFactor);
   }
   
   if (MoneyManagement && StopLossPips <= 0)
   {
      if (UseEquity)
      {
         PositionSize = ((AccountEquity()/100) * RiskPercent) / (MarketInfo(Symbol(),MODE_LOTSIZE) / AccountLeverage());
      }
      else
      {
         PositionSize = ((AccountBalance()/100) * RiskPercent) / (MarketInfo(Symbol(),MODE_LOTSIZE) / AccountLeverage());
      }
   }
   
   if (!MoneyManagement)
   {
      PositionSize = FixedLots;
   }

   if (PositionSize < MinLots)
   {
      PositionSize = MinLots;
   }
   if (PositionSize > MaxLots)
   {
      PositionSize = MaxLots;
   }
   PositionSize = NormalizeDouble(PositionSize,LotsDecimalAllowed);
   return (PositionSize);
}

bool SendOrders (int BuyOrSell, double LotSize, double PriceToOpen, double Slippage, double SL_Price, double TP_Price, string comments, datetime ExpirationTime)
{
   int ticket, errorType;
   
   if (BuyOrSell == OP_BUY)
   {  
      if (IsECN)
      {
         Print("Bid: "+Bid+" Ask: "+Ask+" | Opening Buy Order: "+Symbol()+", "+BuyOrSell+", "+LotSize+", "+PriceToOpen+", "+Slippage+", "+SL_Price+", "+TP_Price+", "+comments+", "+EA_MAGIC_NUM+", "+ExpirationTime+", Green");
         ticket=OrderSend(Symbol(),BuyOrSell,LotSize,PriceToOpen,Slippage,0,0,comments,EA_MAGIC_NUM,ExpirationTime,Green);
         if(ticket>0)
         {
            if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) 
            {
               Print("BUY order opened : ",OrderOpenPrice());
               msg = ticket + ": Buy position opened at "+DoubleToStr(OrderOpenPrice(),Digits);
               WriteToLogFile(msg);
               if (OrderModify(ticket,OrderOpenPrice(),SL_Price,TP_Price,0))
               {
                  Print("Stop Loss and Take Profit added");
                  msg = ticket + ": Stop Loss: "+DoubleToStr(SL_Price,Digits)+" and Take Profit "+DoubleToStr(TP_Price,Digits)+" added";
                  WriteToLogFile(msg);
               }
               else
               {
                  errorType = GetLastError();
                  Print("ERROR adding Stop Loss and Take Profit - ",ErrorDescription(errorType));
                  msg = ticket + ":ERROR adding Stop Loss: "+DoubleToStr(SL_Price,Digits)+" and Take Profit "+DoubleToStr(TP_Price,Digits)+" - "+ErrorDescription(errorType);
                  WriteToLogFile(msg);
               }
               return (true);
            }
         }
         else 
         {  
            errorType = GetLastError();
            Print("Error opening BUY order : ", ErrorDescription(errorType));
            msg = "CANNOT open BUY position. "+ErrorDescription(errorType);
            WriteToLogFile(msg);
            return (false);
         }
      }
      else
      {
         Print("Bid: "+Bid+" Ask: "+Ask+" | Opening Buy Order: "+Symbol()+", "+BuyOrSell+", "+LotSize+", "+PriceToOpen+", "+Slippage+", "+SL_Price+", "+TP_Price+", "+comments+", "+EA_MAGIC_NUM+", "+ExpirationTime+", Green");
         ticket=OrderSend(Symbol(),BuyOrSell,LotSize,PriceToOpen,Slippage,SL_Price,TP_Price,comments,EA_MAGIC_NUM,ExpirationTime,Green);
         if(ticket>0)
         {
            if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) 
            {
               Print("BUY order opened : ",OrderOpenPrice());
               msg = ticket + ": Buy position opened. "+ErrorDescription(errorType);
               WriteToLogFile(msg);
               return (true);
            }
         }
         else 
         {  
            errorType = GetLastError();
            Print("Error opening BUY order : ", ErrorDescription(errorType));
            msg = "CANNOT open BUY position. "+ErrorDescription(errorType);
            WriteToLogFile(msg);
            return (false);
         }
      }
   }
   if (BuyOrSell == OP_SELL)
   {  
      if (IsECN)
      {
         Print("Bid: "+Bid+" Ask: "+Ask+" | Opening Sell Order: "+Symbol()+", "+BuyOrSell+", "+LotSize+", "+PriceToOpen+", "+Slippage+", "+SL_Price+", "+TP_Price+", "+comments+", "+EA_MAGIC_NUM+", "+ExpirationTime+", Red");
         ticket=OrderSend(Symbol(),BuyOrSell,LotSize,PriceToOpen,Slippage,0,0,comments,EA_MAGIC_NUM,ExpirationTime,Red);
         if(ticket>0)
         {
            if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) 
            {
               Print("SELL order opened : ",OrderOpenPrice());
               msg = ticket + ": Sell position opened at "+DoubleToStr(OrderOpenPrice(),Digits);
               WriteToLogFile(msg);
               if (OrderModify(ticket,OrderOpenPrice(),SL_Price,TP_Price,0))
               {
                  Print("Stop Loss and Take Profit added");
                  msg = ticket + ": Stop Loss: "+DoubleToStr(SL_Price,Digits)+" and Take Profit "+DoubleToStr(TP_Price,Digits)+" added";
                  WriteToLogFile(msg);
               }
               else
               {
                  errorType = GetLastError();
                  Print("ERROR adding Stop Loss and Take Profit - ",ErrorDescription(errorType));
                  msg = ticket + ":ERROR adding Stop Loss: "+DoubleToStr(SL_Price,Digits)+" and Take Profit "+DoubleToStr(TP_Price,Digits)+" - "+ErrorDescription(errorType);
                  WriteToLogFile(msg);
               }
               return (true);
            }
         }
         else 
         {  
            errorType = GetLastError();
            Print("Error opening SELL order : ", ErrorDescription(errorType));
            msg = "CANNOT open SELL position. "+ErrorDescription(errorType);
            WriteToLogFile(msg);
            return (false);
         }
      }
      else
      {
         Print("Bid: "+Bid+" Ask: "+Ask+" | Opening Sell Order: "+Symbol()+", "+BuyOrSell+", "+LotSize+", "+PriceToOpen+", "+Slippage+", "+SL_Price+", "+TP_Price+", "+comments+", "+EA_MAGIC_NUM+", "+ExpirationTime+", Red");
         ticket=OrderSend(Symbol(),BuyOrSell,LotSize,PriceToOpen,Slippage,SL_Price,TP_Price,comments,EA_MAGIC_NUM,ExpirationTime,Red);
         if(ticket>0)
         {
            if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) 
            {
               Print("Sell order opened : ",OrderOpenPrice());
               msg = ticket + ": Sell position opened. "+ErrorDescription(errorType);
               WriteToLogFile(msg);
               return (true);
            }
         }
         else 
         {  
            errorType = GetLastError();
            Print("Error opening SELL order : ", ErrorDescription(errorType));
            msg = "CANNOT open SELL position. "+ErrorDescription(errorType);
            WriteToLogFile(msg);
            return (false);
         }
      }
   }
}


bool Spread_Still_In_Range()
{
   if (Use_Spread_Filtering && CustomSpread > Spread_Filter)
   {
      return (false);
   }
   return (true);
}


void OpenBuyOrder()
{
   RefreshRates();
   double PriceToOpen, TakeProfitPrice, StopLossPrice, PositionSize;
   PriceToOpen = Ask;
   PriceToOpen = NormalizeDouble(PriceToOpen,Digits);
   PositionSize = PositionSizeToOpen(the_StopLoss);
   if (TakeProfit == 0)
   {
      TakeProfitPrice = 0;
   }
   else
   {
      TakeProfitPrice = PriceToOpen + (TakeProfit * Point * PipFactor);
      TakeProfitPrice = NormalizeDouble(TakeProfitPrice,Digits);
   }
   if (the_StopLoss == 0)
   {
      StopLossPrice = 0;
   }
   else
   {
      StopLossPrice = PriceToOpen - (the_StopLoss * Point * PipFactor);
      StopLossPrice = NormalizeDouble(StopLossPrice,Digits);
   }
   if (PositionSize < MinLots)
   {
      PositionSize = MinLots;
   }
   if (PositionSize > MaxLots)
   {
      PositionSize = MaxLots;
   }
   PositionSize = NormalizeDouble(PositionSize,LotsDecimalAllowed);
   string DateNow = TimeDay(TimeCurrent())+"-"+TimeMonth(TimeCurrent())+"-"+TimeYear(TimeCurrent());
   SendOrders(OP_BUY, PositionSize, PriceToOpen, Slippage, StopLossPrice, TakeProfitPrice, "CBBP_"+DateNow, 0);            
}

void OpenSellOrder()
{
   RefreshRates();
   double PriceToOpen, TakeProfitPrice, StopLossPrice, PositionSize;
   PriceToOpen = Bid;
   PriceToOpen = NormalizeDouble(PriceToOpen,Digits);
   PositionSize = PositionSizeToOpen(the_StopLoss);
   if (TakeProfit == 0)
   {
      TakeProfitPrice = 0;
   }
   else
   {
      TakeProfitPrice = PriceToOpen - (TakeProfit * Point * PipFactor);
      TakeProfitPrice = NormalizeDouble(TakeProfitPrice,Digits);
   }
   if (the_StopLoss == 0)
   {
      StopLossPrice = 0;
   }
   else
   {
      StopLossPrice = PriceToOpen + (the_StopLoss * Point * PipFactor);
      StopLossPrice = NormalizeDouble(StopLossPrice,Digits);
   }
   
   if (PositionSize < MinLots)
   {
      PositionSize = MinLots;
   }
   if (PositionSize > MaxLots)
   {
      PositionSize = MaxLots;
   }
   PositionSize = NormalizeDouble(PositionSize,LotsDecimalAllowed);
   string DateNow = TimeDay(TimeCurrent())+"-"+TimeMonth(TimeCurrent())+"-"+TimeYear(TimeCurrent());
   SendOrders(OP_SELL, PositionSize, PriceToOpen, Slippage, StopLossPrice, TakeProfitPrice, DateNow, 0);
}

void ManageTrades()
{
   double TrailLevel = PipFactor*Point*TrailingStop;
   TrailLevel = NormalizeDouble(TrailLevel,Digits);
   double BE_Level = PipFactor*Point*BreakEven_Pips;
   BE_Level = NormalizeDouble(BE_Level,Digits);
   double TakeProfitPrice, StopLossPrice, TrueBEPrice;
   string logmsg = "";
   int ticket, errorType;
   double closeNOWprice = 0;
   
   int total = OrdersTotal();
   if (total > 0)
   {
      // must go backwards
      for(int cnt=total-1;cnt>=0;cnt--)
      {
         if(OrderSelect(cnt,SELECT_BY_POS))
         {
            if(OrderSymbol()==Symbol() && OrderMagicNumber() == EA_MAGIC_NUM)
            {
               if (OrderType() == OP_BUY)
               {
                  // In case Stop Loss and TakeProfit was not added. Let's do something about it here...
                  if (OrderStopLoss() == 0 && the_StopLoss != 0)
                  {
                     ticket = OrderTicket();
                     // Close the trade immediately if price has already moved broken the stop loss level
                     if (OrderOpenPrice()-Bid >= PipFactor*Point*the_StopLoss)
                     {
                        closeNOWprice = NormalizeDouble(Bid,Digits);
                        if (OrderClose(ticket,OrderLots(),closeNOWprice,Slippage,Red))
                        {
                           Print("Emergency (Stop Loss) closure of order: ",ticket," successful");
                           logmsg = ticket+": Emergency (Stop Loss) closure successful!";
                           WriteToLogFile(logmsg);
                           continue;
                        }
                        else
                        {
                           errorType = GetLastError();
                           Print("ERROR! Emergency (Stop Loss) closure of order: ",ticket," failed! - ",ErrorDescription(errorType));
                           logmsg = ticket + ":Emergency (Stop Loss) closure of order: "+ticket+" failed! - "+ErrorDescription(errorType);
                           WriteToLogFile(logmsg);
                        }
                     }
                     else
                     {
                        // try to place the Stop Loss and Take Profit level now
                        StopLossPrice = OrderOpenPrice() - (the_StopLoss * Point * PipFactor);
                        StopLossPrice = NormalizeDouble(StopLossPrice,Digits);
                        TakeProfitPrice = OrderOpenPrice() + (TakeProfit * Point * PipFactor);
                        TakeProfitPrice = NormalizeDouble(TakeProfitPrice,Digits);
                        if (OrderModify(ticket,OrderOpenPrice(),StopLossPrice,TakeProfitPrice,0))
                        {
                           Print("Stop Loss and Take Profit of order: ",ticket," added successfully");
                           logmsg = ticket+": Stop Loss and Take Profit added successfully!";
                           WriteToLogFile(logmsg);
                        }
                        else
                        {
                           errorType = GetLastError();
                           Print("ERROR! Adding Stop Loss and Take Profit of order: ",ticket," failed! - ",ErrorDescription(errorType));
                           logmsg = ticket + ":Adding Stop Loss and Take Profit of order: "+ticket+" failed! - "+ErrorDescription(errorType);
                           WriteToLogFile(logmsg);
                        }
                     }
                  }
                  // Similar to the above except this tackles the takeprofit level breech scenario
                  if (OrderTakeProfit() == 0 && TakeProfit != 0)
                  {
                     // Close the trade immediately if price has already moved broken the stop loss level
                     if (Bid-OrderOpenPrice() >= PipFactor*Point*TakeProfit)
                     {
                        ticket = OrderTicket();
                        closeNOWprice = NormalizeDouble(Bid,Digits);
                        if (OrderClose(ticket,OrderLots(),closeNOWprice,Slippage,Blue))
                        {
                           Print("Emergency (Take Profit) closure of order: ",ticket," successful");
                           logmsg = ticket+": Emergency (Take Profit) closure successful!";
                           WriteToLogFile(logmsg);
                           continue;
                        }
                        else
                        {
                           errorType = GetLastError();
                           Print("ERROR! Emergency (Take Profit) closure of order: ",ticket," failed! - ",ErrorDescription(errorType));
                           logmsg = ticket + ":Emergency (Take Profit) closure of order: "+ticket+" failed! - "+ErrorDescription(errorType);
                           WriteToLogFile(logmsg);
                        }
                     }
                  }
                  
                  // Check for Breakeven.
                  if (Use_BE)
                  {
                     if(Bid-OrderStopLoss() > BE_Level)
                     {
                        if(CommissionPips > 0)
                        {
                           TrueBEPrice = OrderOpenPrice() + (PipFactor*Point*CommissionPips);
                        }
                        else
                        {
                           TrueBEPrice = OrderOpenPrice();
                        }
                        NormalizeDouble(TrueBEPrice,Digits);
                        if (OrderStopLoss() < TrueBEPrice)
                        {
                           StopLossPrice = Bid - BE_Level;
                           StopLossPrice = NormalizeDouble(StopLossPrice,Digits);
                           if (StopLossPrice >= TrueBEPrice)
                           {
                              if(OrderModify(OrderTicket(),OrderOpenPrice(),TrueBEPrice,OrderTakeProfit(),0,Blue))
                              {
                                 logmsg = "Buy Order "+OrderTicket()+" SL reached breakeven level.";
                                 WriteToLogFile(logmsg);
                              }
                           }
                           else
                           {
                              if(OrderModify(OrderTicket(),OrderOpenPrice(),StopLossPrice,OrderTakeProfit(),0,Blue))
                              {
                                 logmsg = "Buy Order "+OrderTicket()+" SL moving towards breakeven level.";
                                 WriteToLogFile(logmsg);
                              }
                           }
                        }
                     }
                  }
                  // Check for Floating Stop
                  if (!UseJumpingStop && (TrailingStop != 0))
                  {
                     if((Bid-OrderOpenPrice()) > TrailLevel && ((Bid-OrderOpenPrice()) >= BE_Level || OrderStopLoss() >= OrderOpenPrice()))
                     {
                        if(OrderStopLoss() < Bid-TrailLevel)
                        {
                           StopLossPrice = NormalizeDouble(Bid-TrailLevel,Digits);
                           OrderModify(OrderTicket(),OrderOpenPrice(),StopLossPrice,OrderTakeProfit(),0,Blue);
                        }
                     }
                  }
                  // Check for Jumping Stop
                  if (UseJumpingStop && (TrailingStop != 0))
                  {
                     if((Bid-OrderStopLoss()>(TrailLevel*2)) && ((Bid-OrderOpenPrice()) >= BE_Level || OrderStopLoss() >= OrderOpenPrice()))
                     {
                        if ((OrderStopLoss()+TrailLevel) < OrderTakeProfit() || OrderTakeProfit() == 0) // Stop loss level cannot be higher than take profit level
                        {
                           StopLossPrice = NormalizeDouble(OrderStopLoss()+TrailLevel,Digits);
                           OrderModify(OrderTicket(),OrderOpenPrice(),StopLossPrice,OrderTakeProfit(),0,Blue);
                        }
                     }
                  }
               }
               
               if (OrderType() == OP_SELL)
               {
                  // In case Stop Loss and TakeProfit was not added. Let's do something about it here...
                  if (OrderStopLoss() == 0 && the_StopLoss != 0)
                  {
                     ticket = OrderTicket();
                     // Close the trade immediately if price has already moved broken the stop loss level
                     if (Ask - OrderOpenPrice() >= PipFactor*Point*the_StopLoss)
                     {
                        closeNOWprice = NormalizeDouble(Ask,Digits);
                        if (OrderClose(ticket,OrderLots(),closeNOWprice,Slippage,Red))
                        {
                           Print("Emergency (Stop Loss) closure of order: ",ticket," successful");
                           logmsg = ticket+": Emergency (Stop Loss) closure successful!";
                           WriteToLogFile(logmsg);
                           continue;
                        }
                        else
                        {
                           errorType = GetLastError();
                           Print("ERROR! Emergency (Stop Loss) closure of order: ",ticket," failed! - ",ErrorDescription(errorType));
                           logmsg = ticket + ":Emergency (Stop Loss) closure of order: "+ticket+" failed! - "+ErrorDescription(errorType);
                           WriteToLogFile(logmsg);
                        }
                     }
                     else
                     {
                        // try to place the Stop Loss and Take Profit level now
                        StopLossPrice = OrderOpenPrice() + (the_StopLoss * Point * PipFactor);
                        StopLossPrice = NormalizeDouble(StopLossPrice,Digits);
                        TakeProfitPrice = OrderOpenPrice() - (TakeProfit * Point * PipFactor);
                        TakeProfitPrice = NormalizeDouble(TakeProfitPrice,Digits);
                        if (OrderModify(ticket,OrderOpenPrice(),StopLossPrice,TakeProfitPrice,0))
                        {
                           Print("Stop Loss and Take Profit of order: ",ticket," added successfully");
                           logmsg = ticket+": Stop Loss and Take Profit added successfully!";
                           WriteToLogFile(logmsg);
                        }
                        else
                        {
                           errorType = GetLastError();
                           Print("ERROR! Adding Stop Loss and Take Profit of order: ",ticket," failed! - ",ErrorDescription(errorType));
                           logmsg = ticket + ":Adding Stop Loss and Take Profit of order: "+ticket+" failed! - "+ErrorDescription(errorType);
                           WriteToLogFile(logmsg);
                        }
                     }
                  }
                  // Similar to the above except this tackles the takeprofit level breech scenario
                  if (OrderTakeProfit() == 0 && TakeProfit != 0)
                  {
                     // Close the trade immediately if price has already moved broken the stop loss level
                     if (OrderOpenPrice()-Ask >= PipFactor*Point*TakeProfit)
                     {
                        ticket = OrderTicket();
                        closeNOWprice = NormalizeDouble(Ask,Digits);
                        if (OrderClose(ticket,OrderLots(),closeNOWprice,Slippage,Blue))
                        {
                           Print("Emergency (Take Profit) closure of order: ",ticket," successful");
                           logmsg = ticket+": Emergency (Take Profit) closure successful!";
                           WriteToLogFile(logmsg);
                           continue;
                        }
                        else
                        {
                           errorType = GetLastError();
                           Print("ERROR! Emergency (Take Profit) closure of order: ",ticket," failed! - ",ErrorDescription(errorType));
                           logmsg = ticket + ":Emergency (Take Profit) closure of order: "+ticket+" failed! - "+ErrorDescription(errorType);
                           WriteToLogFile(logmsg);
                        }
                     }
                  }
                  
                  // Check for Breakeven
                  if (Use_BE)
                  {
                     if(OrderStopLoss()-Ask > BE_Level)
                     {
                        if(CommissionPips > 0)
                        {
                           TrueBEPrice = OrderOpenPrice() - (PipFactor*Point*CommissionPips);
                        }
                        else
                        {
                           TrueBEPrice = OrderOpenPrice();
                        }
                        NormalizeDouble(TrueBEPrice,Digits);
                        if (OrderStopLoss() > TrueBEPrice)
                        {
                           StopLossPrice = Ask + BE_Level;
                           StopLossPrice = NormalizeDouble(StopLossPrice,Digits);
                           if (StopLossPrice <= TrueBEPrice)
                           {
                              if(OrderModify(OrderTicket(),OrderOpenPrice(),TrueBEPrice,OrderTakeProfit(),0,Blue))
                              {
                                 logmsg = "Sell Order "+OrderTicket()+" SL reached breakeven level.";
                                 WriteToLogFile(logmsg);
                              }
                           }
                           else
                           {
                              if(OrderModify(OrderTicket(),OrderOpenPrice(),StopLossPrice,OrderTakeProfit(),0,Blue))
                              {
                                 logmsg = "Sell Order "+OrderTicket()+" SL moving towards breakeven level.";
                                 WriteToLogFile(logmsg);
                              }
                           }
                        }
                     }
                  }
                  // Check for Floating Stop
                  if (!UseJumpingStop && (TrailingStop != 0))
                  {
                     if((OrderOpenPrice()-Ask) > TrailLevel  && ((OrderOpenPrice()-Ask) >= BE_Level || OrderStopLoss() <= OrderOpenPrice()))
                     {
                        if(OrderStopLoss() > Ask+TrailLevel)
                        {
                           StopLossPrice = NormalizeDouble(Ask+TrailLevel,Digits);
                           OrderModify(OrderTicket(),OrderOpenPrice(),StopLossPrice,OrderTakeProfit(),0,Blue);
                        }
                     }
                  }
                  // Check for Jumping Stop
                  if (UseJumpingStop && (TrailingStop != 0))
                  {
                     // only activate when position is in profit by stoploss amt.
                     if(((OrderStopLoss()-Ask)>(TrailLevel*2)) && ((OrderOpenPrice()-Ask) >= BE_Level || OrderStopLoss() <= OrderOpenPrice()))
                     {
                        if ((OrderStopLoss()-TrailLevel) > OrderTakeProfit() || OrderTakeProfit() == 0) // Stop loss level cannot be less than take profit level
                        {
                           StopLossPrice = NormalizeDouble(OrderStopLoss()-TrailLevel,Digits);
                           OrderModify(OrderTicket(),OrderOpenPrice(),StopLossPrice,OrderTakeProfit(),0,Blue);
                        }
                     }
                  }
               }
            }
         }
      }
   }
}

//+------------------------------------------------------------------+
//| Miscellaneous functions                                          |
//+------------------------------------------------------------------+

void GetSpread()
{
   if (UserDefinedSpread <= 0)
   {
      CustomSpread = (MarketInfo(Symbol(),MODE_SPREAD)) / PipFactor;
   }
   else
   {
      CustomSpread = UserDefinedSpread;
   }
   
   // Should we add the spread into the StopLoss?
   the_StopLoss = StopLoss;
   if (StopLoss > 0)
   {
      if (Add_Spread_To_StopLoss)
      {
         the_StopLoss = StopLoss + CustomSpread;
      }
      else
      {
         the_StopLoss = StopLoss;
      }
   }
}

void WriteComment()
{
   msg = "";
   int currentHour = TimeHour(Time[0]);
   if (SessionOpenHour1 < SessionOpenHour2)
   {
      if (currentHour < SessionOpenHour2)
      {
         msg = "EA waiting for "+Session2+" Open";
      }
      if (currentHour < SessionOpenHour1 || currentHour > SessionOpenHour2)
      {
         msg = "EA waiting for "+Session1+" Open";
      }
   }
   else
   {
      if (currentHour < SessionOpenHour1)
      {
         msg = "EA waiting for "+Session1+" Open";
      }
      if (currentHour < SessionOpenHour2 || currentHour > SessionOpenHour1)
      {
         msg = "EA waiting for "+Session2+" Open";
      }
   }
   msg = msg + "\nCurrent Time: "+ currentHour +":"+TimeMinute(TimeCurrent());
   
   if (PipFactor == 10)
   {
      msg = msg + "\nWorking with Fractional pips";
   }
   else
   {
      msg = msg + "\nWorking with Non-Fractional pips";
   }
 //  double stoplevel = MarketInfo(Symbol(), MODE_STOPLEVEL) / PipFactor;
   
   if (MoneyManagement && the_StopLoss > 0)
   {
      msg = msg + "\nUsing MoneyManagement Feature according to Stop loss";
   }
   msg = msg + "\nCurrent Spread: "+DoubleToStr(CustomSpread,1)+" pips";
   if (Add_Spread_To_StopLoss && the_StopLoss != 0)
   {
      msg = msg + "\nSpread will be added to your Stop Loss";
   }
   else
   {
      msg = msg + "\nSpread will NOT be added to Stop Loss";
   }
   if (SessionIsOn)
   {
      msg = msg + "\n\nTime to trade "+latestSession+". Looking for entry...";
      msg = msg + "\nSession Open Price: "+DoubleToStr(theSessionOpenPrice,Digits);
      msg = msg + "\nCurrent Price:      "+DoubleToStr(Close[0],Digits);
   }
   else
   {
      msg = msg + "\n"+latestSession+" trading window is closed.";
   }
   Comment(msg);
}

void WriteToLogFile(string input)
{
   string filename = "CBBP-"+Symbol()+"-"+Day()+"-"+Month()+"-"+Year()+".log";
   int handle = FileOpen(filename,FILE_READ|FILE_WRITE);
   if (handle>1)
   {
      string prefix = Day()+"/"+Month()+"/"+Year()+" - "+Hour()+":"+Minute()+":"+Seconds()+" => ";
      FileSeek(handle, 0, SEEK_END); // go to end of file
      FileWrite(handle, prefix+input);
      FileClose(handle);
   }
}
// This method is created to spawn a new file for a new day. The first line to be written sometimes don't get written.
// The dummy message used here can act as a buffer so that useful info don't get missed out.
void CreateNewLogFileIfNewDay()
{
   if (todayOfYear != DayOfYear())
   {
      todayOfYear = DayOfYear();
      WriteToLogFile("Dummy message");
   }
}

bool TimeToTrade()
{
   int currentHour = TimeHour(Time[0]);
   int currentMinute = TimeMinute(TimeCurrent());
   if ((currentHour == SessionOpenHour1 || currentHour == SessionOpenHour2) && currentMinute < GraceMinutes)
   {
      return (true);
   }
   return (false);
}

int GetSessionOpenCandle()
{
   int SessionOpenCandleIndex = -1;
   for (int i=0; i<=GraceMinutes+1; i++)
   {
      if (TimeHour(Time[i]) == currentSessionHour && TimeMinute(Time[i]) == 0)
      {
         SessionOpenCandleIndex = i;
         break;
      }
   }
   return (SessionOpenCandleIndex);
}

//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
{
//----
   if (!StartupStatusOK)
   {
      Comment("There were errors in your EA inputs. Please recheck them again.");
      return (0);
   }
   CreateNewLogFileIfNewDay();
   ManageTrades();
   GetSpread();
   
   if (TimeToTrade())
   {
      currentSessionHour = TimeHour(Time[0]);
      if (currentSessionHour == SessionOpenHour1)
      {
         latestSession = Session1;
      }
      if (currentSessionHour == SessionOpenHour2)
      {
         latestSession = Session2;
      }
      if (TradeNotPlacedYet() && TradeTheSession)
      {
         int SessionOpenIndex = GetSessionOpenCandle();
         SessionIsOn = true;
         if (!SessionOpenPriceWritten)
         {
            string logmsg = latestSession+" open at "+DoubleToStr(Open[SessionOpenIndex],Digits);
            Print(logmsg);
            WriteToLogFile(logmsg);
            SessionOpenPriceWritten = true;
         }
         if (Should_Buy(SessionOpenIndex) && TradeTheSession)
         {
            OpenBuyOrder();
            TradeTheSession = false;
         }
         if (Should_Sell(SessionOpenIndex) && TradeTheSession)
         {
            OpenSellOrder();
            TradeTheSession = false;
         }
      }
      else
      {
         SessionIsOn = false;
      }
   }
   else
   {
      SessionIsOn = false;
      TradeTheSession = true;
      ProblemLogged = false;
      SessionOpenPriceWritten = false;
   }
     if (Show_Comments)
   {
      WriteComment();
   }
 
//----
   return(0);
}
//+------------------------------------------------------------------+