//+------------------------------------------------------------------+
//|                                                      Caillou.mq4 |
//|                                  Copyright © 2010, Steve Hopwood |
//|                              http://www.hopwood3.freeserve.co.uk |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2010, Steve Hopwood"
#property link      "http://www.hopwood3.freeserve.co.uk"
#include <WinUser32.mqh>
#include <stdlib.mqh>
#define  NL    "\n"
#define  up "Up"
#define  down "Down"
#define  none "None"
#define closelabelname "Close label"
#define stoplabelname "Stop label"
#define startlabelname "Start label"


extern int     DisplayGapSize=30;
extern double  Lot=0.1;
extern double  WithTrendLotMultiplier=2;
extern int     ProfitTarget=20;
extern int     SingleTradeProfitTarget=10;
extern int     MagicNumber=20110712;
extern string  TradeComment="C";
extern bool    CriminalIsECN=false;
extern string  tt="----Trading hours----";
extern string  Trade_Hours= "Set Morning & Evening Hours";
extern string  Trade_Hoursi= "Use 24 hour, local time clock";
extern string  Trade_Hours_M= "Morning Hours 0-12";
extern  int    start_hourm = 0;
extern  int    end_hourm = 12;
extern string  Trade_Hours_E= "Evening Hours 12-24";
extern  int    start_houre = 12;
extern  int    end_houre = 24;
extern string  fsh="Friday stop trading hour";
extern int     FridayStopHour=14;
extern string  fta="For the Aussies";
extern int     SaturdayStopHour=-1;
extern string  Tin="----Trend Inputs----";
extern bool    UseTrend=true;
extern int     tf_1=1;
extern int     tf_2=5;
extern int     tf_3=15;
extern int     tf_4=30;
extern int     tf_5=60;
extern string  Iin="----Indicators Values----";
extern int     RSIperiod=8;
extern int     RSIprice=0;
extern int     RSIshift=0;
extern int     MAtype=0;
extern int     MAperiod=3;
extern int     MAprice=0;
extern int     MAshift=1;
extern string  ap0="Applied price: 0=Close; 1=Open; 2=High";
extern string  ap1="3=Low; 4=Median; 5=Typical; 6=Weighted";



int            OldBars, OpenTrades;
string         PipDescription=" pips";
string         CandleDirection;
string         Gap, ScreenMessage;
double         upl;//Basket profit/loss
bool           ForceClose=false;
bool           RobotStopped=true;
string         trend;
int            TicketNo;

//Labels
int CloseButtonX = 300, CloseButtonY = 25;
int StopButtonX  = 300, StopButtonY  = 75;
int StartButtonX = 300, StartButtonY = 125;

//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+

void DisplayUserFeedback()
{
   
   if (IsTesting() && !IsVisualMode()) return;

   ScreenMessage = "";
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, TimeToStr(TimeLocal(), TIME_DATE|TIME_MINUTES|TIME_SECONDS), NL );
 
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Trading hours", NL);
   if (start_hourm == 0 && end_hourm == 12 && start_houre && end_houre == 24) ScreenMessage = StringConcatenate(ScreenMessage,Gap, "            24H trading", NL);
   else
   {
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "            start_hourm: ", DoubleToStr(start_hourm, 2), 
                      ": end_hourm: ", DoubleToStr(end_hourm, 2), NL);
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "            start_houre: ", DoubleToStr(start_houre, 2), 
                      ": end_houre: ", DoubleToStr(end_houre, 2), NL);
                      
   }//else
   
   if (FridayStopHour > -1) ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Fridday stop hour: ", FridayStopHour, NL );
   if (SaturdayStopHour > -1) ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Saturday stop hour: ", SaturdayStopHour, NL );   
   
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Lot: ", Lot, NL );
   
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Profit target: ", DoubleToStr(ProfitTarget, 2), NL );
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Open trades = ", OpenTrades, ":   Upl = ", DoubleToStr(upl, 2), NL );
   
   
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Candle direction: ", CandleDirection, NL );
   if (UseTrend) ScreenMessage = StringConcatenate(ScreenMessage, Gap, " Trend is ", trend, NL );
   
   Comment(ScreenMessage);


}//void DisplayUserFeedback()


