//+------------------------------------------------------------------+
//|   Ibuks Bread'nButter multi-pair auto-trader by SteveHopwood.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 stoplabelname "Stop label"
#define startlabelname "Start label"


/*
void LookForTradingOpportunities()
bool SendSingleTrade(string symbol, int type, string comment, double lotsize, double price, double stop, double take)
void Send_Buy_Limit_Trade(string symbol, int tf)
bool DoesTradeExist(string symbol, int tf)
double GetMa(string symbol, int tf, int period, int mashift, int method, int ap, int shift)
double CalculateTakeProfit(string symbol, int type, double price)
double CalculateStopLoss(string symbol, int type, double price)
void DeleteOrphanGlobals()
void UpdateFillPrices()
void LookForTradeClosures()


----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)

*/

extern string  gi="----General inputs----";
extern double  Lot=0.01;
extern int     TakeProfit = 30;
extern int     StopLoss = 100;
extern int     MagicNumber=0;
extern string  TradeComment="";
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	PairsToTrade = "EURUSD,GBPUSD,NZDUSD,USDCAD,USDCHF,USDJPY,GBPJPY,EURJPY,AUDJPY,NZDJPY,CADJPY,CHFJPY,GBPCHF,AUDCAD,AUDCHF,AUDNZD,AUDUSD,CADCHF,EURAUD,EURCAD,EURCHF,EURGBP,EURNZD";
//extern string	PairsToTrade = "EURUSD";
extern string	PeriodsToTrade = "H1,H4,D1";//,W1,MN"; // Time Frames to display are user defined
extern bool    AllowMultipleTimeFrameTrades=true;

extern string  mab="----EMA and Buffer inputs----";
extern int     BufferPips = 20;
extern int     MaPeriod=24;
extern int     MaMethod=MODE_EMA;
extern int     MaShift=0;
extern int     MaAppliedPrice=0;
extern string  mame="Method: 0=sma; 1=ema; 2=smma;  3=lwma";
extern string  maap="Applied price: 0=Close; 1=Open; 2=High";
extern string  maap1="3=Low; 4=Median; 5=Typical; 6=Weighted";

extern string  mis="----Odds and ends----";
extern int     DisplayGapSize=30;



//Pair extraction
int		NoOfPairs;				// Holds the number of pairs passed by the user via the inputs screen
int		NoOfPeriods;			// Holds the number of periods passed by the user via the inputs screen
string	TradePair[];			//Array to hold the pairs traded by the user
string	TradePeriod[];			//Array to hold the periods traded by the user
int		TradePeriodTF[];		//Array to hold the periods traded by the user
double TradeTrendDiffs[][5];	//Array to hold the pairs diffs from MA
color 	Trend[][5];	//Array to hold the pairs trend color
color 	TrendColor[5];	//Array to hold the trend colors
bool  	AlertSent[];

#define NOSIGNAL  0
#define ABOVEMA   1
#define BELOWMA   2
#define ABOVEBAND 3
#define BELOWBAND 4

int WindowNo = 0;

string objPrefix ;	// all objects drawn by this indicator will be prefixed with this
string buff_str ;	// all objects drawn by this indicator will be prefixed with this


//double pip;
int pipMult,pipMultTab[]={1,10,1,10,1,10,100}; // multiplier to convert pips to Points;

string _type[]= {"SMA","EMA","SMMA","LWMA"};

//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 */


//Trade TF holding globals
string         GvName;

//Trading
int            TicketNo;

//Misc
string         Gap, ScreenMessage;
int            OldGvBars, OldPriceUpdateBars;

//Labels
int StopButtonX = 350, StopButtonY = 100;
int StartButtonX = 350, StartButtonY = 150;

void DisplayUserFeedback()
{

   int cc;
   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, "Take profit in pips (EA will convert for x_digit crims): ", TakeProfit, NL);
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Stop loss in pips (EA will convert for x_digit crims): ", StopLoss, 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, "Criminal's minimum lot size: ", MarketInfo(Symbol(), MODE_MINLOT), NL, 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
   
   Comment(ScreenMessage);
}//void DisplayUserFeedback()


