HiddenSLandTP

Author: Copyright 2017, M Wilson.
HiddenSLandTP
Orders Execution
Checks for the total of open ordersIt Closes Orders by itself
0 Views
0 Downloads
0 Favorites
HiddenSLandTP
//+------------------------------------------------------------------+
//|                                                HiddenSLandTP.mq4 |
//|                                        Copyright 2017, M Wilson. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2017, M Wilson."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict
//+------------------------------------------------------------------+
//| Class for storing trade data                                     |
//+------------------------------------------------------------------+
class C_Trade
  {
private:
   bool              DeleteLine(const string strName="HL_HSLTP_",bool boolReportError=True);
   bool              CreateHorizontalLine(const string name="HLine",double price=0,const color clr=clrRed,const ENUM_LINE_STYLE style=STYLE_SOLID,const int width=1,const bool back=false,const bool selection=true,const bool hidden=false,const long z_order=0);
public:
   //Trade Variables
   int               m_intTicket;
   int               m_intMagicNumber;
   string            m_strSymbol;
   int               m_intType;
   datetime          m_dtOpenTime;
   double            m_dblOpenPrice;
   double            m_dblStopLoss;
   double            m_dblTakeProfit;
   double            m_dblHiddenStopLoss;
   double            m_dblHiddenTakeProfit;
   bool              m_boolHasBeenClosed;
   int               m_intSelectAttempts;
   //Constructor/Desctructor
                     C_Trade(){m_boolHasBeenClosed=False;m_intSelectAttempts=0;};
                    ~C_Trade(){};
   //Public Functions
   bool              InitiateFromSelectedTrade();         //Populate class from selected trade data.
   bool              BreachHiddenStopLossOrTakeProfit();   //Look for breaches of the hidden stoploss or takeprofit.
   void              PlotSLandTP();                       //Draw stoploss and takeprofit as horizontal lines.
  };
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//|  Initiate Trade from Selected Trade                              |
//+------------------------------------------------------------------+
bool C_Trade::InitiateFromSelectedTrade()
  {
//Order Select on an active trade must have been called before this function is run
//It populates the trade using the details of the selected trade.

//Only works on live buy/sell orders
   if(!(OrderType()==OP_BUY || OrderType()==OP_SELL)) return False;

//Replicate the selected trade.
   this.m_intTicket=OrderTicket();
   this.m_intMagicNumber=OrderMagicNumber();
   this.m_strSymbol=OrderSymbol();
   this.m_intType=OrderType();
   this.m_dtOpenTime=OrderOpenTime();
   this.m_dblOpenPrice=OrderOpenPrice();
   this.m_dblStopLoss=OrderStopLoss();
   this.m_dblTakeProfit=OrderTakeProfit();
//By default, set the hidden stoploss and takeprofit to the current stoploss and takeprofit.
//They need to be changed later on.
   this.m_dblHiddenStopLoss=this.m_dblStopLoss;
   this.m_dblHiddenTakeProfit=this.m_dblHiddenTakeProfit;

   return True;
  }