int init()
{
//----
   //Adapt to x digit criminals
   int multiplier;
   if(Digits == 2 || Digits == 4) multiplier = 1;
   if(Digits == 3 || Digits == 5) multiplier = 10;
   if(Digits == 6) multiplier = 100;   
   if(Digits == 7) multiplier = 1000;   
   
   if (multiplier > 1) PipDescription = " points";
   


   Gap="";
   if (DisplayGapSize >0)
   {
      for (int cc=0; cc< DisplayGapSize; cc++)
      {
         Gap = StringConcatenate(Gap, " ");
      }   
   }//if (DisplayGapSize >0)
   
  //Create a close immediately label
  ObjectDelete(closelabelname);
  ObjectCreate(closelabelname, OBJ_LABEL, 0, 0, 0);
  ObjectSet(closelabelname, OBJPROP_XDISTANCE, CloseButtonX);
  ObjectSet(closelabelname, OBJPROP_YDISTANCE, CloseButtonY);
  ObjectSetText(closelabelname, "Close all trades", 12, "Arial", Yellow);

  //Create a stop expert label
  ObjectDelete(stoplabelname);
  ObjectCreate(stoplabelname, OBJ_LABEL, 0, 0, 0);
  ObjectSet(stoplabelname, OBJPROP_XDISTANCE, StopButtonX);
  ObjectSet(stoplabelname, OBJPROP_YDISTANCE, StopButtonY);
  ObjectSetText(stoplabelname, "Stop the robot", 12, "Arial", Yellow);

  //Create a restart expert label
  ObjectDelete(startlabelname);
  ObjectCreate(startlabelname, OBJ_LABEL, 0, 0, 0);
  ObjectSet(startlabelname, OBJPROP_XDISTANCE, StartButtonX);
  ObjectSet(startlabelname, OBJPROP_YDISTANCE, StartButtonY);
  ObjectSetText(startlabelname, "Start the robot", 12, "Arial", Yellow);

   if (TradeComment == "") TradeComment = " ";
   //OldBars = Bars;
   GetPreviousBarDirection();
   if (UseTrend) GetTREND();
   DisplayUserFeedback();
   start();
   
//----
   return(0);
}
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
{
//----
   
//----
   return(0);
}


void GetPreviousBarDirection()
{
   CandleDirection = none;
//   if (Close[1] > Open[1]) CandleDirection = up;
//   if (Close[1] < Open[1]) CandleDirection = down;
   if ( (Bid > Open[0]) && (Bid > iMA(NULL,0,MAperiod,0,MAtype,MAprice,MAshift)) ) CandleDirection = up;
   if ( (Bid < Open[0]) && (Ask < iMA(NULL,0,MAperiod,0,MAtype,MAprice,MAshift)) ) CandleDirection = down;

}//void GetPreviousBarDirection()

void CountOpenTrades()
{
   upl = 0;
   OpenTrades = 0;
   
   if (OrdersTotal() == 0) return;
   
   for (int cc = OrdersTotal() - 1; cc >= 0; cc--)
   {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;
      if (OrderMagicNumber() != MagicNumber) continue;
      
      if (OrderSymbol() == Symbol() )
      {
         upl+= OrderProfit() + OrderSwap() + OrderCommission();
         OpenTrades++;
         TicketNo = OrderTicket();
      }//if (OrderMagicNumber() != MagicNumber && OrderSymbol() == Symbol() )
      
   
   }//for (int cc = OrdersTotal() - 1; cc >= 0; cc--)
   
}//void CountOpenTrades()

bool CloseOrderGroup(int ordertype)
{
   ForceClose = false;
   
   for (int cc = OrdersTotal() - 1; cc >= 0; cc--)
   {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;
      if (OrderMagicNumber() != MagicNumber) continue;
      
      if (OrderMagicNumber() == MagicNumber && OrderSymbol() == Symbol() && OrderType() == ordertype )
      {
         bool result = OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 1000, Red);
         if (!result) ForceClose = true;
         if (result) cc++;
      }//if (OrderMagicNumber() != MagicNumber && OrderSymbol() == Symbol() )
      
   
   }//for (int cc = OrdersTotal() - 1; cc >= 0; cc--)


}//bool ClosePosition()




