//+------------------------------------------------------------------+
//|                                                      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.01;
extern double  WithTrendLotMultiplier=1;
extern int     ProfitTarget=1;
extern int     SingleTradeProfitTarget=1;
extern int     MagicNumber=0;
extern string  TradeComment="";
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 = 8;
extern  int    end_hourm = 14;
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 string  rsiin="----Rsi inputs----";
extern bool    UseRsi=false;
extern int     RsiTf=1440;
extern int     RsiPeriod=20;
extern string  rsap="Applied price: 0=Close; 1=Open; 2=High";
extern string  rsap1="3=Low; 4=Median; 5=Typical; 6=Weighted";
extern int     RsiAppliedPrice=0;
extern int     SaturdayStopHour=-1;


int            OldBars, OpenTrades;
string         PipDescription=" pips";
string         CandleDirection;
string         Gap, ScreenMessage;
double         upl;//Basket profit/loss
bool           ForceClose=false;
bool           RobotStopped=false;
double         RsiVal;
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, "Lot: ", Lot, NL );
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Candle direction: ", CandleDirection, 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, "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);
   if (UseRsi) ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Rsi = ", RsiVal, ":  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 (UseRsi) GetRsi(RsiTf, RsiPeriod, RsiAppliedPrice, 0);
   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;
   

}//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 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, CLR_NONE);
         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()

void GetRsi(int tf, int period, int ap, int shift)
{
   RsiVal = (iRSI(NULL, tf, period, ap, shift) );
   
   trend = none;
   if (RsiVal > 55) trend = up;
   if (RsiVal < 45) trend = down;
   
}//End double GetRsi(int tf, int period, int ap, int shift)


//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
{
//----
   
   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();
         return;
      }//if (upl >= ProfitTarget)
      
      //Close all label moved
      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 (UseRsi) GetRsi(RsiTf, RsiPeriod, RsiAppliedPrice, 0);
      if (!UseRsi || OpenTrades > 0) trend = up;
      GetPreviousBarDirection();
      double SendLot = Lot;
      if (CandleDirection == up)
      {
         if (AreBuysAllInProfit() && trend == up)
         {
            if (UseRsi && trend == up && OpenTrades > 0) SendLot = Lot * WithTrendLotMultiplier;
            if (OpenTrades == 1 && upl > 0 && SingleTradeProfitTarget > 0) return;
            RefreshRates();
            while(IsTradeContextBusy() ) Sleep(100);
            int ticket = OrderSend(Symbol(), OP_SELL, SendLot, Bid, 0, 0, 0, TradeComment, MagicNumber, 0, Red); 
         }//if (AreBuysAllInProfit())         
      }//if (CandleDirection == up)

      if (CandleDirection == down)
      {
         if (!UseRsi || OpenTrades > 0) trend = down;
         if (AreSellsAllInProfit() && trend == down && OpenTrades > 0)
         {
            if (UseRsi && trend == down) SendLot = Lot * WithTrendLotMultiplier;
            if (OpenTrades == 1 && upl > 0 && SingleTradeProfitTarget > 0) return;
            RefreshRates();
            while(IsTradeContextBusy() ) Sleep(100);
            ticket = OrderSend(Symbol(), OP_BUY, SendLot, Ask, 0, 0, 0, TradeComment, MagicNumber, 0, Green);
         }//if (AreBuysAllInProfit())         
      }//if (CandleDirection == down)
      
   
   }//if (OldBars != Bars)
   
   
//----
   return(0);
}
//+------------------------------------------------------------------+