//+------------------------------------------------------------------+
//|Steve Hopwood's BS 2 Moving Average and MACD combo multi_pair.mq4 |
//|                                                                  |
//|                                                                  |
//+------------------------------------------------------------------+

#property show_inputs
#include <WinUser32.mqh>
#include <stdlib.mqh>
#define  NL    "\n"
#define gv " 2ma macd "
#define long "Long"
#define short "Short"
#define none "None"


/*
www.forexpros.com
	

void DisplayUserFeedback()
int start()
void GetPosition()
void DoesTradeExist(string symbol)
bool NewsExist()    not used in this robot
bool SendSingleTrade(int type, string symbol)
double SetStopLoss(int type, string symbol)
bool DoesTradeExist(string symbol)
bool ShouldRobotSleep(string symbol)

----SMA & MACD----
void GetSmaTradeDirection(string symbol)
void GetMacdDirection(string symbol)


----Trade management----
void ManageTrades()
void JumpingStopLoss(int ticket) 
bool CheckForHiddenStopLossHit(int type, int iPipsAboveVisual, double stop)
void ShouldHalfTradeClose()
bool CloseTrade(int ticket)


----Pairs traded----
void CleanUpInputString()
void CalculatePairsPassed()

*/


extern string  PairsToTrade = "AUDJPY,AUDUSD,CADJPY,CHFJPY,EURAUD,EURCAD,EURCHF,EURGBP,EURJPY,EURUSD,GBPJPY,GBPUSD,USDCAD,USDCHF,USDJPY";
extern double  Lot = 0.02;
extern int     MagicNumber = 4971887;
extern string  TradeComment="MA MACD";
extern int     MaxSpread=120;
extern bool    CriminalIsECN=false;
extern int     MaxTradesAllowed=6;
extern int     SleepAfterTradeClosesMins=60;
extern string  trs="----Trading style----";
extern bool    SendImmediateMarketOrder=false;
extern bool    SendPendingOrder=true;
extern int     PendingOrderPips=100;
extern int     PendingOrderDeleteMins=120;
extern bool    LongTradeAllowed=true;//Allows user to disable trading
extern bool    ShortTradeAllowed=true;//Allows user to disable trading
extern bool    OnlyTradeAtNewCandle=false;
extern bool    AlertNotTrade=false;
extern string  sls="----Trade management----";
extern string  JSL="Jumping stop loss";
extern bool    JumpingStop=false;
extern int     JumpingStopPips=1000;
extern bool    AddBEP=true;
extern int     BreakEvenProfit=100;
extern bool    HideJumpingStop=false;
extern int     PipsAwayFromVisualJS=100;
extern string  tt="----Trading hours----";
extern string  Trade_Hours= "Set Morning & Evening Hours 24hr";
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  wei="----Week ending inputs----";
extern bool    FridayClose=true;
extern bool    SaturdayClose=false;
extern int     CloseHour = 12;
extern string  oae="----Odds and ends----";
extern int     DisplayGapSize=30;
extern bool    ShowPairsInformation=true;
                                    



//Open trades\trade direction.
//bool              LongOpen;
//bool              ShortOpen;
bool              TradeExists;
int               TicketNo;
//int             ShortTicketNo;
string            TradeDirection;
int               NoOfTrades;
//Sma and MACD
string            MacdDirection;
double            MacdVal;
double            sma50;
double            sma100;
double            MinBreakPips=100;

//Trading hours
bool     ClosedForFriday;
bool     ClosedForSaturday;



//Pair extraction
string   InputString;//Holds the contents PairsToTrade for tidying yp etc
int      NoOfPairs;// Holds the number of pairs passed by the user via the inputs screen
string   TradePair[]; //Array to hold the pairs traded by the user
int      dBars[];

//Misc stuff
int      Decimals, OldBars;
string   Trend, ScreenMessage, Gap;
bool     RobotDisabled;
string   DisabledMessage;


