//+------------------------------------------------------------------+
//|              Steve Hopwood's Bollinger Bands BS trend trader.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"
//MACD direction
#define long "Long"
#define short "Short"
#define none "None"


/*

/*

void DisplayUserFeedback()

----Trading functions----
void LookForOpenTrades()
bool SendSingleTrade(int type)
double SetStopLoss(int type)
bool CheckForHiddenStopLossHit(int type, int iPipsAboveVisual, double stop )
void GetSpread()
bool CloseTrade(int ticket)
void ShouldHalfTradeClose()
bool ShouldRobotSleep()

----TP and SL
void JumpingStopLoss(int ticket) 

----SMA & MACD----
GetSmaTradeDirection()
void GetMacdDirection()

********News filter functions***********
Thanks to Tim at FXAW for all this
bool NewsFilterCheck()
      Use construct bool TradeAllowed = NewsFilterCheck()
string Num2Impact(int impact)

----Misc----
void WaitForConnection()
void ReplaceMissingGlobals()

*/
extern string     bs="----Basic stuff----";
extern bool       LongTradeAllowed=true;//Allows user to disable trading
extern bool       ShortTradeAllowed=true;//Allows user to disable trading
extern double     Lot=0.02;
extern int        MagicNumber=4872635;
extern string     TradeComment="MA MACD";
extern int        MaxSpread=120;
extern int        SleepAfterTradeClosesMins=60;
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     news="-----News filter-----";
extern bool       UseNewsFilter=false;
extern int        MinsUntilNews=60;
extern string     news1="3=High; 2=Medium; 1=Low";
extern int        NewsImpact=3;
extern string     oae="----Odds and ends----";
extern int        DisplayGapSize=30;



//Open trades\trade direction.
bool              LongOpen;
bool              ShortOpen;
int               LongTicketNo;
int               ShortTicketNo;
string            TradeDirection;

//Sma and MACD
string            MacdDirection;
double            MacdVal;
double            sma50;
double            sma100;

//Misc stuff
string            ScreenMessage, Gap;
int               NewsBars;
bool              RobotDisabled;
string            DisabledMessage;
int               Spread;

void DisplayUserFeedback()
{
   ScreenMessage = "";
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, "50 SMA = ", DoubleToStr(sma50, Digits), NL);
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, "100 SMA = ", DoubleToStr(sma100, Digits), NL);
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Trade direction = ", TradeDirection, NL);
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, "MACD = ", MacdVal, NL);
   //if (!TradeDirection == none) ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Usable Macd direction = ", MacdDirection, NL);
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Macd direction = ", MacdDirection, NL);
   
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, 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 (LongTradeAllowed) ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Long trading is allowed", NL);
   else ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Long trading is disabled", NL);
   if (ShortTradeAllowed) ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Short trading is allowed", NL);
   else ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Short trading is disabled", NL);
   GetSpread();
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, "MaxSpread = ", MaxSpread, "  Spread = ", Spread, NL);
   ScreenMessage=StringConcatenate(ScreenMessage, Gap, "The robot will sleep for ", SleepAfterTradeClosesMins, " mins after a trade closure",NL);
   //News filter
   if (UseNewsFilter) 
   {
      NewsFilterCheck();
   }//if (UseNewsFilter)  
     
   if(JumpingStop==true)
   {
      ScreenMessage = StringConcatenate(ScreenMessage,  NL, 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, NL, Gap, "Jumping stop disabled");
   }
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, NL);
   
   if (LongOpen) ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Long trade open  ", LongTicketNo, NL);
   if (ShortOpen) ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Short trade open  ", ShortTicketNo, NL);
   

   Comment(ScreenMessage);
}//void DisplayUserFeedback()