//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
{
//----
   int i, j;
	objPrefix = WindowExpertName();

//  pipMult = pipMultTab[Digits];
//  pip = Point * pipMult;

	//Extract the pairs traded by the user
	NoOfPairs = StringFindCount(PairsToTrade,",")+1;
	ArrayResize(TradePair, NoOfPairs);
	string AddChar = StringSubstr(Symbol(),6,4);
	StrPairToStringArray(PairsToTrade, TradePair, AddChar);

	NoOfPeriods = StringFindCount(PeriodsToTrade, ",")+1;
	ArrayResize(TradePeriod, NoOfPeriods);
	ArrayResize(TradePeriodTF, NoOfPeriods);
	StrToStringArray(PeriodsToTrade, TradePeriod);
	
	for(j=0; j<NoOfPeriods; j++)
	{
		TradePeriodTF[j] = StrToTF(TradePeriod[j]);	//this is for display Periods from topleft corner
		//TradePeriodTF[NoOfPeriods-j] = StrToTF(TradePeriod[j]);	//this is for display Periods from topright corner
	}
//----	
	ArrayResize(Trend, NoOfPairs);
	ArrayInitialize(Trend, NOSIGNAL);
	ArrayResize(TradeTrendDiffs, NoOfPairs);
	ArrayInitialize(TradeTrendDiffs, 0);

   Gap="";
   if (DisplayGapSize >0)
   {
      for (int cc=0; cc< DisplayGapSize; cc++)
      {
         Gap = StringConcatenate(Gap, " ");
      }   
   }//if (DisplayGapSize >0)

  //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);



//----
   return(0);
}
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
{
//----
   Comment("");   
	RemoveObjects(objPrefix);
	ObjectDelete(stoplabelname);
	ObjectDelete(startlabelname);
	
//----
   return(0);
}

//-------------------------------------------------------------------+
void RemoveObjects(string Pref)
//+------------------------------------------------------------------+
{   
	int i;
	string objname = "";

	for (i = ObjectsTotal(); i >= 0; i--)
	{
		objname = ObjectName(i);
		if (StringFind(objname, Pref, 0) > -1) ObjectDelete(objname);
	}
	return(0);
} // End void RemoveObjects(string Pref)

//+------------------------------------------------------------------+
int StringFindCount(string str, string str2)
//+------------------------------------------------------------------+
// Returns the number of occurrences of STR2 in STR
// Usage:   int x = StringFindCount("ABCDEFGHIJKABACABB","AB")   returns x = 3
{
  int c = 0;
  for (int i=0; i<StringLen(str); i++)
    if (StringSubstr(str,i,StringLen(str2)) == str2)  c++;
  return(c);
} // End int StringFindCount(string str, string str2)

//+------------------------------------------------------------------+
void StrPairToStringArray(string str, string &a[], string p_suffix, string delim=",")
//+------------------------------------------------------------------+
{
	int z1=-1, z2=0;
	for (int i=0; i<ArraySize(a); i++)
	{
		z2 = StringFind(str,delim,z1+1);
		a[i] = StringSubstr(str,z1+1,z2-z1-1) + p_suffix;
		if (z2 >= StringLen(str)-1)   break;
		z1 = z2;
	}
	return(0);
}

//+------------------------------------------------------------------+
void StrToStringArray(string str, string &a[], string delim=",")
//+------------------------------------------------------------------+
{
	int z1=-1, z2=0;
	for (int i=0; i<ArraySize(a); i++)
	{
		z2 = StringFind(str,delim,z1+1);
		a[i] = StringSubstr(str,z1+1,z2-z1-1);
		if (z2 >= StringLen(str)-1)   break;
		z1 = z2;
	}
	return(0);
}

//+------------------------------------------------------------------+
// Converts a timeframe string to its MT4-numeric value
// Usage:   int x=StrToTF("M15")   returns x=15
int StrToTF(string str)
//+------------------------------------------------------------------+
{
  str = StringUpper(str);
  str = StringTrimLeft(str);
  str = StringTrimRight(str);
  
  if (str == "M1")   return(1);
  if (str == "M5")   return(5);
  if (str == "M15")  return(15);
  if (str == "M30")  return(30);
  if (str == "H1")   return(60);
  if (str == "H4")   return(240);
  if (str == "D1")   return(1440);
  if (str == "W1")   return(10080);
  if (str == "MN")   return(43200);
  return(0);
}  