void DisplayUserFeedback()
{

   ScreenMessage = "";
   int cc;
   
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Trading ", PairsToTrade, NL);
   if (LongTradeAllowed) ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Taking long trades ", NL);
   else  ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Not taking long trades ", NL);
   if (ShortTradeAllowed) ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Taking long trades ", NL);
   else ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Not taking long trades ", NL);
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Lot size = ", Lot, NL);
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Magic number: ", MagicNumber, NL);
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Trade comment: ", TradeComment, NL);
   if (CriminalIsECN) ScreenMessage = StringConcatenate(ScreenMessage, Gap, "CriminalIsECN is true ", NL);
   else ScreenMessage = StringConcatenate(ScreenMessage, Gap, "CriminalIsECN is false ", NL);
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, "AM trade hour start = ", start_hourm, NL);
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, "AM trade hour end = ", end_hourm, NL);
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, "PM trade hour start = ", start_houre, NL);
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, "PM trade hour end = ", end_houre, NL);
   if (FridayClose) ScreenMessage= StringConcatenate(ScreenMessage, Gap, "Friday close = ", DoubleToStr(CloseHour, 2), NL);
   if (SaturdayClose) ScreenMessage= StringConcatenate(ScreenMessage, Gap, "Saturday close = ", DoubleToStr(CloseHour, 2), NL);
   if (ClosedForSaturday) ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Trading suspended for Saturday close. Continuing to monitor open trades.", NL);
   if (ClosedForFriday) ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Trading suspended for Friday close. Continuing to monitor open trades.", NL);
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Pending pips distance = ", PendingOrderPips, NL);
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Pending trades expiry = ", PendingOrderDeleteMins, " minutes", NL);
   if(JumpingStop==true)
   {
      ScreenMessage = StringConcatenate(ScreenMessage,  Gap, "Jumping stop set to ", JumpingStopPips);
      if (HideJumpingStop)  ScreenMessage = StringConcatenate(ScreenMessage, " (HideJumpingStop = true: PipsAwayFromVisualJS = ", PipsAwayFromVisualJS, ")");
      if(AddBEP==true)
      {
         ScreenMessage = StringConcatenate(ScreenMessage, ", also adding BreakEvenProfit (", BreakEvenProfit, " pips)");      
      }      
   }
   else
   {
      ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Jumping stop disabled");
   }
   ScreenMessage = StringConcatenate(ScreenMessage, NL, NL);

   if (ShowPairsInformation)
   {
      for (cc = 0; cc < NoOfPairs; cc++)
      {
         string symbol = TradePair[cc];
         GetSmaTradeDirection(symbol);
         GetMacdDirection(symbol);
         int digits = MarketInfo(symbol, MODE_DIGITS);
         double bid = MarketInfo(symbol, MODE_BID);
         ScreenMessage = StringConcatenate(ScreenMessage, Gap, symbol, 
                         ": 50 SMA = ", DoubleToStr(sma50, digits),
                         ": 100 SMA = ", DoubleToStr(sma100, digits),
                         ": Trade direction = ", TradeDirection, 
                         ": MACD = ", DoubleToStr(MacdVal, digits), NL);
      }//for (cc = 0; cc < NoOfCurrencies; cc==)
   }//if (ShowPairsInformation)

   Comment(ScreenMessage);
   
}//End void DisplayUserFeedback()


//+------------------------------------------------------------------+
//| expert Initialization function                                   |
//+------------------------------------------------------------------+

int init()
  {

   if (!IsDemo() )
   {
      if (MagicNumber == 4971887)
      {
         MessageBox("You cannot run this robot until changed the MagicNumber input from the default of 4971887." + NL 
                    + "Please reload the robot with a new MagicNumber input.");
         Comment("                This robot can do nothing. Please reload it");
         DisabledMessage = "You need to change the MagicNumber input";
         RobotDisabled = true;
         return;
      }//if (MagicNumber == 4872635)
      
      //Insufficient length
      string mn = DoubleToStr(MagicNumber,0);
      if (StringLen(mn) < 5)
      {
         MessageBox("Your MagicNumber input needs to be at least 5 digits long, Your MagicNumber is " + mn + NL 
                    + "Please reload the robot with the MagicNumber input containing at least 5 digits - the more the better.");
         Comment("                This robot can do nothing. Please reload it");
         DisabledMessage = "You need to make the MagicNumber input at 5 digits long - more is better";
         RobotDisabled = true;
         return;
      }//if (StringLen(mn) < 5)     
      
   }//if (!IsDemo)
   
   
   //Amend inputs to cater for different broker digits
   int dig = MarketInfo(Symbol(), MODE_DIGITS);
   if (dig == 2 || dig == 4)
   {   
      PendingOrderDeleteMins/= 10;      
   }//if (dig = 3)
   
   //Extract the pairs traded by the user
   // Cleanup first
   InputString=PairsToTrade;
   CleanUpInputString();
   
   // Extract the number of paraaters passed by the user
   CalculatePairsPassed();
   
   string AddChar = StringSubstr(Symbol(),6,4);
   
   // Resize the arrays appropriately
   string NewArray = ArrayResize(TradePair, NoOfPairs);
   double iNew3 = ArrayResize(dBars, NoOfPairs);
   
   int Index = 0;//For searching InputString
   int LastIndex = 0;//Points the the most recent Index
   for (int cc = 0; cc < NoOfPairs; cc ++)
   {
      Index = StringFind(InputString, ",",LastIndex);
      if (Index > -1)
      {
         TradePair[cc] = StringSubstr(InputString, LastIndex,Index-LastIndex);
         TradePair[cc] = StringTrimLeft(TradePair[cc]);
         TradePair[cc] = StringTrimRight(TradePair[cc]);
         TradePair[cc] = StringConcatenate(TradePair[cc], AddChar);
         
         LastIndex = Index+1;
         dBars[cc] = iBars(TradePair[cc], 0);         
      }//if (Index > -1)            
   }//for (int cc; cc<NoOfPairs; cc ++)

    int Step = MarketInfo(Symbol(),MODE_LOTSTEP);
    
    if(Step == 0.01) Decimals = 2;
    if(Step == 0.10) Decimals = 1;
    if(Step == 1.00) Decimals = 0;
    
    
   Gap="";
   if (DisplayGapSize >0)
   {
      for (cc=0; cc< DisplayGapSize; cc++)
      {
         Gap = StringConcatenate(Gap, " ");
      }   
   }
   
   GetPosition();   
   if (NoOfTrades == 0) OldBars = iBars(NULL, 0);

      
   Comment(".........Waiting for a tick");
   
   return(0);
    
  }
  
