//+------------------------------------------------------------------+
//|                                                    The Finch.mq4 |
//|                                       Copyright 2016, Rob Booker |
//|                                             http://robbooker.com |
//|                                                                  |
//|    v2.5 30-Oct-2017 BW                                           |
//|     	add chart background colours                                |
//|    v2.5.1 10-Nov-2017 BW                                         |
//|     	add parameter to control chart background colours           |
//|      tidy up comment                                             |
//+------------------------------------------------------------------+
#property copyright "Copyright 2017, Rob Booker"
#property link      "http://robbooker.com"
#property strict
#property version   "2.5.1"
string    version = "2.5.1"; // [BW used in comment field of ordersend ]


input string WARNING = "Using a robot carries risk, use on demo account FIRST";
input string NOTE = "Download the Robots guide: http://bit.ly/2c2yYnL";
input int Magic =12345;
input int CandlesBack = 30;
input int Slippage=5;
input int Max_Spread_Pips=5;

input double First_Trade_Lots=0.01;
input double Second_Trade_Lots=0.03;

input int Pips_To_Trade_2 = 70;

input string Stop_Type="Default no stop loss";
input double Stop_Loss_In_Dollars=0.0;

input string Profit_In_Dollars = "Profit Targets in Dollar Value format";
input double First_Trade_Profit_In_Dollars=1.3;
input double Second_Trade_Profit_In_Dollars=1.3;

input bool Break_Even = false;
input double Break_Even_At_Profit = 6.5;

input int RSIPeriod = 21;
input int MomentumPeriod = 20;

// [BW 2.5.1
input bool Change_Colour = true;
// BW]

input bool Mail_Alert = false;
input bool PopUp_Alert = false;
input bool Sound_Alert = false;
input bool SmartPhone_Notifications=false;
double UsePoint;
int UseSlippage;

double Order_Stop;

double CloseOne;

int LastKDB;
int LastKDS;
// [BW 2.5
string InstanceID = "Finch";
color InitialClr = LightCyan;
color FirstTradeClr = Plum;
color SecondTradeClr = Gold;
// BW]
double Order_Profit;

int Order_Type = 2;
double PriceForBuy=9999.0;
double PriceForSell=0.0;


bool BreakEven=false;

int TotalTrades=0;

bool BuysNotAllowed=false;
bool SellsNotAllowed=false;

int OnInit()
{
   UsePoint = PipPoint();
   UseSlippage = GetSlippage();
   if (Change_Colour) ChartBackColorSet(InitialClr,0); // reset chart colour to initial

return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason)
{
    // [BW v2.5 added color reset line below ]
    if (Change_Colour) ChartBackColorSet(InitialClr,0); // reset chart colour to initial
}