//+------------------------------------------------------------------+
// Converts any lowercase characters in a string to uppercase
// Usage:    string x=StringUpper("The Quick Brown Fox")  returns x = "THE QUICK BROWN FOX"
string StringUpper(string str)
//+------------------------------------------------------------------+
{
  string outstr = "";
  string lower  = "abcdefghijklmnopqrstuvwxyz";
  string upper  = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  for(int i=0; i<StringLen(str); i++)  {
    int t1 = StringFind(lower,StringSubstr(str,i,1),0);
    if (t1 >=0)  
      outstr = outstr + StringSubstr(upper,t1,1);
    else
      outstr = outstr + StringSubstr(str,i,1);
  }
  return(outstr);
}  

//+------------------------------------------------------------------+
void GetPairTrends(double &diffs[][], int &trend[][])
//+------------------------------------------------------------------+
{
	int i, j;
	double diff;
	
	for(i=0; i<NoOfPairs; i++)
	{
		if (iClose(TradePair[i], PERIOD_H1, 0) == 0) continue;
		for(j=0; j<NoOfPeriods; j++)
		{
			trend[i][j] = NOSIGNAL;

      int digits=MarketInfo(TradePair[i],MODE_DIGITS);
      double point = MarketInfo(TradePair[i],MODE_POINT);
      double pip = point * pipMultTab[digits];
		diff = (iClose(TradePair[i], TradePeriodTF[j], 0) - iMA(TradePair[i], TradePeriodTF[j], MaPeriod, MaShift, MaMethod, MaAppliedPrice, 0))/pip;
  		diffs[i][j] = diff;

			if(diff > 0)
			{
				if(diff > BufferPips)
				{
					trend[i][j] = ABOVEBAND;
				}
				else
				{
					trend[i][j] = ABOVEMA;
				}
			}
			else
			{
				if(diff < -BufferPips)
				{
					trend[i][j] = BELOWBAND;
				}
				else
				{
					trend[i][j] = BELOWMA;
				}
			}
		} //End for(j=0; j<NoOfPeriods; j++)
	} //End for(i=0; i<NoOfPairs; i++)
	return(0);

}

//=============================================================================
//                           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)


///////////////////////////////////////////////////////////////////////////////////////////////////////

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()

bool DoesTradeExist(string symbol, int tf)
{
   //This checks both the symbol and the timeframe, allowing the user to have multi-penings in place
   //according to the relation of the market to the 24 ema of each traded tf
   
   if (OrdersTotal() == 0) return(false);
   if (GlobalVariablesTotal() == 0) return(false);
   
   for (int cc = GlobalVariablesTotal() - 1; cc >= 0 ; cc--)
   {
      int tn = StrToDouble(GlobalVariableName(cc));
      if (tn == 0) continue;
      if (!OrderSelect(tn, SELECT_BY_TICKET)) continue;
      if (OrderMagicNumber() !=MagicNumber) continue;
      if (OrderSymbol() != symbol) continue;
      if (OrderCloseTime() > 0) continue;
      int TradeTf = GlobalVariableGet(GlobalVariableName(cc));
      if (TradeTf == tf) return(true);
      if (OrderSymbol() == symbol && TradeTf != tf && AllowMultipleTimeFrameTrades) continue;  
      
      //Got this far, so there is already a trade open
      return(true);   
   }//for (int cc = OrdersTotal() - 1; cc >= 0 ; cc--)

   //Got this far, so there is no trade already open, or there is one on a different tf and the user is allowing this
   return(false);


}//End bool DoesTradeExist(string symbol, int tf)

double GetMa(string symbol, int tf, int period, int mashift, int method, int ap, int shift)
{
   return(iMA(symbol, tf, period, mashift, method, ap, shift) );
}//End double GetMa(string symbol, int tf, int period, int mashift, int method, int ap, int shift)