//+------------------------------------------------------------------+
//| expert Deinitialization function                                 |
//+------------------------------------------------------------------+

int deinit()
  {

    Comment("");
    
    return(0);

  }
  
//+------------------------------------------------------------------+
//| expert GetPosition function                                      |
//+------------------------------------------------------------------+

void GetPosition()
{

   NoOfTrades = 0;
   if (OrdersTotal() == 0 ) return;
   
   for(int cc = OrdersTotal() - 1; cc >= 0; cc--)
   {
       if(!OrderSelect(cc, SELECT_BY_POS, MODE_TRADES) ) continue;
         
       if(OrderMagicNumber() == MagicNumber)
       {
           NoOfTrades++;
       }//if(OrderSymbol() == symbol && OrderMagicNumber() == MagicNumber)
         
   }//for(int cc = 0; cc <= OrdersTotal(); cc++)
 
 
}//void GetPosition(string symbol)



/*
//+------------------------------------------------------------------+
//| expert News function                                             |
//+------------------------------------------------------------------+  

bool NewsExist()
  {
  
    bool News;

    for(int d = 0; d < NoOfPairs; d++)
      {
        int MinutesSincePrevEvent =
          iCustom(NULL,0,"Economic News",TradePair[d],true,false,false,true,true,1,0);

        int MinutesUntilNextEvent =
          iCustom(NULL,0,"Economic News",TradePair[d],true,false,false,true,true,1,1);

        if(MinutesUntilNextEvent < 60 ||
           MinutesSincePrevEvent < 15)
          {
            News = true;
          }
      }
      
    return(News);

  }
*/
//+------------------------------------------------------------------+
//| expert Trend function                                            |
//+------------------------------------------------------------------+  


void CleanUpInputString()
{
   // Does any tidying up of the user inputs
   
   //Remove unwanted spaces
   InputString = StringTrimLeft(InputString);
   InputString = StringTrimRight(InputString);

   //Add final comma if ommitted by user
   if (StringSubstr(InputString, StringLen(InputString)-1) != ",") 
      InputString = StringConcatenate(InputString,",");
      
   
}//void CleanUpInputString

void CalculatePairsPassed()
{
   // Calculates the numbers of paramaters passed in LongMagicNumber and TradeComment.
   
   int Index = 0;//For searching NoTradePairs
   int LastIndex;//Points the the most recent Index
   
   while(Index > -1)
      {
         Index = StringFind(InputString, ",",LastIndex);
         if (Index > -1)
         {
            NoOfPairs ++;
            LastIndex = Index+1;            
         }//if (Index > -1)
      }//while(int cc > -1)
   
   
   
}//End void CalculatePairsPassed()





void ShouldHalfTradeClose()
{
   //Only called if selected trade is in profit/
   //Closes half the trade at profit of risk x 2
   
   RefreshRates();
   double ask = MarketInfo(OrderSymbol(), MODE_ASK);
   double bid = MarketInfo(OrderSymbol(), MODE_BID);
   double point = MarketInfo(OrderSymbol(), MODE_POINT);
   double digits = MarketInfo(OrderSymbol(), MODE_DIGITS);
      //Long
   if (OrderType() == 0)
   {
      double HcPrice = NormalizeDouble(OrderOpenPrice() + (OrderOpenPrice() - OrderStopLoss()) * 2, digits);//Half close price
      if (ask > HcPrice)
      {
        bool result = OrderClose(OrderTicket(),OrderLots() / 2, OrderClosePrice(),100,CLR_NONE);
        if (!result)
        {
             int err=GetLastError();
             Alert(Symbol(), " MA MACD Combo robot ", OrderType()," part-close failed with error(",err,"): ",ErrorDescription(err));
             return;
        }//if (!result)
        //Get new ticket number
        Sleep(100);
        DoesTradeExist(OrderSymbol() );
        OrderSelect(TicketNo, SELECT_BY_TICKET);
        if (OrderStopLoss() < OrderOpenPrice() )
        {
           double SL = OrderOpenPrice();
           result = OrderModify(OrderTicket(), OrderOpenPrice(), SL, OrderTakeProfit(), 0, CLR_NONE);
           if (!result)
            {
                err=GetLastError();
                Alert(Symbol(), " MA MACD Combo robot ", OrderType(), " Stop loss move failed with error(",err,"): ",ErrorDescription(err));
                return;
            }//if (!result)     
        }//if (OrderStopLoss() < OrderOpenPrice() )
     }//if (Ask > HcPrice)      
   }//if (OrderType() == 0)
   
   //Short
   if (OrderType() == 1)
   {
      HcPrice = NormalizeDouble(OrderOpenPrice() - (OrderStopLoss() - OrderOpenPrice()) * 2, digits);//Half close price
      if (bid < HcPrice)
      {
         result = OrderClose(OrderTicket(),OrderLots() / 2, OrderClosePrice(),100,CLR_NONE);
         if (!result)
         {
             err=GetLastError();
             Alert(Symbol(), " MA MACD Combo robot ", OrderType()," part-close failed with error(",err,"): ",ErrorDescription(err));
             return;
         }//if (!result)
        //Get new ticket number
        Sleep(100);
        DoesTradeExist(OrderSymbol() );
        OrderSelect(TicketNo, SELECT_BY_TICKET);
        if (OrderStopLoss() < OrderOpenPrice() )
        {
           SL = OrderOpenPrice();
           result = OrderModify(OrderTicket(), OrderOpenPrice(), SL, OrderTakeProfit(), 0, CLR_NONE);
           if (!result)
            {
                err=GetLastError();
                Alert(Symbol(), " MA MACD Combo robot ", OrderType(), " Stop loss move failed with error(",err,"): ",ErrorDescription(err));
                return;
            }//if (!result)     
        }//if (OrderStopLoss() < OrderOpenPrice() ) 
      }//if (Bid < HcPrice)      
   }//if (OrderType() == 1)
   

}//void ShouldHalfTradeClose()