//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
{
//----
   
   if (!IsDemo() )
   {
      if (MagicNumber == 4872635)
      {
         MessageBox("You cannot run this robot until changed the MagicNumber input from the default of 4872635." + 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)
      
      //Default trade comment needs changing
      if (TradeComment == "MA MACD")
      {
         MessageBox("You cannot run this robot until changed the TradeComment input from the default of MA MACD." + NL 
                    + "Please reload the robot with a new TradeComment input.");
         Comment("                This robot can do nothing. Please reload it");
         DisabledMessage = "You need to change the TradeComment input";
         RobotDisabled = true;
         return;
      }//if (MagicNumber == 876987)            
   }//if (!IsDemo)
   
   
   if (Period() != PERIOD_D1 && Period() != PERIOD_H1)
   {
      MessageBox("This is an H1 or D1 trading strategy. Consider changing the timr frame on your chart.");
   }//if (Period() != PERIOD_D1 && Period() != PERIOD_H1)
   
   
   Gap="";
   if (DisplayGapSize >0)
   {
      for (int cc=0; cc< DisplayGapSize; cc++)
      {
         Gap = StringConcatenate(Gap, " ");
      }   
   }

   //Adjust settings for 4 digit crim
   if (Digits == 2 || Digits == 4)
   {
      JumpingStopPips/= 10;
      BreakEvenProfit/= 10;
      PipsAwayFromVisualJS/= 10;
      MaxSpread/= 10;
      //MinStopLoss/= 10;
   }//if (Digits == 2 || Digits == 4)

   
   
//----
   return(0);
}
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
{
//----
   Comment("");
//----
   return(0);
}

double SetStopLoss(int type)
{
   //Returns a stop that is the highest\lowest of the previous 5 bars
   
   if (type == 0)
   {
      double stop = Low[0];
      for (int cc = 1; cc < 5; cc++)
      {
         if (Low[cc] < stop) stop = Low[cc];
      }//if (type = 0)   
   }//if (type == 0)

   if (type == 1)
   {
      stop = High[0];
      for (cc = 1; cc < 5; cc++)
      {
         if (High[cc] > stop) stop = High[cc];
      }//if (type = 0)   
   }//if (type == 0)

   return(stop);

}//End double SetStopLoss(int type)


bool SendSingleTrade(int type)
{
   // 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)
   
   WaitForConnection();
   RefreshRates();
   
   double StopLoss;
      
   // Buy trade
   if (type == 0)
   {
      double TradePrice=Ask;
      int colour = 32768;//green
      SetStopLoss(0);
   }//if (type == 0)   
   
   
   // Sell trade
   if (type == 1)
   {
      TradePrice=Bid;      
      colour = 255;//red
      SetStopLoss(1);
   }//if (type == 1)
   
   
   int slippage = 10;
   if (Digits == 3 || Digits == 5) slippage = 100;
   
   int ticket = OrderSend(Symbol(),type, Lot, TradePrice, slippage, StopLoss, 0, TradeComment, MagicNumber,0, colour);
   if (ticket < 0)
   {
      int err=GetLastError();
      Alert(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)

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
   
   //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
   
   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

void WaitForConnection()
{
   //An attempt to make the bot hang around until all the usual criminal disconnection suspects are overcome
   while (IsTradeContextBusy() || !IsConnected() ||!IsTradeAllowed() )
   {
      Comment("");
      Comment("Criminal is pissing around with the connection. Please hang on for a brief ice age.");
   }//while (IsTradeContextBusy() || !IsConnected() ||!IsTradeAllowed() )   
   
}//End void WaitForConnection()



void LookForOpenTrades()
{
   //Searches for open trades
   LongOpen = false;
   LongTicketNo = 0;
   
   ShortOpen = false;
   ShortTicketNo = 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() ) 
      {
         //Long
         if (OrderType() == OP_BUY)
         {
            LongTicketNo = OrderTicket();
            LongOpen = true;
         }//if (OrderType() == OP_BUY)
         
                           
         //Short
         if (OrderType() == OP_SELL)
         {
            ShortTicketNo = OrderTicket();
            ShortOpen = true;
         }//if (OrderType() == OP_SELL)       
         
      }//if (OrderMagicNumber() == MagicNumber && OrderSymbol() == symbol)       
   }//for (int cc = OrdersTotal() - 1; cc >= 0, cc--)
   

   
   
}//End void LookForOpenTrades()

bool NewsFilterCheck()
{
   // Checks for impending news events.
   // Deletes pending trades where necessary.
   // Closes open trades in profit or at be if required.
   // Returns true if news is inside the user parameters, else false

   
   if(!IsTesting())
   {      
      int  minutesUntilNextEvent = iCustom(NULL, 0, "FFCal", true, true, false, true, true, 1, 1);
      datetime dTime = minutesUntilNextEvent * 60;
      string sTime = TimeToStr(dTime, TIME_MINUTES);
      string sText;
      
      if (minutesUntilNextEvent>MinsUntilNews)//No news within the chosen timescale
      {
         sText = StringConcatenate("No News within the next ", sTime);
         bool TradeAllowed = true;
      }//if (minutesUntilNextEvent>MinsUntilNews)
      else
      {
         //News event within the chosen timescale
         int impactOfNextEvent = iCustom(NULL, 0, "FFCal", true, true, false, true, true, 2, 1);
         string sImpact = Num2Impact(impactOfNextEvent);
         if(StringLen(sImpact)>0) sImpact = "[" + sImpact + "] ";
         //sText = sImpact + "News in " + minutesUntilNextEvent + " mins.";
         sText = sImpact + "News in " + sTime;
         ScreenMessage = StringConcatenate(ScreenMessage, Gap, sText, NL);
         //Should the robot suspend trading?
         if (impactOfNextEvent >= NewsImpact)
         {
            TradeAllowed = false;//Suspend trading            
         }//if (impact >= NewsImpact)
         
      }//else
      ScreenMessage = StringConcatenate(ScreenMessage, Gap, sText, NL);
      return(TradeAllowed);
   }//if(!IsTesting())


}// End bool NewsFilterCheck()

string Num2Impact(int impact)
{
 if (impact == 3) return ("HIGH IMPACT");
 if (impact == 2) return ("MED IMPACT");
 if (impact == 1) return ("LOW IMPACT");
 else return ("");
}//End string Num2Impact(int impact)

void GetSpread()
{
   Spread = MarketInfo(Symbol(), MODE_SPREAD);
}//End void GetSpread()




bool CloseTrade(int ticket)
{
   //Attempts to close the trade. Returns true if succeeds, else false
   
   if (!OrderSelect(ticket, SELECT_BY_TICKET) ) return;
   WaitForConnection();
   bool result = OrderClose(ticket, OrderLots(), OrderClosePrice(), 1000, CLR_NONE);
   if (result) return(true);
   else return(false);

}//End bool CloseTrade(int ticket)

void GetSmaTradeDirection()
{
   //Sets TradeDirection according to the market in relation to the two sma's
   TradeDirection = none;
   
   sma50 = iMA(NULL, 0, 50, 0, MODE_SMA, PRICE_CLOSE, 0);
   sma100 = iMA(NULL, 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)
   
   //Check there are at least 10 pips in favour of the trade direction
   if (Ask > sma50 && Ask > sma100 && Close[1] > HighestSma) 
   {
      if (Ask - HighestSma > 10 * Point) TradeDirection = long;
   }//if (Ask > sma50 && Ask > sma100) 
   
   
   if (Bid < sma50 && Bid < sma100 && Close[1] < LowestSma)
   {
      if (LowestSma - Bid > 10 * Point) TradeDirection = short;
   }//if (Bid < sma50 && Bid < sma100) TradeDirection = short;
   

}//void GetSmaTradeDirection()

void GetMacdDirection()
{
   //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
   
   MacdDirection = none;
   MacdVal = iMACD(NULL, 0, 12, 26, 9, PRICE_CLOSE, MODE_MAIN, 0);

   if (MacdVal > 0)
   {
      for (int cc = 1; cc < 4; cc++)
      {
         double PrevMacdVal = iMACD(NULL, 0, 12, 26, 9, PRICE_CLOSE, MODE_MAIN, 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 = 1; cc < 4; cc++)
      {
         PrevMacdVal = iMACD(NULL, 0, 12, 26, 9, PRICE_CLOSE, MODE_MAIN, cc);
         if (PrevMacdVal > 0)
         {
            MacdDirection = short;
            return;
         }//if (MacdVal < 0)         
      }//for (int cc = 1; cc < 4: cc ++)
   }//if (MacdVal < 0)
   
   
   

}//End void GetMacdDirection()

void ShouldHalfTradeClose()
{
   //Only called if selected trade is in profit/
   //Closes half the trade at profit of risk x 2
   
   //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);
        LookForOpenTrades();
        OrderSelect(LongTicketNo, 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);
        LookForOpenTrades();
        OrderSelect(ShortTicketNo, 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()

bool ShouldRobotSleep()
{
   // 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);

}//bool ShouldRobotSleep()


//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
{

   if (RobotDisabled )
   {
      Comment("The robot has been suspended. Reason: ", DisabledMessage);
      return;
   }//if (RobotDisabled )

      
   //Check for open trades. Their ticket numbers are stored in variables set up for the purpose
   LookForOpenTrades();
   
   //Check for sleep time after trade closure for any reason
   if (!LongOpen && !ShortOpen)
   {
      bool SendToSleep = ShouldRobotSleep();// Compares closure time of history trade with current time, 
                                            // returning true for sleep or false. Will return false if no history trades
      if (SendToSleep)
      {
         Comment("Sleeping after trade closure");
         Sleep((SleepAfterTradeClosesMins*60)*1000);
      }//if (SendToSleep)
      
   }//if (!LongOpen && !ShortOpen)
   
   
   //Look for open trade exit
   if (LongOpen || ShortOpen) double sma50 = iMA(NULL, 0, 50, 0, MODE_SMA, PRICE_CLOSE, 0);
   if (LongOpen)
   {
      if (Ask < sma50 && Close[1] < sma50 && Ask < NormalizeDouble(sma50 - (10 * Point), Digits) ) CloseTrade(LongTicketNo);
   }//if (LongOpen)
   
   if (ShortOpen)
   {
      if (Bid > sma50 && Close[1] > sma50 && Bid > NormalizeDouble(sma50 + (10 * Point), Digits) ) CloseTrade(ShortTicketNo);
   }//if (LongOpen)
   
   
   ////////////////////////////////////////////////////////////////////////////////////////////
   //Stop loss manipulation
   if (JumpingStop)
   {
      if (LongOpen)
      {
         JumpingStopLoss(LongTicketNo);
      }//if (LongOpen)
   
      
      if (ShortOpen)
      {
         JumpingStopLoss(ShortTicketNo);
      }//if (ShortOpen)
   
   }//if (JumpingStop)
   
   //Partial trade closure
   if (LongOpen)
   {
      OrderSelect(LongTicketNo, SELECT_BY_TICKET);
      if (OrderCloseTime() == 0 && OrderProfit() > 0 && OrderLots() == Lot)
      {
         ShouldHalfTradeClose();
      }//if (OrderCloseTime() == 0 && OrderProfit() > 0)
      
   }//if (LongOpen)
   
      
   ////////////////////////////////////////////////////////////////////////////////////////////
   
   //Only allow one open trade at a time
   if (LongOpen || ShortOpen)
   {
      DisplayUserFeedback();
      return;
   }//if (LongOpen || ShortOpen)
   
   
   //Trade entry. Check overriding filters first
   if (UseNewsFilter)
   {
      bool TradeAllowed = true;
      TradeAllowed = NewsFilterCheck();
      if (!TradeAllowed)
      {
         DisplayUserFeedback();
         return;
      }//if (!TradeAllowed)
   }//if (UseNewsFilter)
   
   
   //Overriding filters ok, so continue
   GetSmaTradeDirection();//Looks at market compared to sma's and sets TradeDirection accordingly - none, long or short
   if (TradeDirection == none) TradeAllowed = false;
   if (TradeDirection == long && LongOpen) TradeAllowed = false;
   if (TradeDirection == short && ShortOpen) TradeAllowed = false;
   GetMacdDirection();
   
   //Cut all this short if trading is not allowed
   if (!TradeAllowed)
   {
      DisplayUserFeedback();
      return;
   }//if (!TradeAllowed)
   
   //Trading is allowed, so 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.
   if (MacdDirection == none) TradeAllowed = false;
   
   if (TradeAllowed)
   {
      if (TradeDirection == long && MacdDirection == long)
      {
         SendSingleTrade(0);
      }//if (Ask - HighestSma > 10 * Point) TradeDirection = long;
      
      if (TradeDirection == short && MacdDirection == short)
      {
         SendSingleTrade(1);
      }//if (Ask - HighestSma > 10 * Point) TradeDirection = long;
      
      
   
   }//if (TradeAllowed)
   
   
   ////////////////////////////////////////////////////////////////////////////////////////////
   
  
   DisplayUserFeedback();
  
   
}
//+------------------------------------------------------------------+