bool ClosePosition()
{
   ForceClose = false;
   
   for (int cc = OrdersTotal() - 1; cc >= 0; cc--)
   {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;
      if (OrderMagicNumber() != MagicNumber) continue;
      
      if (OrderMagicNumber() == MagicNumber && OrderSymbol() == Symbol() )
      {
         bool result = OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 1000, Red);
         if (!result) ForceClose = true;
         if (result) cc++;
      }//if (OrderMagicNumber() != MagicNumber && OrderSymbol() == Symbol() )
      
   
   }//for (int cc = OrdersTotal() - 1; cc >= 0; cc--)


}//bool ClosePosition()

bool AreBuysAllInProfit()
{
   if (OrdersTotal() == 0) return(true);
   
   for (int cc = OrdersTotal() - 1; cc >= 0; cc--)
   {
      if (!OrderSelect(cc, SELECT_BY_POS, MODE_TRADES) ) continue;
      if (OrderMagicNumber() != MagicNumber) continue;
      if (OrderSymbol() != Symbol() ) continue;
      
      if (OrderProfit() < 0 && OrderType() == OP_BUY) return(false);
   }//for (int cc = OrdersTotal() - 1; cc >= 0; cc--)
   
   
   return(true);

}//bool (AreBuysAllInProfit()

bool AreSellsAllInProfit()
{
   if (OrdersTotal() == 0) return(true);
   
   for (int cc = OrdersTotal() - 1; cc >= 0; cc--)
   {
      if (!OrderSelect(cc, SELECT_BY_POS, MODE_TRADES) ) continue;
      if (OrderMagicNumber() != MagicNumber) continue;
      if (OrderSymbol() != Symbol() ) continue;
      
      if (OrderProfit() < 0 && OrderType() == OP_SELL) return(false);
   }//for (int cc = OrdersTotal() - 1; cc >= 0; cc--)
   
   
   return(true);

}//bool AreSellsAllInProfit()

bool CheckTradingTimes()
{
   int hour = TimeHour(TimeLocal() );
   
   if (end_hourm < start_hourm)
	{
		end_hourm += 24;
	}
	

	if (end_houre < start_houre)
	{
		end_houre += 24;
	}
	
	bool ok2Trade = true;
	
	ok2Trade = (hour >= start_hourm && hour <= end_hourm) || (hour >= start_houre && hour <= end_houre);

	// adjust for past-end-of-day cases
	// eg in AUS, USDJPY trades 09-17 and 22-06
	// so, the above check failed, check if it is because of this condition
	if (!ok2Trade && hour < 12)
	{
 		hour += 24;
		ok2Trade = (hour >= start_hourm && hour <= end_hourm) || (hour >= start_houre && hour <= end_houre);		
		// so, if the trading hours are 11pm - 6am and the time is between  midnight to 11am, (say, 5am)
		// the above code will result in comparing 5+24 to see if it is between 23 (11pm) and 30(6+24), which it is...
	}


   // check for end of day by looking at *both* end-hours

   if (hour >= MathMax(end_hourm, end_houre))
   {      
      ok2Trade = false;
   }//if (hour >= MathMax(end_hourm, end_houre))

   return(ok2Trade);

}//bool CheckTradingTimes()


double RSI(int tf)
{
   double digits = MarketInfo(NULL,MODE_DIGITS);
   double RsiVal = NormalizeDouble( (iRSI(NULL, tf, RSIperiod, RSIprice, RSIshift)), digits+4);
   
   return(RsiVal);
   
}//End double GetRsi(int tf, int period, int ap, int shift)


double RSIMA(int tf)
{  
   double digits = MarketInfo(NULL, MODE_DIGITS);
  
  //Returns the sma (3) of the Rsi(8)
  
   double RsiMa = NormalizeDouble( iRSI(NULL, tf, RSIperiod, PRICE_CLOSE, MAshift), digits+4);
   for (int cc = 1 + MAshift; cc <= 2 + MAshift; cc++)
   {
      double rv = NormalizeDouble( iRSI(NULL, tf, RSIperiod, PRICE_CLOSE, cc), digits+4);
      RsiMa+= rv;   
   }//for (int cc = 1; cc <= 3; cc++)
   RsiMa/= 3;
   
   return(RsiMa);

}



