//+-------------------------------------------------------------------+
//|                                                        Aurora.mq4 |
//|                                  Copyright © 2009, Steve Hopwood  |
//|                              http://www.hopwood3.freeserve.co.uk  |
//+-------------------------------------------------------------------+
#property copyright "Copyright © 2009, 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  both "Both"
#define  none "No tradable trend"

//Round number
#define  highline "Next high round number"
#define  lowline "Next low round number"

/*



Matt Kennel has provided the code for bool O_R_CheckForHistory(int ticket). Cheers Matt, You are a star.



Code for adding debugging Sleep
Alert("G");
int x = 0;
while (x == 0) Sleep(100);

FUNCTIONS LIST
int init()
int start()

----Trading----

void LookForTradingOpportunities()
   
bool IsTradingAllowed()
bool SendSingleTrade(int type, string comment, double lotsize, double price, double stop, double take)
bool DoesTradeExist()
bool CheckTradingTimes()
double CalculateLotSize(double price1, double price1)
void ShouldTradeClose()
void CalculateDailyResult()
void CalculatePipsProfit()
double CalculateLotSize()
void CalculateMarketDistanceFromAA()

----Trade direction----
void DrawLines()
void GetPivot()
void DrawPivot(double pivot)


----Matt's Order Reliable library code
bool O_R_CheckForHistory(int ticket) Cheers Matt, You are a star.
void O_R_Sleep(double mean_time, double max_time)

----Indicator readings----
void ReadIndicatorValues()
void CalculateAverageCandleLength()
double GetAa(int tf, int price, int period, int mashift, int method, int buffer, int shift)
void GetCandleRange()

----BIG NUMBERS MODULE----
void GetNextRoundNumbers()
void DrawLines(string name, double price, color col, int style, int width)
void DeleteLines()


*/

extern string  gen="----General inputs----";
extern double  Lot=0.1;//Leave at zero for the bot to calculate lot size by risk
extern int     StopLoss=5;
extern int     TakeProfit=5;
extern int     MagicNumber=29885;
extern string  TradeComment="M1 Scalper";
extern bool    CriminalIsECN=false;
extern double  MaxSpread=20;

extern string  mi="====Martingale inputs----";
extern bool    UseMartingale=true;
extern double  MartingaleLotMultiplier=2;
extern double  MaxLotsAllowed=6.4;

extern string  aal="----All averages inputs----";
extern bool    UseAA=true;
extern int     TimeFrame    =  0;
extern int     Price        =  0;
extern int     MA_Period    = 14;
extern int     MA_Shift     =  0;
extern int     MA_Method    =  0;
extern int     CandleShift  =  0;

extern string  cri="----Candle Range inputs----";
extern int     MaxCandleRange=5;
extern int     MinimumCandleRange=0;
extern int     MaxPipsFromAA=7;

extern string  lcs="Round number lines";
extern bool    UseRoundNumberFilter=true;
extern color   BuyLineColour=Yellow;
extern color   SellLineColour=Yellow;

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  mis="----Odds and ends----";
extern int     DisplayGapSize=30;

//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 */

//Trading variables
int            TicketNo, OpenTrades;
bool           CanTradeThisPair;//Will be false when this pair fails the currency can only trade twice filter, or the balanced trade filter
bool           BuyOpen, SellOpen;
string         direction;
string         swing;
bool           TradeExists;
int            LossTrades, WinTrades;
double         OverallProfit;
double         PipsProfit;
double         MarketDistance;

//All Averages
double         AaVal, AaUp, AaDown;//Buffers 0 (val) 1 (up) and 3 (down)

//PwR
string         trend;

//Candle range
double         PrevCandleRange;
double         ConvertedCandleRange;//For entry, tp/sl purposes


//Margin status display
bool           EnoughMargin;
string         MarginMessage;

//Round numbers
double         RoundNumberHigh, RoundNumberLow;