void ManageTrades()
{
   //Called if there are any open trades
   for (int cc = OrdersTotal() - 1; cc >=0; cc--)
   {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;
      if (OrderMagicNumber() ==  MagicNumber)
      {
         TicketNo = OrderTicket();
         if (JumpingStop)
         {
            JumpingStopLoss(TicketNo);
         }//if (JumpingStop)
         
         //Partial trade closure
         OrderSelect(TicketNo, SELECT_BY_TICKET);//Should not need re-selecting, but just in case
         if (OrderCloseTime() == 0 && OrderProfit() > 0 && OrderLots() == Lot)
         {
            ShouldHalfTradeClose();
         }//if (OrderCloseTime() == 0 && OrderProfit() > 0)
      
         //Pick up on any failed stop move to breakeven
         if (OrderType() == OP_BUY)
         {
            if (OrderLots() < Lot && OrderStopLoss() < OrderOpenPrice() )
            {
               OrderModify(TicketNo, OrderOpenPrice(), OrderOpenPrice(), OrderTakeProfit(), OrderExpiration(), CLR_NONE);
            }//if (OrderLots() < Lot && OrderStopLoss() < OrderOpenPrice() )            
         }//if (OrderType() == OP_BUY)
         
         if (OrderType() == OP_SELL)
         {
            if (OrderLots() < Lot && OrderStopLoss() > OrderOpenPrice() )
            {
               OrderModify(TicketNo, OrderOpenPrice(), OrderOpenPrice(), OrderTakeProfit(), OrderExpiration(), CLR_NONE);
            }//if (OrderLots() < Lot && OrderStopLoss() < OrderOpenPrice() )            
         }//if (OrderType() == OP_SELL)
         
      }//if (OrderSymbol() == symbol && OrderMagicNumber() ==  MagicNumber)      
   }//for (int cc = OrdersTotal() - 1; cc >=0)

   
   
}//void ManageTrades()

void GetSmaTradeDirection(string symbol)
{
   //Sets TradeDirection according to the market in relation to the two sma's
   TradeDirection = none;
   
   sma50 = iMA(symbol, 0, 50, 0, MODE_SMA, PRICE_CLOSE, 0);
   sma100 = iMA(symbol, 0, 100, 0, MODE_SMA, PRICE_CLOSE, 0);
   
   double HighestSma = sma50;
   double LowestSma = sma100;
   
   if (sma50 > sma100)
   {
      HighestSma = sma50;
      LowestSma = sma100;
   }//if (sma50 > sma100)
   
   if (sma50 < sma100)
   {
      HighestSma = sma100;
      LowestSma = sma50;
   }//if (sma50 > sma100)
   
   double ask = MarketInfo(symbol, MODE_ASK);
   double bid = MarketInfo(symbol, MODE_BID);
   double point = MarketInfo(symbol, MODE_POINT);
   
   //Check there are at least 10 pips in favour of the trade direction
   if (ask > sma50 && ask > sma100) 
   {
      if (ask - HighestSma > MinBreakPips * point) TradeDirection = long;
   }//if (Ask > sma50 && Ask > sma100) 
   
   
   if (bid < sma50 && bid < sma100)
   {
      if (LowestSma - bid > MinBreakPips * point) TradeDirection = short;
   }//if (Bid < sma50 && Bid < sma100) TradeDirection = short;
   

}//void GetSmaTradeDirection(string symbol)

