//+------------------------------------------------------------------+
//|                                                      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"
#define longlabelname "Long label"
#define shortlabelname "Short label"

extern int     DisplayGapSize=30;
extern double  Lot=0.1;
extern double  WithTrendLotMultiplier=1;
extern int     ProfitTarget=5;
extern int     SingleTradeProfitTarget=5;
extern bool    UsePrevHiLoStopLoss=false;
extern int     HiLoSLShift=1;//number of bars to read high or low value
extern bool    MoneyManagement = true;
extern double  RiskPercent = 2;
extern bool    UseEquity=false;
extern int     MaxPairAllowedTrades=30;
extern int     FkMinimumMarginPercent=100;
extern double  MaxSpread=120;
extern string  mtd="Orignal method=false or gspe's method=true";
extern bool    CounterTrade=false;
extern bool    UseEddMethod=false; 
extern bool    AllowBuyTrades=true;
extern bool    AllowSellTrades=true;
int            RiskPips=0; //for MM
int            LotsDecimalAllowed = 2;// for MM
extern int     MagicNumber=0;
extern string  TradeComment="";
extern bool    CriminalIsECN=true;
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=24;
extern string  fta="For the Aussies";
extern int     SaturdayStopHour=-1;
extern string  frtin="----Fractal inputs----";
extern bool    UseFractals=false;
extern string  frtin2="v1.04 = 2, v1.05 = 3";
extern int     FractalCandleLookBack=2; //
extern string  rsiin="----Rsi inputs----";
extern bool    UseRsi=true;
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 string  atrin="----ATR inputs----";
extern bool    UseATRTakeProfit=true;
extern int     ATRTf=60;
extern int     ATRPeriod=14;
extern int     ATRFactor=50;

int            OldBars, OpenTrades;
string         PipDescription=" pips";
string         CandleDirection;
string         Gap, ScreenMessage;
double         upl;//Basket profit/loss
bool           ForceClose=false;
bool           RobotStopped=false;
double         RsiVal;
double         ATRVal;
string         trend;
int            TicketNo;
double         pt,spt;//Profit target
double	      nDigits,nPoint;
int            multiplier;
int            slippage=3;
double         MarginLevelPercent;//Used to stop trading when this value falls below FkMinimumMarginPercent
bool           TradingAllowed;
double         UpFract,DnFract;

//Matt's O-R stuff
int 	         O_R_Setting_max_retries 	= 10;
double 	      O_R_Setting_sleep_time 		= 4.0; /* seconds */
double 	      O_R_Setting_sleep_max 		= 15.0; /* seconds */

//Labels
int CloseButtonX = 300, CloseButtonY = 25;
int StopButtonX = 300, StopButtonY = 75;
int StartButtonX = 300, StartButtonY = 125;
int LongButtonX = 300, LongButtonY = 175;
int ShortButtonX = 300, ShortButtonY = 225;

//+------------------------------------------------------------------+
//| 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(pt, 2), NL );
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Open trades = ", OpenTrades, ":   Upl = ", DoubleToStr(upl, 2), NL );
   if (MarketInfo(Symbol(), MODE_SPREAD) <= MaxSpread) ScreenMessage = StringConcatenate(ScreenMessage,Gap, "MaxSpread: ", MaxSpread, "  Spread is ", MarketInfo(Symbol(), MODE_SPREAD), NL);
   else ScreenMessage = StringConcatenate(ScreenMessage,Gap, "> MaxSpread: ", MaxSpread, " Spread is ", MarketInfo(Symbol(), MODE_SPREAD), 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, "Friday 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 );
   if (UseATRTakeProfit) ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Atr(", ATRPeriod, ") = ", ATRVal, NL );
   
   Comment(ScreenMessage);


}//void DisplayUserFeedback()