//Pending price inputs. Keeps things hidden from the crims
bool           PendingBuy, PendingSell;
double         PendingPrice, PendingStop, PendingTake;
datetime       PendingTime;
double         PendingCandleRange;
double         HiddenStopLoss, HiddenTakeProfit, HiddenBreakEven;//For the management functions

//Misc
string         Gap, ScreenMessage;
int            OldBars;
string         PipDescription=" pips";
bool           ForceTradeClosure;
bool           InvalidStopError;//For dealing with invalid stops

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 );
   /*
   //Code for time to bar-end display from Candle Time by Nick Bilak
   double i;
   int m,s,k;
   m=Time[0]+Period()*60-CurTime();
   i=m/60.0;
   s=m%60;
   m=(m-m%60)/60;
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, m + " minutes " + s + " seconds left to bar end", NL);
   */
      
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);      
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Lot size: ", Lot, " (Criminal's minimum lot size: ", MarketInfo(Symbol(), MODE_MINLOT), ")", NL);
   if (UseMartingale) ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Using Martingale. Multiplier is ", MartingaleLotMultiplier,  NL);
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Take profit: ", TakeProfit, PipDescription,  NL);
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Stop loss: ", StopLoss, PipDescription,  NL);
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Magic number: ", MagicNumber, NL);
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Trade comment: ", TradeComment, NL);
   if (CriminalIsECN) ScreenMessage = StringConcatenate(ScreenMessage,Gap, "CriminalIsECN = true", NL);
   else ScreenMessage = StringConcatenate(ScreenMessage,Gap, "CriminalIsECN = false", NL);
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "MaxSpread = ", MaxSpread, ": Spread = ", MarketInfo(Symbol(), MODE_SPREAD), NL, 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

   ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);      
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Results today. Wins: ", WinTrades, ": Losses ", LossTrades,
                                     ": P/L ", DoubleToStr(OverallProfit, 2), NL);
   
   if (TicketNo > -1) ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Open trade pips: ", PipsProfit, NL);
   
   
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Previous candle range: ", PrevCandleRange, " pips", NL);
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "AA value ", AaVal, ": Trend is ", trend, NL);
   int pp = MaxPipsFromAA;
   if (Digits == 3 || Digits == 5) pp/= 10;
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Market is ", MarketDistance, " pips away from AA. Maximum allowed is ", pp, " pips.", NL);
   
   
   
   if (UseRoundNumberFilter)
   {   
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);
      ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Next high round number = ", DoubleToStr(RoundNumberHigh, Digits), NL);
      ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Next low round number = ", DoubleToStr(RoundNumberLow, Digits), NL);
   }//   if (UseRoundNumberFilter)

   ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);

   
   if (MarginMessage != "") ScreenMessage = StringConcatenate(ScreenMessage,NL, Gap, MarginMessage, NL);

   
   Comment(ScreenMessage);


}//void DisplayUserFeedback()


//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
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";
   
   TakeProfit*= multiplier;
   StopLoss*= multiplier;
   MaxPipsFromAA*= multiplier;
   
   
   Gap="";
   if (DisplayGapSize > 0)
   {
      for (int cc=0; cc< DisplayGapSize; cc++)
      {
         Gap = StringConcatenate(Gap, " ");
      }   
   }//if (DisplayGapSize >0)
   

   //Reset CriminIsECN if crim is IBFX and the punter does not know or, like me, keeps on forgetting
   string name = TerminalCompany();
   int ispart = StringFind(name, "IBFX", 0);
   if (ispart < 0) ispart = StringFind(name, "Interbank FX", 0);
   if (ispart > -1) CriminalIsECN = true;   

   if (TradeComment == "") TradeComment = " ";
   OldBars = Bars;
   TicketNo = -1;
   ReadIndicatorValues();
   CalculateDailyResult();
   DisplayUserFeedback();
   
   //Call sq's show trades indi
   //iCustom(NULL, 0, "SQ_showTrades",Magic, 0,0);

   