//+------------------------------------------------------------------+
//|  Check for breach of hidden stoploss or takeprofit               |
//+------------------------------------------------------------------+
bool C_Trade::BreachHiddenStopLossOrTakeProfit()
  {
   bool boolRet=False;

   RefreshRates();

   if(this.m_intType==OP_BUY)
     {  //Test buy trade to see if the bid has passed the hidden stoploss or takeprofit
      double dblBid=MarketInfo(this.m_strSymbol,MODE_BID);
      if(dblBid>this.m_dblHiddenTakeProfit || dblBid<this.m_dblHiddenStopLoss) boolRet=True;
     }
   else if(this.m_intType==OP_SELL)
     {  //Test sell trade to see if the ask has passed the hidden stoploss or takeprofit
      double dblAsk=MarketInfo(this.m_strSymbol,MODE_ASK);
      if(dblAsk<this.m_dblHiddenTakeProfit || dblAsk>this.m_dblHiddenStopLoss) boolRet=True;
     }

   return boolRet;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void C_Trade::PlotSLandTP()
  {
//First define name of hidden stoploss and takeprofit
   string strSL = "HL_HSL_"+IntegerToString(this.m_intTicket);
   string strTP = "HL_HTP_"+IntegerToString(this.m_intTicket);

//Delete the lines
   this.DeleteLine(strSL);
   this.DeleteLine(strTP);

//Now add the lines.
   this.CreateHorizontalLine(strSL,this.m_dblHiddenStopLoss,clrRed,STYLE_SOLID,2,True);
   this.CreateHorizontalLine(strTP,this.m_dblHiddenTakeProfit,clrLightGreen,STYLE_SOLID,2,True);

//Refresh the chart
   ChartRedraw();
  }
//+------------------------------------------------------------------+
//|  Private Function to delete line                                 |
//+------------------------------------------------------------------+
bool C_Trade::DeleteLine(const string strName="HL_HSLTP_",bool boolReportError=True)
  {
//Delete's any kind of line, you just have to give it the right name
   ResetLastError();

   if(ObjectFind(0,strName)>=0)
     {
      if(!ObjectDelete(0,strName))
        {
         if(boolReportError) Print(__FUNCTION__,": failed to delete the line: ",strName," Error code = ",GetLastError());
         return(false);
        }
     }

   return(true);
  }
//+------------------------------------------------------------------+
//|  Private Function to create line                                 |
//+------------------------------------------------------------------+
bool C_Trade::CreateHorizontalLine(const string          name="HLine",// line name
                                   double                price=0,// line price
                                   const color           clr=clrRed,        // line color
                                   const ENUM_LINE_STYLE style=STYLE_SOLID, // line style
                                   const int             width=1,           // line width
                                   const bool            back=false,        // in the background
                                   const bool            selection=true,    // highlight to move
                                   const bool            hidden=false,// hidden in the object list
                                   const long            z_order=0) // priority for mouse click
  {

   ResetLastError();

   if(!ObjectCreate(0,name,OBJ_HLINE,0,0,price))
     {
      Print(__FUNCTION__,": failed to create a horizontal line! Error code = ",GetLastError());
      return(false);
     }

   ObjectSetInteger(0,name,OBJPROP_COLOR,clr);

   ObjectSetInteger(0,name,OBJPROP_STYLE,style);

   ObjectSetInteger(0,name,OBJPROP_WIDTH,width);

   ObjectSetInteger(0,name,OBJPROP_BACK,back);
//--- enable (true) or disable (false) the mode of moving the line by mouse
//--- when creating a graphical object using ObjectCreate function, the object cannot be
//--- highlighted and moved by default. Inside this method, selection parameter
//--- is true by default making it possible to highlight and move the object
   ObjectSetInteger(0,name,OBJPROP_SELECTABLE,selection);
   ObjectSetInteger(0,name,OBJPROP_SELECTED,selection);
//--- hide (true) or display (false) graphical object name in the object list
   ObjectSetInteger(0,name,OBJPROP_HIDDEN,hidden);
//--- set the priority for receiving the event of a mouse click in the chart
   ObjectSetInteger(0,name,OBJPROP_ZORDER,z_order);
//--- successful execution
   return(true);
  }
//+------------------------------------------------------------------+
//| Enum to specify if relative to open price or mid.                |
//+------------------------------------------------------------------+
enum RelativePrice
  {
   OpenPrice,
   Mid
  };

//+------------------------------------------------------------------+
//| Inputs to EA.                                                    |
//+------------------------------------------------------------------+
input int I_StopLoss_Points=50;           //Desired StopLoss in points.
input int I_TakeProfit_Points=50;         //Desired TakeProfit in points.
input RelativePrice I_Relative=OpenPrice; //Use OpenPrice or Mid when calculating StopLoss or TakeProfit.
input bool I_DrawLines=True;             //Draw Lines on Chart.
input int I_Slippage=5;                   //Slippage.

//+------------------------------------------------------------------+
//| Global Vaiables.                                                 |
//+------------------------------------------------------------------+
C_Trade *g_objTradeArray[];               //Global Array to store the hidden instruments.
bool g_boolPrintConculsion;               //Global Variable indicating if we print a comment when all trades have been closed.
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {

//Blank the comment
   Comment("");

//Initiate variable telling us when to print out that all trades have been closed.
   g_boolPrintConculsion=True;

//Scan through the live trades and build an array containing the trades
   int intCount=OrdersTotal();
   for(int i=0;i<intCount;i++)
     {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
        {
         //Only process trades that are associated with the active charts symbol.
         if(OrderSymbol()==Symbol())
           {
            C_Trade *objTrade=new C_Trade();
            if(objTrade.InitiateFromSelectedTrade())
              {
               //Get the point for the symbol
               double dblPoint=MarketInfo(objTrade.m_strSymbol,MODE_POINT);
               int intDigits=(int)MarketInfo(objTrade.m_strSymbol,MODE_DIGITS);

               //Depending upon the input, calculate the reference price relative to either the open price of the trade,
               //or the current mid of the trades symbol.
               double dblRefPrice=objTrade.m_dblOpenPrice;
               if(I_Relative==Mid)
                 {
                  dblRefPrice=(MarketInfo(objTrade.m_strSymbol,MODE_BID)+MarketInfo(objTrade.m_strSymbol,MODE_ASK))/2;
                 }

               //We have a live trade that has been populated, now add the hidden stoploss and hidden take profit.
               if(objTrade.m_intType==OP_BUY)
                 {
                  objTrade.m_dblHiddenStopLoss=NormalizeDouble(dblRefPrice-(I_StopLoss_Points*dblPoint),intDigits);
                  objTrade.m_dblHiddenTakeProfit=NormalizeDouble(dblRefPrice+(I_TakeProfit_Points*dblPoint),intDigits);

                 }
               else if(objTrade.m_intType==OP_SELL)
                 {
                  objTrade.m_dblHiddenStopLoss=NormalizeDouble(dblRefPrice+(I_StopLoss_Points*dblPoint),intDigits);
                  objTrade.m_dblHiddenTakeProfit=NormalizeDouble(dblRefPrice-(I_TakeProfit_Points*dblPoint),intDigits);
                 }

               //Print out a record of the hidden stoploss and take profit.
               string strPrint=" Ticket: "+IntegerToString(OrderTicket())+" HiddenSL: "+DoubleToString(objTrade.m_dblHiddenStopLoss)+" HiddenTP: "+DoubleToString(objTrade.m_dblHiddenTakeProfit);
               Print(__FUNCTION__,strPrint);

               //Potentially draw the lines
               if(I_DrawLines) objTrade.PlotSLandTP();

               //Add the trade to the array.
               int intArray=ArraySize(g_objTradeArray);
               ArrayResize(g_objTradeArray,intArray+1);
               g_objTradeArray[intArray]=objTrade;
               objTrade=NULL;
              }
            else
              {
               delete objTrade;
              }
           }
        }
      else
        {
         Print(__FUNCTION__," Could not select trade by position");
        }
     }

   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//Blank the comment
   Comment("");

//Delete the array of hidden trades.
   int intArray=ArraySize(g_objTradeArray);
   for(int i=0;i<intArray;i++)
     {
      if(g_objTradeArray[i]!=NULL)  delete g_objTradeArray[i];
     }
   ArrayFree(g_objTradeArray);

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//Check the array for any breaches of the hidden stoploss.
   int intCount=ArraySize(g_objTradeArray);
   int intOpenTrades=0;
   for(int i=0;i<intCount;i++)
     {
      if(!g_objTradeArray[i].m_boolHasBeenClosed)
        {
         intOpenTrades++;
         if(g_objTradeArray[i].BreachHiddenStopLossOrTakeProfit())
           {
            //Because the array is not cleaned when a trade is closed, trades may exist in the array that are no longer live.
            //Close the trade only if it can be found successfully.
            if(OrderSelect(g_objTradeArray[i].m_intTicket,SELECT_BY_TICKET,MODE_TRADES))
              {

               //Get the appropraite close price based upon the order type.   
               double dblClosePrice=MarketInfo(OrderSymbol(),MODE_BID);
               if(OrderType()==OP_SELL) dblClosePrice=MarketInfo(OrderSymbol(),MODE_ASK);

               //Attempt to close the order.   This could be enhanced with some error checking, I have left this out
               //for now.
               bool boolRes=OrderClose(OrderTicket(),OrderLots(),dblClosePrice,I_Slippage,clrWhite);

               //If successful, mark the trade in the array as being complete.
               if(boolRes)
                 {
                  g_objTradeArray[i].m_boolHasBeenClosed=True;
                 }
               else
                 {
                  Print(__FUNCTION__," Error Closing Ticket: "+IntegerToString(g_objTradeArray[i].m_intTicket)+" Error: ",GetLastError());
                 }
              }
            else
              {
               //If we cannot select the trade, then see if it exists in the history
               if(OrderSelect(g_objTradeArray[i].m_intTicket,SELECT_BY_TICKET,MODE_HISTORY))
                 {  //We have found the ticket in the history, assume the ticket has been closed by another method.
                  g_objTradeArray[i].m_boolHasBeenClosed=True;
                 }
               else
                 {
                  //Could not select the trade, try up to 3 times, and then assume it has been closed
                  g_objTradeArray[i].m_intSelectAttempts++;
                  if(g_objTradeArray[i].m_intSelectAttempts>3)
                    {
                     Print(__FUNCTION__," Could not select trade, assume it has been closed: "+IntegerToString(g_objTradeArray[i].m_intTicket));
                     g_objTradeArray[i].m_boolHasBeenClosed=True;
                    }
                 }
              }
           }
        }
     }

//Add a comment indicating when the EA has closed all of the trades.
   if(intOpenTrades<1 && intCount>0 && g_boolPrintConculsion)
     {
      Comment("TASK COMPLETE - ALL INITIAL TRADES HAVE BEEN CLOSED");
      Print(__FUNCTION__," TASK COMPLETE - ALL INITIAL TRADES HAVE BEEN CLOSED");
      g_boolPrintConculsion=False;
     }
  }
//+------------------------------------------------------------------+

Comments