int init()
{
//----
   //Adapt to x digit criminals
   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(Digits == 2 || Digits == 4)   {nPoint = Point;		nDigits = 0;}
   if(Digits == 3 || Digits == 5)   {nPoint = Point*10;    nDigits = 1;}
   if(Digits == 6)                  {nPoint = Point*100;   nDigits = 2;} 
   if(Digits == 7)                  {nPoint = Point*1000;  nDigits = 3;}
   //+------------------------------------------------------------------+ 
   
   if (multiplier > 1) PipDescription = " points";
   
   RiskPips*=multiplier;


   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);

  //Create a long immediately label
  ObjectDelete(longlabelname);
  ObjectCreate(longlabelname, OBJ_LABEL, 0, 0, 0);
  ObjectSet(longlabelname, OBJPROP_XDISTANCE, LongButtonX);
  ObjectSet(longlabelname, OBJPROP_YDISTANCE, LongButtonY);
  ObjectSetText(longlabelname, "Execute Long Trade", 12, "Arial", Yellow);
  
  //Create a short immediately label
  ObjectDelete(shortlabelname);
  ObjectCreate(shortlabelname, OBJ_LABEL, 0, 0, 0);
  ObjectSet(shortlabelname, OBJPROP_XDISTANCE, ShortButtonX);
  ObjectSet(shortlabelname, OBJPROP_YDISTANCE, ShortButtonY);
  ObjectSetText(shortlabelname, "Execute Short Trade", 12, "Arial", Yellow);
  
   if (TradeComment == "") TradeComment = " ";
   //OldBars = Bars;
   GetPreviousBarDirection();
   if (UseRsi) GetRsi(RsiTf, RsiPeriod, RsiAppliedPrice, 0);
   if (UseATRTakeProfit)
   {
      GetATR(ATRTf, RsiPeriod, 0);
      if(ATRVal>0) pt=(ATRVal*ATRFactor/100)/nPoint/(AccountLeverage()*Lot);
      if(ATRVal>0) spt=(SingleTradeProfitTarget/ProfitTarget)*pt;
   }
   
   //--- Calcalate Initial Lot size 
   if (MoneyManagement == true) Lot=PositionSizeToOpen(RiskPips);
   
   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)

void GetATR(int tf, int period, int shift)
{
   ATRVal = (iATR(NULL, tf, period, shift) );
   
}//End double GetRsi(int tf, int period, int ap, int shift)

   //--- Calculate Lot size
double PositionSizeToOpen(int StopLossPips)
{
   double PositionSize;
   double riskDollars;
   double MinLots, MaxLots;
   
   if (MoneyManagement && StopLossPips > 0)
   {      
      if (UseEquity)
      {
         riskDollars = (AccountEquity()/100) * RiskPercent;
      }
      else
      {
         riskDollars = (AccountBalance()/100) * RiskPercent;
      }
      PositionSize = (riskDollars / StopLossPips) / (MarketInfo(Symbol(),MODE_TICKVALUE) * multiplier);
   }
   
   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());
      }
   }
   //Print("PosSize "+PositionSize);
   
   if (!MoneyManagement)
   {
      PositionSize = Lot;
   }
   
   MinLots=MarketInfo(Symbol(),MODE_MINLOT);
   MaxLots=MarketInfo(Symbol(),MODE_MAXLOT);
   
   if (PositionSize < MinLots)
   {
      PositionSize = MinLots;
   }
   if (PositionSize > MaxLots)
   {
      PositionSize = MaxLots;
   }
   PositionSize = NormalizeDouble(PositionSize,LotsDecimalAllowed);
   //Print("PosSize "+PositionSize);
   return (PositionSize);
}

//"Buy when price closes above the open price of previous down candle. Sell when price closes below the open price of previous up candle.
bool CheckPrices(string dir)
{
   int cc=1;
   bool PriceConfirmed=false;
   
   if (dir==up)
   {
      while(!PriceConfirmed)
      {
         if (Close[cc]<Open[cc]) PriceConfirmed=true;
         else cc++;
      }
      if (Close[0]>Open[cc]) return(true);
   }
   if (dir==down)
   {
      while(!PriceConfirmed)
      {
         if (Close[cc]>Open[cc]) PriceConfirmed=true;
         else cc++;
      }
      if (Close[0]<Open[cc]) return(true);
   }
   
   return(false);

}