//----
   return(0);
}
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
{
//----
   Comment("");
   DeleteHiLoLines();
   
//----
   return(0);
}



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;
   
   

   //Pending trades need to accommodate CriminalIsECN input
   if (!CriminalIsECN) int ticket = OrderSend(Symbol(),type, lotsize, price, slippage, stop, take, comment, MagicNumber, 0, col);
   
   //Is a 2 stage criminal - for market orders 
   if (CriminalIsECN)
   {
      bool result;
      int err;
      ticket = OrderSend(Symbol(),type, lotsize, price, slippage, 0, 0, comment, MagicNumber, 0, 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));
      if (err == 130) InvalidStopError = true;
      return(false);
   }//if (ticket < 0)  
   
   if (ticket == -1) return(true);
   
   TicketNo = ticket;
   //Make sure the trade has appeared in the platform's history to avoid duplicate trades.
   //My mod of Matt's code attempts to overcome the bastard crim's attempts to overcome Matt's code.
   bool TradeReturnedFromCriminal = false;
   while (!TradeReturnedFromCriminal)
   {
      TradeReturnedFromCriminal = O_R_CheckForHistory(ticket);
      if (!TradeReturnedFromCriminal)
      {
         Alert(Symbol(), " sent trade not in your trade history yet. Turn of this ea NOW.");
      }//if (!TradeReturnedFromCriminal)
   }//while (!TradeReturnedFromCriminal)
   
   //Got this far, so trade send succeeded
   return(true);
   
}//End bool SendSingleTrade(int type, string comment, double lotsize, double price, double stop, double take)

bool DoesTradeExist()
{
   
   TicketNo = -1;
   
   if (OrdersTotal() == 0) return(false);
   
   for (int cc = OrdersTotal() - 1; cc >= 0 ; cc--)
   {
      if (!OrderSelect(cc,SELECT_BY_POS)) continue;
      
      if (OrderMagicNumber()==MagicNumber && OrderSymbol() == Symbol() )      
      {
         TicketNo = OrderTicket();
         return(true);         
      }//if (OrderMagicNumber()==MagicNumber && OrderSymbol() == Symbol() )      
   }//for (int cc = OrdersTotal() - 1; cc >= 0 ; cc--)

   return(false);

}//End bool DoesTradeExist()

double CalculateLotSize()
{

   //Calculate Martingale lot size

   if (!UseMartingale) return(Lot);
   
   
   //Find most recent trade
   if (OrdersHistoryTotal() == 0) return(Lot);
   double SendLots = Lot;
   
   for (int cc = OrdersHistoryTotal() - 1; cc >= 0; cc--)
   {
      if (!OrderSelect(cc, SELECT_BY_POS, MODE_HISTORY) ) continue;
      if (OrderSymbol() != Symbol() ) continue;
      if (OrderMagicNumber() != MagicNumber) continue;
      if (OrderProfit() < 0)
      {
         double LotStep = MarketInfo(Symbol(),MODE_LOTSTEP);
         double digit = 0;
         if (LotStep == 0.1) digit = 1;
         if (LotStep == 0.01) digit = 2;
         SendLots = NormalizeDouble(OrderLots() * MartingaleLotMultiplier, digit);         
      }//if (OrderProfit() < 0)
      break;
   
   }//for (int cc = OrdersHistoryTotal() - 1; cc >= 0; cc--)
   
   //Check maximum lots allowed filter in the Martingale section
   if (SendLots > MaxLotsAllowed) SendLots = Lot;
   
   return(SendLots);

}//End double CalculateLotSize()