void OnTick()
{
   CheckProfit();
   
// [BW v2.5 Change screen colour depending on 1st or second trade
   if (Change_Colour) {
      if(TotalTrades == 1) {
         ChartBackColorSet(FirstTradeClr,0);  // set chart colour to 1st trade 
         }
      else if(TotalTrades == 2) {
         ChartBackColorSet(SecondTradeClr,0);  // set chart colour to 1st trade 
         }
   else if(TotalTrades == 0) {
         ChartBackColorSet(InitialClr,0);  // set chart colour to 1st trade 
         }
   }      
// BW]  

   if(TotalTrades==2) return;
   if(CloseOne!=Close[1])
   {
      if(!BuysNotAllowed && Order_Type!=1 && Close[0]<=PriceForBuy && RSIBuyCheck(1)) OpenTrade("Buy");
      if(!SellsNotAllowed && Order_Type!=0 && Close[0]>=PriceForSell && RSISellCheck(1)) OpenTrade("Sell");

      CloseOne=Close[1];
   }
}
double PipPoint()
{
   if(Digits() == 2 || Digits() == 3) return(0.01);
   else if(Digits() == 4 || Digits() == 5) return(0.0001);
   return(Point);
}
int GetSlippage()
{
   if(Digits() == 2 || Digits() == 4) return(Slippage);
   else if(Digits() == 3 || Digits() == 5) return(Slippage*10);
   return(Digits());
}
void CheckProfit()
{
   double Profits=0.0;
   TotalTrades=0;
   for(int x=0;x<OrdersTotal();x++)
   {
      if(OrderSelect(x,SELECT_BY_POS,MODE_TRADES))
      {
         if(OrderMagicNumber()!=Magic) continue;
         if(OrderSymbol()!=Symbol()) continue;
         
         Profits+=OrderProfit();
         TotalTrades=TotalTrades+1;
         
         if(OrderType()==0) {Order_Type=OrderType();PriceForBuy=OrderOpenPrice()-(Pips_To_Trade_2*UsePoint);}
         if(OrderType()==1) {Order_Type=OrderType();PriceForSell=OrderOpenPrice()+(Pips_To_Trade_2*UsePoint);}
         
      }
   }

   if(TotalTrades==0) {BreakEven=false;Order_Type=2;return;}
   
   if(TotalTrades==1 && Profits>=First_Trade_Profit_In_Dollars) {Print("Profit is "+DoubleToStr(Profits,2));CloseAllTrades();return;}
   if(TotalTrades>=2 && Profits>=Second_Trade_Profit_In_Dollars) {Print("Profit is "+DoubleToStr(Profits,2));CloseAllTrades();return;}

   if(Stop_Loss_In_Dollars>0 && TotalTrades>0 && Profits<=(Stop_Loss_In_Dollars*(-1))) {Print("Profit is "+DoubleToStr(Profits,2));CloseAllTrades();return;}

   if(Break_Even && !BreakEven && Profits>=Break_Even_At_Profit) {Print("Finch Break Even Begin");BreakEven=true;}
   
   if(Break_Even && BreakEven && Profits<=0) {CloseAllTrades();return;}
return;
}
int OpenTrades()
{
   int thetotal=0;
   for(int x=0;x<OrdersTotal();x++)
   {
      if(OrderSelect(x,SELECT_BY_POS,MODE_TRADES))
      {
         if(OrderMagicNumber()!=Magic) continue;
         if(OrderSymbol()!=Symbol()) continue;
         
         thetotal++;
      }
   }
   RefreshRates();
   return(thetotal);
}   
void CloseAllTrades()
{
   Order_Type=2;
   
   BreakEven=false;
   
   PriceForBuy=9999.0;
   PriceForSell=0.0;

   while(OpenTrades()>0)
   {   
      for(int x=0;x<OrdersTotal();x++)
      {
         if(OrderSelect(x,SELECT_BY_POS,MODE_TRADES))
         {
            if(OrderMagicNumber()!=Magic) continue;
            if(OrderSymbol()!=Symbol()) continue;
            
            if(OrderType()==0) bool c1 = OrderClose(OrderTicket(),OrderLots(),Bid,UseSlippage);
            if(OrderType()==1) bool c2 = OrderClose(OrderTicket(),OrderLots(),Ask,UseSlippage);
            
            x--;
            
            if(GetLastError()==136) continue;
         }
      }
      Sleep(1000);
      RefreshRates();
   }
return;
}
void OpenTrade(string Type)
{
   double TheSpread=MarketInfo(Symbol(),MODE_SPREAD);
   if(Digits()==3 || Digits()==5) TheSpread = MarketInfo(Symbol(),MODE_SPREAD)/10;
   
   if(TheSpread>Max_Spread_Pips) {Print("Spread too large, can't place trade");return;}

   // [BW v2.5
   string PeriodText;
   PeriodText = FnGetPeriodText(Period());
   // BW]
   
   double Lots = First_Trade_Lots;
   if(TotalTrades==1) { // [BW 2.5.1
      Lots=Second_Trade_Lots;
      PeriodText += " 2nd";
   }
   else PeriodText += " 1st";
   // BW]
   
   if(Type=="Buy")
   {      
      int Buy = OrderSend(Symbol(),OP_BUY,Lots,Ask,UseSlippage,0,0,PeriodText,Magic,0,0);

      if(GetLastError()==4110) {BuysNotAllowed=true;return;}

      PriceForBuy=Close[0]-(Pips_To_Trade_2*UsePoint);
      
      Order_Type=0;

      SendAlert("New Finch Buy Trade on the "+Symbol());
   }
   if(Type=="Sell")
   {
      int Sell = OrderSend(Symbol(),OP_SELL,Lots,Bid,UseSlippage,0,0,PeriodText,Magic,0,0);

      if(GetLastError()==4111) {SellsNotAllowed=true;return;}
         
      PriceForSell=Close[0]+(Pips_To_Trade_2*UsePoint);
      
      Order_Type=1;
      
      SendAlert("New Finch Sell Trade on the "+Symbol());
   }
return;
}
bool RSISellCheck(int Loc)
{
   double RSIMain = iRSI(Symbol(),0,RSIPeriod,PRICE_CLOSE,Loc);
   if(RSIMain < 50) return(false);
   for(int x=Loc;x<=Loc+2;x++)
   {
      if(High[x]>High[Loc])return(false);
   }
   for(int y=Loc+4;y<(Loc+CandlesBack);y++)
   {
      if(High[y]>High[Loc]) break;
      int s=y;
      for(int z=y-2;z<=y+2;z++)
      {
         if(High[z]>High[y]){y++; break;}
      }
      if(s!=y){y--; continue;}
      bool OB=false;
      for(int k=Loc;k<=y;k++)
      {
         double RSIOB = iRSI(Symbol(),0,RSIPeriod,PRICE_CLOSE,k);
         if(RSIOB>70) {OB=true; break;}
      }
      if(OB==false) continue;
      double Mom1=iMomentum(Symbol(),0,MomentumPeriod,PRICE_CLOSE,Loc);
      double Mom2=iMomentum(Symbol(),0,MomentumPeriod,PRICE_CLOSE,y);
      if(Mom1>Mom2) continue;
      LastKDS=y;
      return(true);
   }
   return(false);
}
bool RSIBuyCheck(int Loc)
{
   double RSIMain = iRSI(Symbol(),0,RSIPeriod,PRICE_CLOSE,Loc);
   if(RSIMain > 50) return(false);
   for(int x=Loc;x<=Loc+2;x++)
   {
      if(Low[x]<Low[Loc])return(false);
   }
   for(int y=Loc+4;y<(Loc+CandlesBack);y++)
   {
      if(Low[y]<Low[Loc]) break;
      int s=y;
      for(int z=y-2;z<=y+2;z++)
      {
         if(Low[z]<Low[y]){y++; break;}
      }
      if(s!=y){y--; continue;}
      bool OB=false;
      for(int k=Loc;k<=y;k++)
      {
         double RSIOB = iRSI(Symbol(),0,RSIPeriod,PRICE_CLOSE,k);
         if(RSIOB<30) {OB=true; break;}
      }
      if(OB==false) continue;
      double Mom1=iMomentum(Symbol(),0,MomentumPeriod,PRICE_CLOSE,Loc);
      double Mom2=iMomentum(Symbol(),0,MomentumPeriod,PRICE_CLOSE,y);
      if(Mom1<Mom2) continue;
      LastKDB=y;
      return(true);
   }
   return(false);
}
void SendAlert(string Message)
{
   if(Mail_Alert) SendMail("New Finch Alert",Message);
   if(PopUp_Alert) Alert(Message);
   if(Sound_Alert) PlaySound("alert.wav");
   if(SmartPhone_Notifications) SendNotification(Message);
   return;
}