bool SendSingleTrade(string symbol, int type, string comment, double lotsize, double price, double stop, double take)
{
   
   
   
   color col = Red;
   if (type == OP_BUY || type == OP_BUYSTOP) col = Green;
   int ticket, err;
   
   
   int expiry = 0;
   //if (SendPendingTrades) expiry = TimeCurrent() + (PendingExpiryMinutes * 60);

   //if (!CriminalIsECN) ticket = OrderSend(symbol, type, lotsize, price, 0, stop, take, comment, MagicNumber, expiry, col);
   ticket = OrderSend(symbol, type, lotsize, price, 0, 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));
      Alert(symbol, " ", price);
      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)

double CalculateTakeProfit(string symbol, int type, double price)
{

   int digits=MarketInfo(symbol,MODE_DIGITS);
   double point = MarketInfo(symbol,MODE_POINT);
   double pip = pipMultTab[digits];
   double tp = TakeProfit * pip;
   
   //Buy limit tp
   if (type == OP_BUY)
   {
      double take = NormalizeDouble(price + (tp * point), digits);   
   }//if (type == OP_BUY)
   
   //Sell limit tp
   if (type == OP_SELL)
   {
      take = NormalizeDouble(price - (tp * point), digits);   
   }//if (type == OP_SELL)
   
   return(take);
   
}//End double CalculateTakeProfit(string symbol, int type, double price)


double CalculateStopLoss(string symbol, int type, double price)
{

   int digits=MarketInfo(symbol,MODE_DIGITS);
   double point = MarketInfo(symbol,MODE_POINT);
   double pip = pipMultTab[digits];
   double sl = StopLoss * pip;
   
   //Buy limit tp
   if (type == OP_BUY)
   {
      double stop = NormalizeDouble(price - (sl * point), digits);   
   }//if (type == OP_BUY)
   
   //Sell limit tp
   if (type == OP_SELL)
   {
      stop = NormalizeDouble(price + (sl * point), digits);   
   }//if (type == OP_SELL)
   
   return(stop);
   
}//End double CalculateStopLoss(string symbol, int type, double price)


void Send_Buy_Limit_Trade(string symbol, int tf)
{
   //Check for an existing trade
   if (DoesTradeExist(symbol, tf) ) return;

   //Calculate trade price, tp and sl
   double price, take, stop;
   bool result;
   int digits = MarketInfo(symbol, MODE_DIGITS);
   //Price
   price = NormalizeDouble(GetMa(symbol, tf, MaPeriod, MaShift, MaMethod, MaAppliedPrice, 0), digits);
   //TP
   if (TakeProfit > 0) take = CalculateTakeProfit(symbol, OP_BUY, price);
   //SL
   if (StopLoss > 0) stop = CalculateStopLoss(symbol, OP_BUY, price);
      
   result = SendSingleTrade(symbol, OP_BUYLIMIT, TradeComment, Lot, price, stop, take);
   
   //Set up a global variable that holds the trade's time frame.
   //This is used to move the order fill price in line with the moving ema
   if (result)
   {
      string name = DoubleToStr(TicketNo, 0);
      GlobalVariableSet(name, tf);
   }//if (result)
   
   
   //Alert(symbol, " ", price, " ", take, " ", stop, " ");
   
}//void Send_Buy_Limit_Trade(string symbol, int tf)

void Send_Sell_Limit_Trade(string symbol, int tf)
{
   //Check for an existing trade
   if (DoesTradeExist(symbol, tf) ) return;

   //Calculate trade price, tp and sl
   double price, take, stop;
   bool result;
   int digits = MarketInfo(symbol, MODE_DIGITS);
   //Price
   price = NormalizeDouble(GetMa(symbol, tf, MaPeriod, MaShift, MaMethod, MaAppliedPrice, 0), digits);
   //TP
   if (TakeProfit > 0) take = CalculateTakeProfit(symbol, OP_SELL, price);
   //SL
   if (StopLoss > 0) stop = CalculateStopLoss(symbol, OP_SELL, price);
      
   result = SendSingleTrade(symbol, OP_SELLLIMIT, TradeComment, Lot, price, stop, take);
   
   //Set up a global variable that holds the trade's time frame.
   //This is used to move the order fill price in line with the moving ema
   if (result)
   {
      string name = DoubleToStr(TicketNo, 0);
      GlobalVariableSet(name, tf);
   }//if (result)
   
   
   //Alert(symbol, " ", price, " ", take, " ", stop, " ");
   
}//void Send_Sell_Limit_Trade(string symbol, int tf)