bool IsTradingAllowed()
{
   //Returns false if any of the filters should cancel trading, else returns true to allow trading
   
   //Maximum candle size
   if (PrevCandleRange > MaxCandleRange) return(false);
      
   //Minimum candle size
   if (PrevCandleRange < MinimumCandleRange) return(false);
      
   //Market maximum pips from AA
   if (MathAbs(Bid - AaVal) > (MaxPipsFromAA * Point) ) return(false);
      
   //Maximum spread
   if (MarketInfo(Symbol(), MODE_SPREAD) > MaxSpread) return(false);
 
   
   //Must be higher hi-lo in a rising market, and lower hi-lo in a falling market
   if (trend == up)
   {
      if (High[1] < High[2]) return(false);
      if (Low[1] < Low[2]) return(false);
   }//if (trend == up)
   
   
   if (trend == down)
   {
      if (High[1] > High[2]) return(false);
      if (Low[1] > Low[2]) return(false);
   }//if (trend == down)
   
   //Must not have closed a trade in the same candle as the trigger candle
   if (OrdersHistoryTotal() > 0)
   {
      for (int cc = OrdersHistoryTotal() - 1; cc >= 0; cc--)
      {
         if (!OrderSelect(cc, SELECT_BY_POS, MODE_HISTORY) ) continue;
         if (OrderSymbol() != Symbol() ) continue;
         if (OrderMagicNumber() != MagicNumber) continue;
         if (OrderCloseTime() < Time[1]) break;
         return(false);
      }//for (int cc = OrdersHistoryTotal() - 1; cc >= 0; cc--)
   }//if (OrdersHistoryTotal() > 0)
   

   return(true);


}//End bool IsTradingAllowed()



void LookForTradingOpportunities()
{

   RefreshRates();
   double price, stop, take;
   int type;
   bool SendTrade;
   
   //Check filters
   if (!IsTradingAllowed() ) return;//Includes the higher high/low check
   
   //Lot size
   //Calculate lotsize to cater for Martingale
   double SendLots = CalculateLotSize();
   
   //The market direction, candle size and higher/lower hi-lo have all been checked prior to reaching this point, so
   //all that is needed is to enter in the direction of the trend.
   
   RefreshRates();
   //Long 
   if (trend == up && Bid > AaVal)
   {
      price = Ask;
      take = NormalizeDouble(price + (TakeProfit * Point), Digits);
      stop = NormalizeDouble(price - (StopLoss * Point), Digits);
      type = OP_BUY;
      SendTrade = true;
   }//if (trend == up && Bid > AaVal)
   

   //Short
   if (trend == down && Bid < AaVal)
   {
      price = Bid;
      take = NormalizeDouble(price - (TakeProfit * Point), Digits);
      stop = NormalizeDouble(price + (StopLoss * Point), Digits);
      type = OP_SELL;
      SendTrade = true;
   }//if (trend == down && Bid < AaVal)
   

   if (SendTrade)
   {
      bool result = SendSingleTrade(type, TradeComment, SendLots, price, stop, take);
   }//if (SendTrade)


}//void LookForTradingOpportunities()


////////////////////////////////////////////////////////////////////////////////////////////////
//Indicator module




/*
double CalculateVolatility(int period, int LookBack)
{
   //Calculates the volatility of a pair based on an average of their movement over LookBack periods
   
   double pips;
   for (int cc = 1; cc < LookBack; cc++)
   {
      pips+= iHigh(NULL, period, cc) - iLow(NULL, period, cc);      
   }//for (int cc = 1; cc < LookBack; cc++)
   
   pips/= LookBack;//Average pips movement per day
   //Alert(pips);

   //Convert to pips
   int multiplier;
   if (Digits == 2) multiplier = 10;
   if (Digits == 3) multiplier = 100;
   if (Digits == 4) multiplier = 1000;
   if (Digits == 5) multiplier = 10000;
   
   pips*= multiplier;
   int rpips = pips;//Convert to a simple integer - all we need
   
   return(rpips);
   
}//End double CalculateVolatility(int period, int LookBack)
*/




//End Indicator module
////////////////////////////////////////////////////////////////////////////////////////////////


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()