bool IsTradingAllowed()
{
      
   //Maximum spread
   if (MarketInfo(Symbol(), MODE_SPREAD) > MaxSpread) return(false);

   //Calculate available margin
   if (AccountMargin() > 0)
   {
      MarginLevelPercent = NormalizeDouble(AccountEquity() / AccountMargin() * 100, 2);
      if (MarginLevelPercent < FkMinimumMarginPercent) return(false);
      
   }//if (OrdersTotal() > 0)

   //Check number of trades if >= to max the exit
   if (OpenTrades>=MaxPairAllowedTrades) return(false);
   
   //if got here the ok to trade
   return(true);   
}

bool SendSingleTrade(int type, string comment, double lotsize, double price, double stop, double take)
{
   
   
   //int slippage = 10;
   if (Digits == 3 || Digits == 5) slippage = 100;
   
   color col = Red;
   if (type == OP_BUY || type == OP_BUYSTOP) col = Green;
   
   int expiry = 0;
   //if (SendPendingTrades) expiry = TimeCurrent() + (PendingExpiryMinutes * 60);

   if (!CriminalIsECN) int ticket = OrderSend(Symbol(),type, lotsize, price, slippage, stop, take, comment, MagicNumber, expiry, col);
   
   
   //Is a 2 stage criminal
   if (CriminalIsECN)
   {
      bool result;
      int err;
      ticket = OrderSend(Symbol(),type, lotsize, price, slippage, 0, 0, comment, MagicNumber, expiry, col);
      if (ticket > 0)
      {
	     
	     if (take > 0 && stop > 0)
        {
           while(IsTradeContextBusy()) Sleep(100);
           result = OrderModify(ticket, OrderOpenPrice(), stop, take, OrderExpiration(), CLR_NONE);
           if (!result)
           {
               err=GetLastError();
               Print(Symbol(), " SL/TP  order modify failed with error(",err,"): ",ErrorDescription(err));               
           }//if (!result)			  
        }//if (take > 0 && stop > 0)
      
	     if (take != 0 && stop == 0)
        {
           while(IsTradeContextBusy()) Sleep(100);
           result = OrderModify(ticket, OrderOpenPrice(), OrderStopLoss(), take, OrderExpiration(), CLR_NONE);
           if (!result)
           {
               err=GetLastError();
               Print(Symbol(), " SL  order modify failed with error(",err,"): ",ErrorDescription(err));               
           }//if (!result)			  
        }//if (take == 0 && stop != 0)

        if (take == 0 && stop != 0)
        {
           while(IsTradeContextBusy()) Sleep(100);
           result = OrderModify(ticket, OrderOpenPrice(), stop, OrderTakeProfit(), OrderExpiration(), CLR_NONE);
           if (!result)
           {
               err=GetLastError();
               Print(Symbol(), " SL  order modify failed with error(",err,"): ",ErrorDescription(err));               
           }//if (!result)			  
        }//if (take == 0 && stop != 0)

      }//if (ticket > 0)
        
      
      
   }//if (CriminalIsECN)
   
   //Error trapping for both
   if (ticket < 0)
   {
      string stype;
      if (type == OP_BUY) stype = "OP_BUY";
      if (type == OP_SELL) stype = "OP_SELL";
      if (type == OP_BUYLIMIT) stype = "OP_BUYLIMIT";
      if (type == OP_SELLLIMIT) stype = "OP_SELLLIMIT";
      if (type == OP_BUYSTOP) stype = "OP_BUYSTOP";
      if (type == OP_SELLSTOP) stype = "OP_SELLSTOP";
      err=GetLastError();
      Alert(Symbol(), " ", stype," order send failed with error(",err,"): ",ErrorDescription(err));
      Print(Symbol(), " ", stype," order send failed with error(",err,"): ",ErrorDescription(err));
      return(false);
   }//if (ticket < 0)  
   
   
   TicketNo = ticket;
   //Make sure the trade has appeared in the platform's history to avoid duplicate trades
   O_R_CheckForHistory(ticket); 
   
   //Got this far, so trade send succeeded
   return(true);
   
}//End bool SendSingleTrade(int type, string comment, double lotsize, double price, double stop, double take)
//=============================================================================
//                           O_R_CheckForHistory()
//
//  This function is to work around a very annoying and dangerous bug in MT4:
//      immediately after you send a trade, the trade may NOT show up in the
//      order history, even though it exists according to ticket number.
//      As a result, EA's which count history to check for trade entries
//      may give many multiple entries, possibly blowing your account!
//
//  This function will take a ticket number and loop until
//  it is seen in the history.
//
//  RETURN VALUE:
//     TRUE if successful, FALSE otherwise
//
//
//  FEATURES:
//     * Re-trying under some error conditions, sleeping a random
//       time defined by an exponential probability distribution.
//
//     * Displays various error messages on the log for debugging.
//
//  ORIGINAL AUTHOR AND DATE:
//     Matt Kennel, 2010
//
//=============================================================================
bool O_R_CheckForHistory(int ticket)
{
   //My thanks to Matt for this code. He also has the undying gratitude of all users of my trading robots
   
   int lastTicket = OrderTicket();

   int cnt = 0;
   int err = GetLastError(); // so we clear the global variable.
   err = 0;
   bool exit_loop = false;
   bool success=false;

   while (!exit_loop) {
      /* loop through open trades */
      int total=OrdersTotal();
      for(int c = 0; c < total; c++) {
         if(OrderSelect(c,SELECT_BY_POS,MODE_TRADES) == true) {
            if (OrderTicket() == ticket) {
               success = true;
               exit_loop = true;
            }
         }
      }
      if (cnt > 3) {
         /* look through history too, as order may have opened and closed immediately */
         total=OrdersHistoryTotal();
         for(c = 0; c < total; c++) {
            if(OrderSelect(c,SELECT_BY_POS,MODE_HISTORY) == true) {
               if (OrderTicket() == ticket) {
                  success = true;
                  exit_loop = true;
               }
            }
         }
      }

      cnt = cnt+1;
      if (cnt > O_R_Setting_max_retries) {
         exit_loop = true;
      }
      if (!(success || exit_loop)) {
         Print("Did not find #"+ticket+" in history, sleeping, then doing retry #"+cnt);
         O_R_Sleep(O_R_Setting_sleep_time, O_R_Setting_sleep_max);
      }
   }
   // Select back the prior ticket num in case caller was using it.
   if (lastTicket >= 0) {
      OrderSelect(lastTicket, SELECT_BY_TICKET, MODE_TRADES);
   }
   if (!success) {
      Print("Never found #"+ticket+" in history! crap!");
   }
   return(success);
}//End bool O_R_CheckForHistory(int ticket)