//+------------------------------------------------------------------+

void LookForTradingOpportunities()
{

   //Included this to check that I have copied sq's code correctly
   for (int cc = 0; cc < NoOfPairs; cc++)
   {
      int digits=MarketInfo(TradePair[cc],MODE_DIGITS);
      double point = MarketInfo(TradePair[cc],MODE_POINT);
      double pip = pipMultTab[digits];
      for(int j=0; j<NoOfPeriods; j++)
	   {
         double buffer = BufferPips;
	        
	     //Buy limit trade sent from above the upper buffer
	     if (TradeTrendDiffs[cc][j] >= buffer && TradeTrendDiffs[cc][j] <= buffer * 2)
	     {
	        Send_Buy_Limit_Trade(TradePair[cc], TradePeriodTF[j]);
	     }//if (TradeTrendDiffs[cc][j] >= 20)
	     
	     buffer = -buffer;
	     //Sell limit trade sent from above the upper buffer
	     if (TradeTrendDiffs[cc][j] <= buffer && TradeTrendDiffs[cc][j] >= buffer * 2)
	     {
	        Send_Sell_Limit_Trade(TradePair[cc], TradePeriodTF[j]);
	     }//if (TradeTrendDiffs[cc][j] >= 20)
	     
	   }//for(j=0; j<NoOfPeriods; j++)
	   
   }//for (cc = 0; cc < NoOfPairs; cc++)   
   

}//End void LookForTradingOpportunities()


void DeleteOrphanGlobals()
{
   //Removes global variables when their trades have been closed/deleted
   
   if (GlobalVariablesTotal() == 0) return;
   
   for (int cc = GlobalVariablesTotal() - 1; cc >= 0; cc--)
   {
      int tn = StrToDouble(GlobalVariableName(cc));
   
      if (tn == 0) continue;

      bool delete = false;
      
      if (!OrderSelect(tn, SELECT_BY_TICKET) ) delete = true;
      if (OrderCloseTime() > 0) delete = true;
      if (delete)
      {   
         GlobalVariableDel(GlobalVariableName(cc) );
         cc++;      
      }//if (delete)
      
   }//for (int cc = OrdersTotal() - 1; cc >= 0 ; cc--)


}//End void DeleteOrphanGlobals()

void UpdateFillPrices()
{
   //Updates pending trade prices to reflect the current ema value.
   //each trade's time frame is stored within a global variable with the trade ticket no as the gv name
   //Also deletes orphaned globals
   
   if (GlobalVariablesTotal() == 0) return;
   
   for (int cc = GlobalVariablesTotal() - 1; cc >= 0; cc--)
   {
      int tn = StrToDouble(GlobalVariableName(cc));
   
      if (tn == 0) continue;//Does not belong to this program

      //Orphan gv deletion
      bool delete = false;      
      if (!OrderSelect(tn, SELECT_BY_TICKET) ) delete = true;
      if (OrderCloseTime() > 0) delete = true;
      if (delete)
      {   
         GlobalVariableDel(GlobalVariableName(cc) );
         cc++;      
      }//if (delete)
      
      
      //Open price mod
      if (!delete)
      {
         int tf = GlobalVariableGet(GlobalVariableName(cc) );
         int digits = MarketInfo(OrderSymbol(), MODE_DIGITS);
         double price = NormalizeDouble(GetMa(OrderSymbol(), tf, MaPeriod, MaShift, MaMethod, MaAppliedPrice, 0), digits);
         if (price != OrderOpenPrice() )
         {
            bool result = OrderModify(OrderTicket(), price, OrderStopLoss(), OrderTakeProfit(), OrderExpiration(), CLR_NONE);
            if (!result) OldPriceUpdateBars = 0;
         }//if (price != OrderOpenPrice() )
         
      }//if (!delete)
      
      
   }//for (int cc = OrdersTotal() - 1; cc >= 0 ; cc--)

}//void UpdateFillPrices()