//[BW v1.23 added the below functions 
string FnGetPeriodText(int CurrPeriod)
{
   string PerTxt;
   switch (CurrPeriod)
   {
   case PERIOD_M1:
      PerTxt = "M1";
      break;
   case PERIOD_M5:
      PerTxt = "M5";
      break;
   case PERIOD_M15:
      PerTxt = "M15";
      break;            
   case PERIOD_M30:
      PerTxt = "M30";
      break; 
   case PERIOD_H1:
      PerTxt = "H1";
      break;
   case PERIOD_H4:
      PerTxt = "H4";
      break;
   case PERIOD_D1:
      PerTxt = "D1";
      break;
   case PERIOD_W1:
      PerTxt = "W1";
      break;
   case PERIOD_MN1:
      PerTxt = "MN1";
      break;
   default :
      PerTxt = "Period Error";
      break;
   }
   PerTxt = InstanceID + " v"+ version+ " " + PerTxt;
   
   return(PerTxt);
}
 

//+------------------------------------------------------------------+
//| The function sets chart background color.                        |
//+------------------------------------------------------------------+
bool ChartBackColorSet(const color clr,const long chart_ID=0)
  {
//--- reset the error value
   ResetLastError();
//--- set the chart background color
   if(!ChartSetInteger(chart_ID,CHART_COLOR_BACKGROUND,clr))
     {
      //--- display the error message in Experts journal
      Print(__FUNCTION__+", Error Code = ",GetLastError());
      return(false);
     }
//--- successful execution
   return(true);
  }   
  // BW] 