void GetMacdDirection(string symbol)
{
   //Returns long if macd has crossed into positive within the last 5 Bars
   //Returns short if macd has crossed into negative within the last 5 Bars
   //Returns none if neither
   
   int StartLoop, EndLoop;
   
   MacdDirection = none;
   
   //Set up parameters for checking at the start of each new candle
   if (OnlyTradeAtNewCandle)
   {
      MacdVal = iMACD(symbol, 0, 12, 26, 9, PRICE_CLOSE, MODE_MAIN, 1) -
                iMACD(symbol, 0, 12, 26, 9, PRICE_CLOSE, MODE_SIGNAL, 1);
      StartLoop = 2;
      EndLoop = 6;
   }//OnlyTradeAtNewCandle
   
   if (!OnlyTradeAtNewCandle)
   {
      MacdVal = iMACD(symbol, 0, 12, 26, 9, PRICE_CLOSE, MODE_MAIN, 0) -
                iMACD(symbol, 0, 12, 26, 9, PRICE_CLOSE, MODE_SIGNAL, 0);
      StartLoop = 1;
      EndLoop = 5;
   }//OnlyTradeAtNewCandle
   
   if (MacdVal > 0)
   {
      for (int cc = StartLoop; cc <= EndLoop; cc++)
      {
         double PrevMacdVal = iMACD(symbol, 0, 12, 26, 9, PRICE_CLOSE, MODE_MAIN, cc) -
                       iMACD(symbol, 0, 12, 26, 9, PRICE_CLOSE, MODE_SIGNAL, cc);
         
         if (PrevMacdVal < 0)
         {
            MacdDirection = long;
            return;
         }//if (MacdVal < 0)
         
      }//for (int cc = 1; cc < 4: cc ++)
   }//if (MacdVal > 0)
   
   
   if (MacdVal < 0)
   {
      for (cc = StartLoop; cc <= EndLoop; cc++)
      {
         PrevMacdVal = iMACD(symbol, 0, 12, 26, 9, PRICE_CLOSE, MODE_MAIN, cc) -
                       iMACD(symbol, 0, 12, 26, 9, PRICE_CLOSE, MODE_SIGNAL, cc);
         
         if (PrevMacdVal > 0)
         {
            MacdDirection = short;
            return;
         }//if (MacdVal < 0)         
      }//for (int cc = 1; cc < 4: cc ++)
   }//if (MacdVal < 0)
   
   
   

}//End void GetMacdDirection(string symbol)

void DoesTradeExist(string symbol)
{
   //Searches for open trades
   TradeExists = false;
   TicketNo = 0;
   
   
   if (OrdersTotal() == 0) return; //nothing to do
   
   for (int cc = OrdersTotal() - 1; cc >= 0; cc--)
   {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;
      if (OrderMagicNumber() == MagicNumber && OrderSymbol() == symbol ) 
      {
         if (OrderType() == OP_BUY || OrderType() == OP_BUYSTOP || OrderType() == OP_SELL || OrderType() == OP_SELLSTOP )
         {
            TicketNo = OrderTicket();
            TradeExists = true;
            return;
         }//if (OrderType() == OP_BUY)                                   
      }//if (OrderMagicNumber() == MagicNumber && OrderSymbol() == symbol)       
   }//for (int cc = OrdersTotal() - 1; cc >= 0, cc--)  
   
}//End void DoesTradeExist(string symbol)