//=============================================================================
//                              O_R_Sleep()
//
//  This sleeps a random amount of time defined by an exponential
//  probability distribution. The mean time, in Seconds is given
//  in 'mean_time'.
//  This returns immediately if we are backtesting
//  and does not sleep.
//
//=============================================================================
void O_R_Sleep(double mean_time, double max_time)
{
   if (IsTesting()) {
      return;   // return immediately if backtesting.
   }

   double p = (MathRand()+1) / 32768.0;
   double t = -MathLog(p)*mean_time;
   t = MathMin(t,max_time);
   int ms = t*1000;
   if (ms < 10) {
      ms=10;
   }
   Sleep(ms);
}//End void O_R_Sleep(double mean_time, double max_time)

//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
{
//----
   
   if (ForceClose)
   {
      ForceClose = ClosePosition();
      return;   
   }//if (ForceClose)
   
   TradingAllowed = IsTradingAllowed();
   
   //--- Calcalate Initial Lot size 
   if (MoneyManagement == true) Lot=PositionSizeToOpen(RiskPips);
      
   upl = 0;
   OpenTrades = 0;
   ForceClose = false;
   
   //if use Rsi
   if (UseRsi) GetRsi(RsiTf, RsiPeriod, RsiAppliedPrice, 0); 
   
   //If use ATR the set take profit
   if(UseATRTakeProfit)
   {
      GetATR(ATRTf, ATRPeriod, 0);
         
      if(ATRVal>0) pt=(ATRVal*ATRFactor/100)/nPoint/(AccountLeverage()*Lot);
      if(ATRVal>0) spt=(SingleTradeProfitTarget/ProfitTarget)*pt;
   }
   else
   {
      pt=ProfitTarget;
      spt=SingleTradeProfitTarget;
   }
   //Print("pt "+pt+", spt "+spt+" point "+nPoint);
   
   if (OrdersTotal() > 0)
   {
      CountOpenTrades();//Calculates basket upl
      if (OpenTrades == 1 && spt > 0) pt = spt;
      //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) 
    
    //EXECUTE Long
    labelx = ObjectGet(longlabelname, OBJPROP_XDISTANCE);
    labely = ObjectGet(longlabelname, OBJPROP_YDISTANCE);
    if (labelx != LongButtonX || labely != LongButtonY)
    {
      Alert("Robot has sent a Long Trade");
      RobotStopped = false;
      RefreshRates();
      bool result = SendSingleTrade(OP_BUY, TradeComment, Lot, Bid, 0, 0);
      ObjectSet(longlabelname, OBJPROP_XDISTANCE, LongButtonX);
      ObjectSet(longlabelname, OBJPROP_YDISTANCE, LongButtonY);
    } //if (labelx != LongButtonX || labely != LongButtonY)

    //EXECUTE Short
    labelx = ObjectGet(shortlabelname, OBJPROP_XDISTANCE);
    labely = ObjectGet(shortlabelname, OBJPROP_YDISTANCE);
    if (labelx != ShortButtonX || labely != ShortButtonY)
    {
      Alert("Robot has sent a Short Trade");
      RobotStopped = false;
      RefreshRates();
      result = SendSingleTrade(OP_SELL, TradeComment, Lot, Ask, 0, 0);
      ObjectSet(shortlabelname, OBJPROP_XDISTANCE, ShortButtonX);
      ObjectSet(shortlabelname, OBJPROP_YDISTANCE, ShortButtonY);
    } //if (labelx != ShortButtonX || labely != ShortButtonY)
        
    if (RobotStopped && OpenTrades == 0)
    {
      Comment(Gap + "Robot is stopped");
      return;
    }//if (RobotStopped && OPenTrades == 0)
    
    
   /////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	DisplayUserFeedback();
	
	if (!TradingAllowed) return;
	
	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 (UseFractals)
		{
		   UpFract = iFractals(NULL, 0, MODE_UPPER, FractalCandleLookBack);
		   DnFract = iFractals(NULL, 0, MODE_LOWER, FractalCandleLookBack);
		}
   
		double SendLot = Lot;
		double SL =0;		
		double price;
		
		if (UsePrevHiLoStopLoss)
		{
         int StopLevel = MarketInfo(Symbol(), MODE_STOPLEVEL) + MarketInfo(Symbol(), MODE_SPREAD);
         if (trend==up)
         {
            SL=Low[HiLoSLShift];
            if (MathAbs(SL-Bid)/Point < StopLevel) SL = NormalizeDouble(Bid+(StopLevel*Point),Digits);
         }
         if (trend==down)
         { 
            SL=High[HiLoSLShift];
		      if (MathAbs(SL-Ask)/Point < StopLevel) SL = NormalizeDouble(Ask-(StopLevel*Point),Digits);
		   } 
		}
		
		//Check for trades
      bool SendBuy = BuyTrigger();
      bool SendSell = SellTrigger();
		int  type,col;
			
		if (SendBuy)
		{
		    if (CounterTrade)
			 {
			      price=Bid;
			      type=OP_SELL;
			 }
			 else
			 {
			      price=Ask;
		         type=OP_BUY;
		    }
		    
			 if (UseRsi && trend == up && OpenTrades > 0) SendLot = Lot * WithTrendLotMultiplier;
			 if (OpenTrades == 1 && upl > 0 && spt > 0) return;
			 RefreshRates();  
			 result = SendSingleTrade(type, TradeComment, SendLot, price, SL, 0);
		}	//if (AreBuysAllInProfit())         

		if (SendSell)
		{
	        if (CounterTrade)
			  {
			      price=Ask;
			      type=OP_BUY;
			  }
			  else
			  {
			      price=Bid;
		         type=OP_SELL;
		     }
		
			  if (UseRsi && trend == down && OpenTrades > 0) SendLot = Lot * WithTrendLotMultiplier;
			  if (OpenTrades == 1 && upl > 0 && spt > 0) return;
			  RefreshRates();
			  result = SendSingleTrade(type, TradeComment, SendLot, price, SL, 0);
		}	//if (AreBuysAllInProfit())         
	}//if (OldBars != Bars)
   
   
//----
   return(0);
}