//=============================================================================
//                           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)


///////////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////////
//INDICATOR MODULE


void GetCandleRange()
{
   //Reads the Candle_Range_in_pips indi for the size of the previous candle. I could hand-code this, but using
   //the indi saves me having to do the conversion of x.xxxx to an integer - something I usually bugger up
   
   int PipDivisor = 1;
   if (Digits == 3 || Digits == 5) PipDivisor = 10;
   PrevCandleRange = ((High[1] - Low[1]) / Point) / PipDivisor;
   
}//void GetCandleRange()

double GetAa(int tf, int price, int period, int mashift, int method, int buffer, int shift)
{

   return(iCustom(NULL, 0, "AllAverages_v2.1 cc", tf, price, period, mashift, method, buffer, shift));

}//End double GetAa(int tf, int price, int period, int mashift, int method, int buffer, int shift)

void ReadIndicatorValues()
{

   GetNextRoundNumbers();
   GetCandleRange();
   AaVal = GetAa(TimeFrame, Price, MA_Period, MA_Shift, MA_Method, 0, CandleShift);
   AaUp = GetAa(TimeFrame, Price, MA_Period, MA_Shift, MA_Method, 1, CandleShift);//Up buffer
   AaDown = GetAa(TimeFrame, Price, MA_Period, MA_Shift, MA_Method, 3, CandleShift);//Down buffer
   
   if (AaUp != EMPTY_VALUE) trend = up;
   if (AaDown != EMPTY_VALUE) trend = down;
   if (AaUp != EMPTY_VALUE && AaDown != EMPTY_VALUE) trend = both;//Happens at the turn

   
}//void ReadIndicatorValues()

//END INDICATOR MODULE
///////////////////////////////////////////////////////////////////////////////////////////////////////


///////////////////////////////////////////////////////////////////////////////////////////////////////
//BIG NUMBERS MODULE

void GetNextRoundNumbers()
{
   //Finds the nearest big numbers to the market price.
   //Saves these in RoundNumberHigh[index] and RoundNumberLow[index]
   
   RefreshRates();
   
   //Jpy pairs
   if (Digits == 2 || Digits == 3)
   {
      int price = Ask;//Truncates the quote
      RoundNumberLow = price;
      RoundNumberHigh = price + 1;
      
            
   }//if (Digits == 2 || Digits == 3)

   //non-Jpy pairs
   if (Digits == 4 || Digits == 5)
   {      
      string sprice = DoubleToStr(Ask, Digits);
      if (Ask >= 10) sprice = StringSubstr(sprice, 0, 5);       
      if (Ask < 10) sprice = StringSubstr(sprice, 0, 4);       
      RoundNumberLow = StrToDouble(sprice);
      RoundNumberHigh = RoundNumberLow + 0.01;      
   }//if (Digits == 4 || Digits == 5)

   

   //Draw the lines
   double hl, ll;//Hi-lo lines
   hl = ObjectGet(highline, OBJPROP_PRICE1);
   ll = ObjectGet(lowline, OBJPROP_PRICE1);
   
   if (Bid > hl || Bid < ll)
   {
      DeleteHiLoLines();
      DrawHiLoLines(highline, RoundNumberHigh, BuyLineColour, STYLE_SOLID, 1);
      DrawHiLoLines(lowline, RoundNumberLow, SellLineColour, STYLE_SOLID, 1);
   }//if (Bid > hl || Bid < ll)
   
   
}//End void GetNextRoundNumbers()

void DeleteHiLoLines()
{
   ObjectDelete(highline);
   ObjectDelete(lowline);
   
}//void DeleteLines()


void DrawHiLoLines(string name, double price, color col, int style, int width)
{

   ObjectDelete(name);
   

   ObjectCreate(name, OBJ_HLINE, 0, TimeCurrent(), price);
   ObjectSet(name, OBJPROP_COLOR, col);
   ObjectSet(name, OBJPROP_WIDTH, width);
   ObjectSet(name, OBJPROP_STYLE, style);
   ObjectSet(name, OBJPROP_RAY, false);
   
   
}//End void DrawLines(string name, double price, color col, int style, int type