bool ShouldRobotSleep(string symbol)
{
   // Checks the history list to find a closed trade.
   // If one exists, checks to see if it closed more than SleepAfterTradeClosesMins.
   // Returns false (sleep not needed) if so, else true (sleep needed)
   
   if (OrdersHistoryTotal() == 0) return(false);// No history trades, so sleep clearly not needed
   
   for(int cnt=0; cnt<OrdersHistoryTotal(); cnt++)
   {
      if(!OrderSelect(cnt,SELECT_BY_POS,MODE_HISTORY)) continue;
      {       
         if (OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
         {
            int TimePassed = (TimeCurrent() - OrderCloseTime()) / 60;
            if (TimePassed < SleepAfterTradeClosesMins) return(true);//Robot should sleep
         }//if (OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)            
      }//if(!OrderSelect(cnt,SELECT_BY_POS,MODE_HISTORY))
   }//for(int cnt=0; cnt<OrdersHistoryTotal(); cnt++)

   //Got this far, so sleep not needed
   return(false);

}//End bool ShouldRobotSleep(string symbol)

double SetStopLoss(int type, string symbol)
{
   //Returns a stop that is the highest\lowest of the previous 5 bars
   
   if (type == 0)
   {
      double stop = iLow(symbol, 0, 0);
      for (int cc = 1; cc < 5; cc++)
      {
         if (iLow(symbol, 0, 0) < stop) stop = iLow(symbol, 0, 0);
      }//if (type = 0)   
   }//if (type == 0)

   if (type == 1)
   {      
      stop = iHigh(symbol, 0, 0);
      for (cc = 1; cc < 5; cc++)
      {
         if (iHigh(symbol, 0, 0) > stop) stop = iHigh(symbol, 0, 0);
      }//if (type = 0)   
   }//if (type == 0)

   return(stop);

}//End double SetStopLoss(int type, string symbol)

bool SendSingleTrade(int type, string symbol)
{
   // Attempts to place a trade according to type, i.e.
   // 0 = OP_BUY
   // 1 = OP_SELL
   
   // Check spread
   if (MarketInfo(symbol, MODE_SPREAD) > MaxSpread)
   {
      return(false);// Spread too large, so abort send
   }//if (MarketInfo(NULL, MODE_SPREAD) > MaxSpreadAllowed)
   
   RefreshRates();
   double ask = MarketInfo(symbol, MODE_ASK);
   double bid = MarketInfo(symbol, MODE_BID);
   double point = MarketInfo(symbol, MODE_POINT);
   double digits = MarketInfo(symbol, MODE_DIGITS);
   
   double StopLoss;
      
   // Buy trade
   if (type == 0)
   {
      double TradePrice=ask;
      int colour = 32768;//green
      StopLoss = SetStopLoss(0, symbol);
      datetime expiry = 0;
   }//if (type == 0)   
   
   //Buy stop trade
   if (type == OP_BUYSTOP)
   {
      TradePrice = NormalizeDouble(ask + (PendingOrderPips * point), digits);
      colour = 32768;//green
      expiry = TimeCurrent()+(PendingOrderDeleteMins*60);
      StopLoss = SetStopLoss(0, symbol);
   }//if (type == 4)

   // Sell trade
   if (type == 1)
   {
      TradePrice=bid;      
      colour = 255;//red
      StopLoss = SetStopLoss(1, symbol);
      expiry = 0;
   }//if (type == 1)
   
   //Sell stop trade
   if (type == OP_SELLSTOP)
   {
      TradePrice = NormalizeDouble(bid - (PendingOrderPips * point), digits);
      colour = 255;//red
      expiry = TimeCurrent()+(PendingOrderDeleteMins*60);
      StopLoss = SetStopLoss(1, symbol);
   }//if (type == 4)
   
   int slippage = 10;
   if (digits == 3 || digits == 5) slippage = 100;
   
   int ticket = OrderSend(symbol,type, Lot, TradePrice, slippage, StopLoss, 0, TradeComment, MagicNumber,expiry, colour);
   if (ticket < 0)
   {
      int err=GetLastError();
      Alert("MA MACD ", symbol, " ", type," order send failed with error(",err,"): ",ErrorDescription(err));
      Print("Order send failed with error(",err,"): ",ErrorDescription(err));
      return(false);
   }//if (ticket < 0)
   else Sleep(1000);//1 second   
   
   return(true);
   
}//End bool SendSingleTrade(int type, string symbol)

bool CloseTrade(int ticket)
{
   //Attempts to close the trade. Returns true if succeeds, else false
   
   if (!OrderSelect(ticket, SELECT_BY_TICKET) ) return;
   bool result = OrderClose(ticket, OrderLots(), OrderClosePrice(), 1000, CLR_NONE);
   if (result) return(true);
   else return(false);

}//End bool CloseTrade(int ticket)

bool CheckForHiddenStopLossHit(int type, int iPipsAboveVisual, double stop)
{
   //Reusable code that can be called by any of the stop loss manipulation routines except HiddenStopLoss().
   //Checks to see if the market has hit the hidden sl and attempts to close the trade if so. 
   //Returns true if trade closure is successful, else returns false

   RefreshRates();
   double ask = MarketInfo(OrderSymbol(), MODE_ASK);
   double bid = MarketInfo(OrderSymbol(), MODE_BID);
   double point = MarketInfo(OrderSymbol(), MODE_POINT);
   double digits = MarketInfo(OrderSymbol(), MODE_DIGITS);
   
   //Check buy trade
   if (type == OP_BUY)
   {
      double sl = NormalizeDouble(stop + (iPipsAboveVisual * point), digits);
      if (bid <= sl)
      {
         bool result = OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 5, CLR_NONE);
         if (result)
         {
            Alert("Stop loss hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket());      
         }//if (result)
         else
         {
            int err=GetLastError();
            Alert("Stop loss hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
            Print("Stop loss hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
         }//else
      }//if (bid <= sl)  
   }//if (type = OP_BUY)
   
   //Check buy trade
   if (type == OP_SELL)
   {
      sl = NormalizeDouble(stop - (iPipsAboveVisual * point), digits);
      if (ask >= sl)
      {
         result = OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 5, CLR_NONE);
         if (result)
         {
            Alert("Stop loss hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket());      
         }//if (result)
         else
         {
            err=GetLastError();
            Alert("Stop loss hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
            Print("Stop loss hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
         }//else
      }//if (ask >= sl)  
   }//if (type = OP_SELL)
   

}//End bool CheckForHiddenStopLossHit(int type, int iPipsAboveVisual, double stop)

void JumpingStopLoss(int ticket) 
{
   if (!OrderSelect(ticket, SELECT_BY_TICKET) ) return;//Order has closed, so nothing to do

   RefreshRates();
   double ask = MarketInfo(OrderSymbol(), MODE_ASK);
   double bid = MarketInfo(OrderSymbol(), MODE_BID);
   double point = MarketInfo(OrderSymbol(), MODE_POINT);
   double digits = MarketInfo(OrderSymbol(), MODE_DIGITS);
  
   double sl=OrderStopLoss(); //Stop loss

   if (OrderType()==OP_BUY)
   {
      //Check hidden js for trade closure
      if (HideJumpingStop)
      {
         bool TradeClosed = CheckForHiddenStopLossHit(OP_BUY, PipsAwayFromVisualJS, OrderStopLoss() );
         if (TradeClosed) return;//Trade has closed, so nothing else to do
      }//if (HideJumpingStop)
      
      // First check if sl needs setting to breakeven
      if (sl==0 || sl<OrderOpenPrice())
      {
         if (ask >= OrderOpenPrice() + (JumpingStopPips*point))
         {
            sl=OrderOpenPrice();
            if (AddBEP==true) sl=sl+(BreakEvenProfit*point); // If user wants to add a profit to the break even
            bool result = OrderModify(OrderTicket(),OrderOpenPrice(),sl,OrderTakeProfit(),0,CLR_NONE);
            if (result)
            {
               Print("Jumping stop set at breakeven: ", OrderSymbol(), ": SL ", sl, ": ask ", ask);
               //Delete the associated hedge trade
               return(0);
            }//if (result)
            if (!result)
            {
               int err=GetLastError();
               Alert(Symbol(), " buy trade. Jumping stop function failed to set SL at breakeven, with error(",err,"): ",ErrorDescription(err));
               Print(Symbol(), " buy trade. Jumping stop function failed to set SL at breakeven, with error(",err,"): ",ErrorDescription(err));
            }//if (!result)
             
            
         }//if (ask >= OrderOpenPrice() + (JumpingStopPips*point))
      } //close if (sl==0 || sl<OrderOpenPrice()

  
      // Increment sl by sl + JumpingStopPips.
      // This will happen when market price >= (sl + JumpingStopPips)
      if (bid>= sl + ((JumpingStopPips*2)*point) && sl>= OrderOpenPrice())      
      {
         sl=sl+(JumpingStopPips*point);
         result = OrderModify(OrderTicket(),OrderOpenPrice(),sl,OrderTakeProfit(),0,CLR_NONE);
         if (result)
         {
            Print("Jumping stop set: ", OrderSymbol(), ": SL ", sl, ": ask ", ask);
            //Delete the associated hedge trade
            return(0);
         }//if (result)
         if (!result)
         {
            err=GetLastError();
            Print(Symbol(), " buy trade. Jumping stop function failed with error(",err,"): ",ErrorDescription(err));
         }//if (!result)
             
      }// if (bid>= sl + (JumpingStopPips*point) && sl>= OrderOpenPrice())      
   }//if (OrderType()==OP_BUY)
   
   if (OrderType()==OP_SELL)
   {
      //Check hidden js for trade closure
      if (HideJumpingStop)
      {
         TradeClosed = CheckForHiddenStopLossHit(OP_SELL, PipsAwayFromVisualJS, OrderStopLoss() );
         if (TradeClosed) return;//Trade has closed, so nothing else to do
      }//if (HideJumpingStop)
            
      // First check if sl needs setting to breakeven
      if (sl==0 || sl>OrderOpenPrice())
      {
         if (ask <= OrderOpenPrice() - (JumpingStopPips*point))
         {
            sl = OrderOpenPrice();
            if (AddBEP==true) sl=sl-(BreakEvenProfit*point); // If user wants to add a profit to the break even
            result = OrderModify(OrderTicket(),OrderOpenPrice(),sl,OrderTakeProfit(),0,CLR_NONE);
            if (result)
            {
               
            }//if (result)
            if (!result)
            {
               err=GetLastError();
               Alert(Symbol(), " sell trade. Jumping stop function failed to set SL at breakeven, with error(",err,"): ",ErrorDescription(err));
               Print(Symbol(), " sell trade. Jumping stop function failed to set SL at breakeven, with error(",err,"): ",ErrorDescription(err));
            }//if (!result)
             
            return(0);
         }//if (ask <= OrderOpenPrice() - (JumpingStopPips*point))
      } // if (sl==0 || sl>OrderOpenPrice()
   
      // Decrement sl by sl - JumpingStopPips.
      // This will happen when market price <= (sl - JumpingStopPips)
      if (bid<= sl - ((JumpingStopPips*2)*point) && sl<= OrderOpenPrice())      
      {
         sl=sl-(JumpingStopPips*point);
         result = OrderModify(OrderTicket(),OrderOpenPrice(),sl,OrderTakeProfit(),0,CLR_NONE);
         if (result)
         {
            Print("Jumping stop set: ", OrderSymbol(), ": SL ", sl, ": ask ", ask);
            
         }//if (result)          
         if (!result)
         {
            err=GetLastError();
            Print(Symbol(), " sell trade. Jumping stop function failed with error(",err,"): ",ErrorDescription(err));
         }//if (!result)

      }// close if (bid>= sl + (JumpingStopPips*point) && sl>= OrderOpenPrice())         
   }//if (OrderType()==OP_SELL)

} //End of JumpingStopLoss sub



//+------------------------------------------------------------------+
//| expert Start function                                            |
//+------------------------------------------------------------------+

int start()
{
    
   if (RobotDisabled )
   {
      Comment("The robot has been suspended. Reason: ", DisabledMessage);
      return;
   }//if (RobotDisabled )


   

    GetPosition();
    if(NoOfTrades > 0) ManageTrades();
    
   
    
/*    //Trade disable conditions
    if (NewsExist() )
    {
         ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Trading disabled because of news event");
         DisplayUserFeedback();
    }//if (NewsExists)
*/    

   
   //Trading hours
   bool TradeHour = false;
   if ((Hour()>=start_hourm && Hour()<end_hourm) || (Hour()>=start_houre && Hour()<end_houre)) TradeHour = true;
   if (!TradeHour)
   {
      Comment(Gap, "Trading suspended - outside trade hours. Continuing to monitor open trades.");
      return;
   }//if (!TradeHour)

    //Look for trading opportunities
    for(int cc = 0; cc < ArraySize(TradePair); cc++)
    {

      string symbol = TradePair[cc];//Does nothing more than make typing easier

      RefreshRates();
      double ask = MarketInfo(symbol, MODE_ASK);
      double bid = MarketInfo(symbol, MODE_BID);
      double point = MarketInfo(symbol, MODE_POINT);
      double digits = MarketInfo(symbol, MODE_DIGITS);
   
      
      //Check for open trades. Their ticket numbers are stored in variables set up for the purpose
      DoesTradeExist(symbol);

      //Look for open trade exit
      if (TradeExists) double sma50 = iMA(symbol, 0, 50, 0, MODE_SMA, PRICE_CLOSE, 0);
      OrderSelect(TicketNo, SELECT_BY_TICKET);
      if (OrderType() == OP_BUY)
      {
         if (ask < NormalizeDouble(sma50 - (MinBreakPips * point), digits) && OrderProfit() >= 0
         && OrderCloseTime() == 0 && OrderLots() < Lot) CloseTrade(TicketNo);
      }if (OrderType() == OP_BUY)
   
      if (OrderType() == OP_SELL)
      {
         OrderSelect(TicketNo, SELECT_BY_TICKET);
         if (bid > NormalizeDouble(sma50 + (MinBreakPips * point), digits) && OrderProfit() >=0
         && OrderCloseTime() == 0 && OrderLots() < Lot) CloseTrade(TicketNo);
      }//if (OrderType() == OP_SELL)
   
      //Check Friday close
     if (FridayClose)
     {
        ClosedForFriday = false;
        if (TimeHour(TimeLocal() ) >= CloseHour && TimeDayOfWeek(TimeLocal() ) == 5)
        {
           ClosedForFriday = true;
           DisplayUserFeedback();
           return;
        }//if (TimeHour(TimeLocal()) >= CloseHour && DayOfWeek() == 5)
     }//if (FridayClose)
   
     //Check Saturday close for Aitipodeans
     if (SaturdayClose)
     {
        ClosedForSaturday = false;
        if (TimeHour(TimeLocal() ) >= CloseHour && TimeDayOfWeek(TimeLocal() ) == 6)
        {
           ClosedForSaturday = true;
           DisplayUserFeedback();
           return;
        }//if (TimeHour(TimeLocal()) >= CloseHour && DayOfWeek() == 5)
     }//if (Saturday)

      //Check for sleep time after trade closure for any reason
      if (!TradeExists)
      {
         bool SendToSleep = ShouldRobotSleep(symbol);// Compares closure time of history trade with current time, 
                                               // returning true for sleep or false. Will return false if no history trades
         if (SendToSleep)
         {
            continue;
         }//if (SendToSleep)
      
      }//if (!LongOpen && !ShortOpen)
   
      if(NoOfTrades >= MaxTradesAllowed) break;

       if (!IsTradeAllowed())
       {
            Comment("Trading disabled by the criminal pillock. Please wait for him to get out of bed.");
            return;
       }//if (!IsTradeAllowed)
        
       if(iClose(TradePair[cc],0,0) > 0)
       {      
            
            if (TradeExists) continue;
            
            //Overriding filters ok, so continue
            bool TradeAllowed = true;
            //SMA
            GetSmaTradeDirection(symbol);//Looks at market compared to sma's and sets TradeDirection accordingly - none, long or short            
            if (TradeDirection == none) TradeAllowed = false;
            if (TradeExists) TradeAllowed = false;
            
            //Check macd. 
            //Will return long if macd crossed into positive within the last 5 bars.
            //Will return short if macd crossed into negative within the last 5 bars.
            GetMacdDirection(symbol);
            if (MacdDirection == none) TradeAllowed = false;
            
            //Abort if trading has been disallowed for any reason
            if (!TradeAllowed) continue;
            
            
            if (IsTradeAllowed() )
            {                    
            
               if (TradeDirection == long && MacdDirection == long && LongTradeAllowed)
               {
                  if (AlertNotTrade) Alert("2MA MACD combo ", symbol, " Long trade is available");
                  else
                  {
                     if (SendImmediateMarketOrder) SendSingleTrade(0, symbol);
                     if (SendPendingOrder) SendSingleTrade(OP_BUYSTOP, symbol);
                  }//else               
               }//if (Ask - HighestSma > 10 * Point) TradeDirection = long;
      
               if (TradeDirection == short && MacdDirection == short && ShortTradeAllowed)
               {
                  if (AlertNotTrade) Alert("2MA MACD combo ", symbol, " Short trade is available");
                  else
                  {               
                     if (SendImmediateMarketOrder) SendSingleTrade(1, symbol);
                     if (SendPendingOrder) SendSingleTrade(OP_SELLSTOP, symbol);
                  }//else
               }//if (Ask - HighestSma > 10 * Point) TradeDirection = long;         
               
            }//if (IsTradeAllowed)        
      
         }//if(iClose(TradePair[cc],0,0) > 0)
      
      }//for(int cc = 0; cc < ArraySize(TradePair); cc++)
    
    DisplayUserFeedback();
      
    return(0);

}//End start()