void LookForTradeClosures()
{
   //Closure criteria: market opens and closes on the wrong side of the ema
   
   for (int cc = GlobalVariablesTotal() - 1; cc >= 0; cc--)
   {
      int tn = StrToDouble(GlobalVariableName(cc));
   
      if (tn == 0) continue;//Does not belong to this program

      //Orphan gv deletion
      bool delete = false;      
      if (!OrderSelect(tn, SELECT_BY_TICKET) ) delete = true;
      if (OrderCloseTime() > 0) delete = true;
      if (delete)
      {   
         GlobalVariableDel(GlobalVariableName(cc) );
         cc++;      
      }//if (delete)
      
      
      //Possible trade closure
      if (!delete)
      {
         if (OrderType() != OP_BUY && OrderType() != OP_SELL) continue;
         int tf = GlobalVariableGet(GlobalVariableName(cc) );
         int digits = MarketInfo(OrderSymbol(), MODE_DIGITS);
         double MaVal = NormalizeDouble(GetMa(OrderSymbol(), tf, MaPeriod, MaShift, MaMethod, MaAppliedPrice, 0), digits);
         bool CloseTrade = false;
         
         if (OrderType() == OP_BUY)
         {
            if (iOpen(OrderSymbol(), tf, 1) < MaVal && iClose(OrderSymbol(), tf, 1) < MaVal) CloseTrade = true;
         }//if (OrderType() == OP_BUY)
         
         if (OrderType() == OP_SELL)
         {
            if (iOpen(OrderSymbol(), tf, 1) > MaVal && iClose(OrderSymbol(), tf, 1) > MaVal) CloseTrade = true;
         }//if (OrderType() == OP_SELL)
         
         if (CloseTrade)
         {
            bool result = OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 1000, CLR_NONE);
            if (!result)
            {
               int err=GetLastError();
               Alert(OrderSymbol() ," order close failed with error(",err,"): ",ErrorDescription(err), ": Ticket ", OrderTicket() );
            }//if ((!result)
            
         }//if (CloseTrade)
         
      }//if (!delete)
      
      
   }//for (int cc = OrdersTotal() - 1; cc >= 0 ; cc--)
   

}//End void LookForTradeClosures()


//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
{
//----

   static bool RobotStopped = false;

   while (IsExpertEnabled())
   {
      Sleep(1000);//One second

     //Trade closures on the wrong side of the ema
     if (OrdersTotal() > 0)
     {
        LookForTradeClosures();
     }//if (OrdersTotal() > 0)


      int labelx = ObjectGet(stoplabelname, OBJPROP_XDISTANCE);
      int labely = ObjectGet(stoplabelname, OBJPROP_YDISTANCE);
      if (labelx != StopButtonX || labely != StopButtonY)
      {
        Alert("Robot is stopped. Will continue to monitor trades for closure");
        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) return;
   
     //Delete orphaned Global Variables once an hour
     if (OldGvBars != iBars(NULL, PERIOD_H1) )
     {
        OldGvBars = iBars(NULL, PERIOD_H1);
        DeleteOrphanGlobals();
     }//if (OldGvBars != iBars(NULL, PERIOD_H1)
   

     /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     //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)
     /////////////////////////////////////////////////////////////////////////////////////////////////////////////////

     //Read the data
     GetPairTrends(TradeTrendDiffs, Trend);
   
     
     //Check for ema changes and adjust the trade opening price every 5 minutes
     if (OldPriceUpdateBars != iBars(NULL, PERIOD_M5) )
     {
        OldPriceUpdateBars = iBars(NULL, PERIOD_M5);
        UpdateFillPrices();   
     }//if (OldPriceUpdateBars != iBars(NULL, PERIOD_M5) )
   
   
   
     //Trading
     LookForTradingOpportunities();

     DisplayUserFeedback();

   }//  while (IsExpertEnabled())

//----
   return(0);
}
//+------------------------------------------------------------------+