//+------------------------------------------------------------------+

bool BuyTrigger()
{
   //Called by Start().
   //Returns true if buy conditions are met, else false
   
   //check if allowed to send trade
   if(!AllowBuyTrades && !CounterTrade) return(false);
   if(!AllowSellTrades && CounterTrade) return(false);
   
   //Original method v1
   if (!UseFractals && !CounterTrade && !UseEddMethod)
   {
      GetPreviousBarDirection();
   
      if (CandleDirection == up && AreBuysAllInProfit() && trend == up) return(true);
   }
   //gspe method v1.01
   if (!UseFractals && CounterTrade && !UseEddMethod)
   {
      GetPreviousBarDirection();
   
      if (CandleDirection == up && AreBuysAllInProfit() && trend == up) return(true);
   }
   
   //gspe method v1.04
   if (UseFractals && CounterTrade && !UseEddMethod)
   {
      if (UpFract != 0 && AreBuysAllInProfit()) return(true);
   }
   
   //edd method ct
   if (UseFractals && CounterTrade && UseEddMethod)
   {
   	if (AreBuysAllInProfit() && CheckPrices(up) && UpFract != 0) return(true);
   }	

   //edd method
   if (UseFractals && !CounterTrade && UseEddMethod)
   {
   	if (AreBuysAllInProfit() && CheckPrices(up) && DnFract != 0) return(true);
   }
   	
	//if made if here no buy trades
	return(false);
}