string GetTREND()
{

trend = none;

if (
     (RSI(tf_5) > RSIMA(tf_5)) &&
     (RSI(tf_4) > RSIMA(tf_4)) &&
     (RSI(tf_3) > RSIMA(tf_3)) &&
     (RSI(tf_2) > RSIMA(tf_2)) &&
     (RSI(tf_1) > RSIMA(tf_1))
   )
     trend = up;

if (
     (RSI(tf_5) < RSIMA(tf_5)) &&
     (RSI(tf_4) < RSIMA(tf_4)) &&
     (RSI(tf_3) < RSIMA(tf_3)) &&
     (RSI(tf_2) < RSIMA(tf_2)) &&
     (RSI(tf_1) < RSIMA(tf_1))
   )
     trend = down;

}



//+------------------------------------------------------------------+
//| expert Exist function                                            |
//+------------------------------------------------------------------+

bool Exist(int orderkind)
  {
    bool Found = false;
    for(int c = 0; c < OrdersTotal(); c++)
      {
        if(OrderSelect(c,SELECT_BY_POS,MODE_TRADES))
          {
            if ( OrderMagicNumber() == MagicNumber && 
                 OrderType() == orderkind && 
                 OrderComment() == TradeComment &&
                 OrderOpenTime() >= Time[0]
                )
               
              {
                Found = true;
              }
          }
      }
    return(Found);
  }