//END BIG NUMBERS MODULE
///////////////////////////////////////////////////////////////////////////////////////////////////////

void CalculateDailyResult()
{
   //Calculate the no of winners and losers from today's trading. These are held in the history tab.

   LossTrades = 0;
   WinTrades = 0;
   OverallProfit = 0;
   
   int tot = OrdersHistoryTotal();
   if (tot == 0) return;
   
   for (int cc = 0; cc <= tot; cc++)
   {
      if (!OrderSelect(cc, SELECT_BY_POS, MODE_HISTORY) ) continue;
      if (OrderSymbol() != Symbol() ) continue;
      if (OrderMagicNumber() != MagicNumber) continue;
      
      OverallProfit+= (OrderProfit() + OrderSwap() + OrderCommission() );
      if (OrderProfit() > 0) WinTrades++;
      if (OrderProfit() < 0) LossTrades++;
      
      
   }//for (int cc = 0; cc <= tot -1; cc++)
   
   

}//End void CalculateDailyResult()

void CalculatePipsProfit()
{
   //Calculates the upl in pips of a currently open trade
   int PipDivisor = 1;
   if (Digits == 3 || Digits == 5) PipDivisor = 10;
   
   if (OrderType() == OP_BUY)
   {
      PipsProfit = ( (Bid - OrderOpenPrice() ) / Point)  / PipDivisor;
   }//if (OrderType() == OP_BUY)
   
   if (OrderType() == OP_SELL)
   {
      PipsProfit = ( (OrderOpenPrice() - Ask) / Point)  / PipDivisor;
   }//if (OrderType() == OP_SELL)
   

}//End void CalculatePipsProfit()

void CalculateMarketDistanceFromAA()
{

   //Calculates the distance of the market away from AA, and stores this in MarketDistance for display
   
   int PipDivisor = 1;
   if (Digits == 3 || Digits == 5) PipDivisor = 10;

   MarketDistance = NormalizeDouble(( MathAbs((Bid - AaVal)) / Point)  / PipDivisor, 1);

}//End void CalculateMarketDistanceFromAA()


//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
{
//----

   
   //Deal with the market moving outside current round number lines
   if(UseRoundNumberFilter && (Ask > RoundNumberHigh || Bid < RoundNumberLow)) GetNextRoundNumbers();

   //Calculate pips profit of current open trade
   if (OrderSelect(TicketNo, SELECT_BY_TICKET) && OrderCloseTime() == 0) CalculatePipsProfit();
   
   //Mop up after a trade has hit tp/sl
   if (TicketNo > -1)
   {
      if (!OrderSelect(TicketNo, SELECT_BY_TICKET) || OrderCloseTime() > 0) 
      {
         TicketNo = -1;
         CalculateDailyResult();
      }//if (!OrderSelect(TicketNo, SELECT_BY_TICKET) || OrderCloseTime() > 0) 
      
   }//if (TicketNo > -1)
   
   //Calculate distance of market from AA
   CalculateMarketDistanceFromAA();
   
   
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   //Trading times
   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)
  
   ///////////////////////////////////////////////////////////////////////////////////////////////         
   //Trading
   if (OldBars != Bars)
   {
      OldBars = Bars;
      ReadIndicatorValues();
      //Find open trades.   
      TradeExists = DoesTradeExist();
      if (TicketNo == -1)
      {   
         LookForTradingOpportunities();
      }//if (TicketNo == -1)
      CalculateDailyResult();
   }//if (OldBars != Bars)
   
   ///////////////////////////////////////////////////////////////////////////////////////////////      

   DisplayUserFeedback();
   
//----
   return(0);
}
//+------------------------------------------------------------------+