bool SellTrigger()
{
   //Called by Start().
   //Returns true if sell conditions are met, else false
   //check if allowed to send trade
   if(!AllowBuyTrades && !CounterTrade) return(false);
   if(!AllowSellTrades && CounterTrade) return(false);
   
   //Original method v1
   if (!UseFractals && !CounterTrade && !UseEddMethod)
   {
      GetPreviousBarDirection();
   
      if (CandleDirection == down && AreSellsAllInProfit() && trend == down) return(true);
   }
   //gspe method v1.01
   if (!UseFractals && CounterTrade && !UseEddMethod)
   {
      GetPreviousBarDirection();
   
      if (CandleDirection == down && AreSellsAllInProfit() && trend == down) return(true);
   }
   
   //gspe method v1.04
   if (UseFractals && CounterTrade && !UseEddMethod)
   {
      if (DnFract != 0 && AreSellsAllInProfit()) return(true);
   }
   
   //edd method ct
   if (UseFractals && CounterTrade && UseEddMethod)
   {
   	if (AreSellsAllInProfit() && CheckPrices(down) && DnFract != 0) return(true);
   }	

   //edd method
   if (UseFractals && !CounterTrade && UseEddMethod)
   {
   	if (AreSellsAllInProfit() && CheckPrices(down) && UpFract != 0) return(true);
   }
   	
	//if made if here no buy trades
	return(false);

}