//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
{
//----

   GetTREND();
   GetPreviousBarDirection();
   
   if (trend != none) RobotStopped = false;
   
   if (ForceClose)
   {
      ForceClose = ClosePosition();
      return;   
   }//if (ForceClose)
   
   upl = 0;
   OpenTrades = 0;
   ForceClose = false;
   
   if (OrdersTotal() > 0)
   {
      CountOpenTrades();//Calculates basket upl
      double pt;//Profit target
     
      if (OpenTrades == 1 && SingleTradeProfitTarget > 0) pt = SingleTradeProfitTarget;
      else pt = ProfitTarget;
      
      if (upl >= pt)
      {
         ForceClose = ClosePosition();
         RobotStopped = true;
         return;
      }//if (upl >= ProfitTarget)
      
      //Close all label moved
      
      if (upl > 0 && trend == none)
      {
         ForceClose = ClosePosition();
         RobotStopped = true;
         return;
      }
      
      
 /*
      if ( (trend == up && CandleDirection == up) )
      {
         ForceClose = CloseOrderGroup(1);
         return;
      }
   
      if ( (trend == down && CandleDirection == down) )
      {
         ForceClose = CloseOrderGroup(0);
         return;
      }
*/
   
      if (OpenTrades > 0)
      {
         double labelx = ObjectGet(closelabelname, OBJPROP_XDISTANCE);
         double labely = ObjectGet(closelabelname, OBJPROP_YDISTANCE);
         if (labelx != CloseButtonX || labely != CloseButtonY)
         {
           ForceClose = ClosePosition();
           ObjectSet(closelabelname, OBJPROP_XDISTANCE, CloseButtonX);
           ObjectSet(closelabelname, OBJPROP_YDISTANCE, CloseButtonY);
           return;           
         } //if (BasketPipsProfit >= ProfitTarget) 
      }//if (OpenTrades > 0)
      
   }//if (OrdersTotal() > 0)
   
   
   /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   //Trading times
   if (OpenTrades == 0)
   {      
      bool TradeTimeOk = CheckTradingTimes();
      if (!TradeTimeOk)
      {
         Comment("Outside trading hours\nstart_hourm-end_hourm: ", start_hourm, "-",end_hourm, "\nstart_houre-end_houre: ", start_houre, "-",end_houre);
         return;
      }//if (hour < start_hourm)
      
      //Friday stop hour
      int d = TimeDayOfWeek(TimeLocal() );
      if (d == 5 && TimeHour(TimeLocal()) >= FridayStopHour && FridayStopHour > -1)
      {
         Comment(Gap + "Past the Friday stop trading hour of " + FridayStopHour);
         return;
      }//if (d == 5 && TimeHour(TimeLocal()) >= FridayStopHour)
      
      //Saturday stop hour
      if (d == 6 && TimeHour(TimeLocal()) >= SaturdayStopHour && SaturdayStopHour > -1)
      {
         Comment(Gap + "Past the Saturday stop trading hour of " + SaturdayStopHour);
         return;
      }//if (d == 5 && TimeHour(TimeLocal()) >= FridayStopHour)
      
   }//if (OPenTrades == 0)
   
   /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   //Stop/start labels
    labelx = ObjectGet(stoplabelname, OBJPROP_XDISTANCE);
    labely = ObjectGet(stoplabelname, OBJPROP_YDISTANCE);
    if (labelx != StopButtonX || labely != StopButtonY)
    {
      Alert("Robot will continue to monitor the basket for closure and appropriate trades. Will not start a new basket.");
      RobotStopped = true;
      ObjectSet(stoplabelname, OBJPROP_XDISTANCE, StopButtonX);
      ObjectSet(stoplabelname, OBJPROP_YDISTANCE, StopButtonY);
    } //if (labelx != StopButtonX || labely != StopButtonY) 

      
    labelx = ObjectGet(startlabelname, OBJPROP_XDISTANCE);
    labely = ObjectGet(startlabelname, OBJPROP_YDISTANCE);
    if (labelx != StartButtonX || labely != StartButtonY)
    {
      Alert("Robot has re-started");
      RobotStopped = false;
      ObjectSet(startlabelname, OBJPROP_XDISTANCE, StartButtonX);
      ObjectSet(startlabelname, OBJPROP_YDISTANCE, StartButtonY);
    } //if (labelx != StopButtonX || labely != StopButtonY) 
    
    if (RobotStopped && OpenTrades == 0)
    {
      Comment(Gap + "Robot is stopped");
      return;
    }//if (RobotStopped && OPenTrades == 0)
    
    
   /////////////////////////////////////////////////////////////////////////////////////////////////////////////////

   DisplayUserFeedback();
   
//if (OldBars != Bars)
   {

//      OldBars = Bars;
      //No need to send a second trade if first one is in profit
      if (OpenTrades == 1)
      {
         if (OrderSelect(TicketNo, SELECT_BY_TICKET) && OrderCloseTime() == 0 && OrderProfit() > 0) return;
      }//if (OPenTrades == 1)

      if (!UseTrend) trend = none;
      if (UseTrend) GetTREND();
           
      GetPreviousBarDirection();
      
      double SendLot = Lot;

      if (CandleDirection == up)
      {
 //        if (!UseTrend) trend = up;  //&& OpenTrades > 0
 //        if (trend == none) trend = up;
         if ( !Exist(0) && trend == up)  //AreBuysAllInProfit() &&   
         {
            if (UseTrend && trend == up) SendLot = Lot * WithTrendLotMultiplier;
 //          if (OpenTrades == 1 && upl > 0 && SingleTradeProfitTarget > 0) return;
            RefreshRates();
            while(IsTradeContextBusy() ) Sleep(10);
            int ticket = OrderSend(Symbol(), OP_BUY, SendLot, Ask, 0, 0, 0, TradeComment, MagicNumber, 0, Green); 
         }//if (AreBuysAllInProfit())         
      }//if (CandleDirection == up)

      if (CandleDirection == down)
      {
//         if (!UseTrend) trend = down; //&& OpenTrades > 0
//         if (trend == none) trend = down;
         if (!Exist(1) && trend == down ) // AreSellsAllInProfit()  &&    
         {
            if (UseTrend && trend == down) SendLot = Lot * WithTrendLotMultiplier;
//          if (OpenTrades == 1 && upl > 0 && SingleTradeProfitTarget > 0) return;
            RefreshRates();
            while(IsTradeContextBusy() ) Sleep(10);
            ticket = OrderSend(Symbol(), OP_SELL, SendLot, Bid, 0, 0, 0, TradeComment, MagicNumber, 0, Red); 
         }//if (AreBuysAllInProfit())         
      }//if (CandleDirection == down)
      
   
   }//if (OldBars != Bars)
   
   
//----
   return(0);
}
//+------------------------------------------------------------------+