MQL5 Wizard: How to Teach an EA to Open Pending Orders at Any Price

Vladimir Karputov | 25 September, 2013

Introduction

An Expert Advisor generated using the MQL5 Wizard can only open pending orders at the fixed distance from the current price. This means that if the market situation changes (e.g. a change in market volatility), the Expert Advisor will have to be run again with new parameters.

This would not be suitable for many trading systems. In most cases, the price level for pending orders is determined dynamically by a trading system. And the distance from the current price is constantly changing. In this article, we will discuss how to modify an Expert Advisor generated using the MQL5 Wizard so that it can open pending orders at varying distances from the current price.


1. The Mechanism of Opening Pending Orders in the Expert Advisor Generated Using the MQL5 Wizard

A generated Expert Advisor would have approximately the same code in its header as provided below:

//+------------------------------------------------------------------+
//| Inputs                                                           |
//+------------------------------------------------------------------+
//--- inputs for expert
input string             Expert_Title="ExpertMySignalEnvelopes.mq5";      // Document name
ulong                    Expert_MagicNumber        =3915;        // 
bool                     Expert_EveryTick          =false;       // 
//--- inputs for main signal
input int                Signal_ThresholdOpen      =10;          // Signal threshold value to open [0...100]
input int                Signal_ThresholdClose     =10;          // Signal threshold value to close [0...100]
input double             Signal_PriceLevel         =0.0;         // Price level to execute a deal
input double             Signal_StopLevel          =85.0;        // Stop Loss level (in points)
input double             Signal_TakeLevel          =195.0;       // Take Profit level (in points)
input int                Signal_Expiration         =0;           // Expiration of pending orders (in bars)
input int                Signal_Envelopes_PeriodMA =13;          // Envelopes(13,0,MODE_SMA,...) Period of averaging
input int                Signal_Envelopes_Shift    =0;           // Envelopes(13,0,MODE_SMA,...) Time shift
input ENUM_MA_METHOD     Signal_Envelopes_Method   =MODE_SMA;    // Envelopes(13,0,MODE_SMA,...) Method of averaging
input ENUM_APPLIED_PRICE Signal_Envelopes_Applied  =PRICE_CLOSE; // Envelopes(13,0,MODE_SMA,...) Prices series
input double             Signal_Envelopes_Deviation=0.2;         // Envelopes(13,0,MODE_SMA,...) Deviation
input double             Signal_Envelopes_Weight   =1.0;         // Envelopes(13,0,MODE_SMA,...) Weight [0...1.0]
//--- inputs for money
input double             Money_FixLot_Percent      =10.0;        // Percent
input double             Money_FixLot_Lots         =0.1;         // Fixed volume
//+------------------------------------------------------------------+

Please note the Signal_PriceLevel parameter. By default, the Expert Advisor is generated with Signal_PriceLevel=0. This parameter defines the distance from the current price. If it is equal to zero, an order will be opened at the current market price. To open a pending order, you should set a non-zero value for the Signal_PriceLevel parameter, i.e. Signal_PriceLevel can be both negative and positive.

The value of Signal_PriceLevel is usually a quite big number. The difference between negative and positive values is shown below:

Signal_PriceLevel=-50:

Fig. 1. Signal_PriceLevel=-50

Fig. 1. Signal_PriceLevel=-50

Signal_PriceLevel=50:

Fig. 2. Signal_PriceLevel=50

Fig. 2. Signal_PriceLevel=50

Thus, if Signal_PriceLevel=-50, a pending order will be opened at the price that is less favorable than the current price, whereas if Signal_PriceLevel=50, a pending order will be opened at the price that is better than the current price.

This version of the Expert Advisor opens Sell Stop and Buy Stop orders.


2. Where Do We Store Data on the Distance From the Price for Opening a Pending Order?

Let's first take a look at the below figure and then proceed to the comments:

Fig. 3. Storing data on the distance from the current price

Fig. 3. Storing data on the distance from the current price

Interpretation of the above figure.

Expert Advisor is the Expert Advisor generated using the MQL5 Wizard.

Thus, the Signal_PriceLevel parameter where the distance from the current price is stored and which was declared in the Expert Advisor is passed to the signal object of the CExpertSignal class.

The CExpertSignal class stores the value of the distance from the current price in the m_price_level variable declared with the protected class scope:

class CExpertSignal : public CExpertBase
  {
protected:
   //--- variables
   double            m_base_price;     // base price for detection of level of entering (and/or exit?)
   //--- variables for working with additional filters
   CArrayObj         m_filters;        // array of additional filters (maximum number of fileter is 64)
   //--- Adjusted parameters
   double            m_weight;         // "weight" of a signal in a combined filter
   int               m_patterns_usage; // bit mask of  using of the market models of signals
   int               m_general;        // index of the "main" signal (-1 - no)
   long              m_ignore;         // bit mask of "ignoring" the additional filter
   long              m_invert;         // bit mask of "inverting" the additional filter
   int               m_threshold_open; // threshold value for opening
   int               m_threshold_close;// threshold level for closing
   double            m_price_level;    // level of placing a pending orders relatively to the base price
   double            m_stop_level;     // level of placing of the "stop loss" order relatively to the open price
   double            m_take_level;     // level of placing of the "take profit" order relatively to the open price
   int               m_expiration;     // time of expiration of a pending order in bars


3. Structure of the Expert Advisor Generated Using the MQL5 Wizard

The Expert Advisor consists of several blocks with different functionality.


Fig. 4. Structure of the Expert Advisor 

Fig. 4. Structure of the Expert Advisor

Interpretation of the above figure:


4. Expert Advisor Blocks Advisable for Modification

As you could see from the structure of the Expert Advisor generated using the MQL5 Wizard, there are base class blocks. Base classes are part of the Standard Library.

The classes per se are descendants of other base classes and they in turn consist of one or more base classes. Below you can find the first few lines of the code of two classes - CExpert and CExpertSignal:

//+------------------------------------------------------------------+
//|                                                       Expert.mqh |
//|                   Copyright 2009-2013, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#include "ExpertBase.mqh"
#include "ExpertTrade.mqh"
#include "ExpertSignal.mqh"
#include "ExpertMoney.mqh"
#include "ExpertTrailing.mqh"
//+------------------------------------------------------------------+
.
.
.
class CExpert : public CExpertBase

and

//+------------------------------------------------------------------+
//|                                                 ExpertSignal.mqh |
//|                   Copyright 2009-2013, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#include "ExpertBase.mqh"
.
.
.
class CExpertSignal : public CExpertBase

I am strongly against any modifications of the base classes:

  1. When MetaEditor is updated, all changes you make to the base classes are overridden and the base classes are restored to their initial state.
  2. Inheritance would be more appropriate in this case. But then you will have to modify the ENTIRE Standard Library.

Instead, it would be best to modify the block of the Expert Advisor and trading signal generator modules, especially since our trading system will already have one modified module in use - the trading signal generator of the Envelopes indicator.

So, that's settled: we will make changes to the blocks of the Expert Advisor and the block of the trading signal generator.


5. The Implementation Logic

The pointer will be passed from the Expert Advisor to the trading signal generator.

For this purpose, we need to additionally declare a variable with the protected scope and write a method that stores the pointer from the Expert Advisor in the internal variable:


  Fig. 5. The Implementation Logic

Fig. 5. The Implementation Logic


6. Trading System

The chart time frame is D1. The indicator to be used is Envelopes with the averaging period of 13 and Exponential averaging method. Types of orders that the Expert Advisor can open are Sell Stop and Buy Stop.

If the previous bar was bullish, we set a Sell Stop order. If the previous bar was bearish, we set a Buy Stop order. In other words, we hope for the pullback:

Fig. 6. Trading System

Fig. 6. Trading System

To generate trading signals as required by the trading system, the standard module of the trading signal generator SignalEnvelopes.mqh has been modified.

Note that here you can use any trading signal generator from the Standard Library.


7. Trading Signal Generator Modification. Getting the Bar Price

So, let's start. I need to say that I prefer saving my programs in MQL5 Storage.

The first thing we should do in order to start modifying the trading signal generator is to create a blank include file, delete everything from it and paste the entire contents of the standard trading signal generator of the Envelopes indicator.

By default the trading signal generator must be located under ...MQL5\Include\Expert\Signal. Not to overload the ...\Signal folder of the Standard Library with too much information, let's create a new folder under the ...\Expert folder and call it \MySignals:

Fig. 7. Creating the MySignals folder

Fig. 7. Creating the MySignals folder

Next, we will create an include file using the MQL5 Wizard.

In MetaEditor, select 'New' under the File menu and then select 'Include file (*.mqh)'.

Fig. 8. MQL5 Wizard. Creating an include file

Fig. 8. MQL5 Wizard. Creating an include file

The name of our signal generator class will be MySignalEnvelopes.

And it will be located under: Include\Expert\MySignals\MySignalEnvelopes. Let's specify it:

Fig. 9. MQL5 Wizard. Location of the include file

Fig. 9. MQL5 Wizard. Location of the include file

After you click 'Finish', the MQL5 Wizard will generate an empty template.

The generated MySignalEnvelopes.mqh file must then be added to MQL5 Storage:

Fig. 10. MQL5 Storage. Adding the file

Fig. 10. MQL5 Storage. Adding the file

Once the file has been added, we need to commit the changes to MQL5 Storage:

Fig. 11. MQL5 Storage. Committing the changes

Fig. 11. MQL5 Storage. Committing the changes

Having completed the above steps, we can proceed to modifying our trading signal generator.

Since the generator is based on the \Include\Expert\Signal\SignalEnvelopes.mqh file, we copy the entire contents of the file and paste it into the generator file, only leaving the original header:

//+------------------------------------------------------------------+
//|                                            MySignalEnvelopes.mqh |
//|                              Copyright © 2013, Vladimir Karputov |
//|                                           http://wmua.ru/slesar/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2013, Vladimir Karputov"
#property link      "http://wmua.ru/slesar/"
#include <Expert\ExpertSignal.mqh>
// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Signals of indicator 'Envelopes'                           |
//| Type=SignalAdvanced                                              |
//| Name=Envelopes                                                   |
//| ShortName=Envelopes                                              |
//| Class=CSignalEnvelopes                                           |
//| Page=signal_envelopes                                            |
//| Parameter=PeriodMA,int,45,Period of averaging                    |
//| Parameter=Shift,int,0,Time shift                                 |
//| Parameter=Method,ENUM_MA_METHOD,MODE_SMA,Method of averaging     |
//| Parameter=Applied,ENUM_APPLIED_PRICE,PRICE_CLOSE,Prices series   |
//| Parameter=Deviation,double,0.15,Deviation                        |
//+------------------------------------------------------------------+
// wizard description end
//+------------------------------------------------------------------+
//| Class CSignalEnvelopes.                                          |
//| Purpose: Class of generator of trade signals based on            |
//|          the 'Envelopes' indicator.                              |
//| Is derived from the CExpertSignal class.                         |
//+------------------------------------------------------------------+
class CSignalEnvelopes : public CExpertSignal
  {
protected:
   CiEnvelopes       m_env;            // object-indicator
   //--- adjusted parameters
   int               m_ma_period;      // the "period of averaging" parameter of the indicator
   int               m_ma_shift;       // the "time shift" parameter of the indicator
   ENUM_MA_METHOD    m_ma_method;      // the "method of averaging" parameter of the indicator
   ENUM_APPLIED_PRICE m_ma_applied;    // the "object of averaging" parameter of the indicator
   double            m_deviation;      // the "deviation" parameter of the indicator
   double            m_limit_in;       // threshold sensitivity of the 'rollback zone'
   double            m_limit_out;      // threshold sensitivity of the 'break through zone'
   //--- "weights" of market models (0-100)
   int               m_pattern_0;      // model 0 "price is near the necessary border of the envelope"
   int               m_pattern_1;      // model 1 "price crossed a border of the envelope"

public:
                     CSignalEnvelopes(void);
                    ~CSignalEnvelopes(void);
   //--- methods of setting adjustable parameters
   void              PeriodMA(int value)                 { m_ma_period=value;        }
   void              Shift(int value)                    { m_ma_shift=value;         }
   void              Method(ENUM_MA_METHOD value)        { m_ma_method=value;        }
   void              Applied(ENUM_APPLIED_PRICE value)   { m_ma_applied=value;       }
   void              Deviation(double value)             { m_deviation=value;        }
   void              LimitIn(double value)               { m_limit_in=value;         }
   void              LimitOut(double value)              { m_limit_out=value;        }
   //--- methods of adjusting "weights" of market models
   void              Pattern_0(int value)                { m_pattern_0=value;        }
   void              Pattern_1(int value)                { m_pattern_1=value;        }
   //--- method of verification of settings
   virtual bool      ValidationSettings(void);
   //--- method of creating the indicator and timeseries
   virtual bool      InitIndicators(CIndicators *indicators);
   //--- methods of checking if the market models are formed
   virtual int       LongCondition(void);
   virtual int       ShortCondition(void);

protected:
   //--- method of initialization of the indicator
   bool              InitMA(CIndicators *indicators);
   //--- methods of getting data
   double            Upper(int ind)                      { return(m_env.Upper(ind)); }
   double            Lower(int ind)                      { return(m_env.Lower(ind)); }
  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CSignalEnvelopes::CSignalEnvelopes(void) : m_ma_period(45),
                                           m_ma_shift(0),
                                           m_ma_method(MODE_SMA),
                                           m_ma_applied(PRICE_CLOSE),
                                           m_deviation(0.15),
                                           m_limit_in(0.2),
                                           m_limit_out(0.2),
                                           m_pattern_0(90),
                                           m_pattern_1(70)
  {
//--- initialization of protected data
   m_used_series=USE_SERIES_OPEN+USE_SERIES_HIGH+USE_SERIES_LOW+USE_SERIES_CLOSE;
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CSignalEnvelopes::~CSignalEnvelopes(void)
  {
  }
//+------------------------------------------------------------------+
//| Validation settings protected data.                              |
//+------------------------------------------------------------------+
bool CSignalEnvelopes::ValidationSettings(void)
  {
//--- validation settings of additional filters
   if(!CExpertSignal::ValidationSettings())
      return(false);
//--- initial data checks
   if(m_ma_period<=0)
     {
      printf(__FUNCTION__+": period MA must be greater than 0");
      return(false);
     }
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Create indicators.                                               |
//+------------------------------------------------------------------+
bool CSignalEnvelopes::InitIndicators(CIndicators *indicators)
  {
//--- check pointer
   if(indicators==NULL)
      return(false);
//--- initialization of indicators and timeseries of additional filters
   if(!CExpertSignal::InitIndicators(indicators))
      return(false);
//--- create and initialize MA indicator
   if(!InitMA(indicators))
      return(false);
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Initialize MA indicators.                                        |
//+------------------------------------------------------------------+
bool CSignalEnvelopes::InitMA(CIndicators *indicators)
  {
//--- check pointer
   if(indicators==NULL)
      return(false);
//--- add object to collection
   if(!indicators.Add(GetPointer(m_env)))
     {
      printf(__FUNCTION__+": error adding object");
      return(false);
     }
//--- initialize object
   if(!m_env.Create(m_symbol.Name(),m_period,m_ma_period,m_ma_shift,m_ma_method,m_ma_applied,m_deviation))
     {
      printf(__FUNCTION__+": error initializing object");
      return(false);
     }
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| "Voting" that price will grow.                                   |
//+------------------------------------------------------------------+
int CSignalEnvelopes::LongCondition(void)
  {
   int result=0;
   int idx   =StartIndex();
   double close=Close(idx);
   double upper=Upper(idx);
   double lower=Lower(idx);
   double width=upper-lower;
//--- if the model 0 is used and price is in the rollback zone, then there is a condition for buying
   if(IS_PATTERN_USAGE(0) && close<lower+m_limit_in*width && close>lower-m_limit_out*width)
      result=m_pattern_0;
//--- if the model 1 is used and price is above the rollback zone, then there is a condition for buying
   if(IS_PATTERN_USAGE(1) && close>upper+m_limit_out*width)
      result=m_pattern_1;
//--- return the result
   return(result);
  }
//+------------------------------------------------------------------+
//| "Voting" that price will fall.                                   |
//+------------------------------------------------------------------+
int CSignalEnvelopes::ShortCondition(void)
  {
   int result  =0;
   int idx     =StartIndex();
   double close=Close(idx);
   double upper=Upper(idx);
   double lower=Lower(idx);
   double width=upper-lower;
//--- if the model 0 is used and price is in the rollback zone, then there is a condition for selling
   if(IS_PATTERN_USAGE(0) && close>upper-m_limit_in*width && close<upper+m_limit_out*width)
      result=m_pattern_0;
//--- if the model 1 is used and price is above the rollback zone, then there is a condition for selling
   if(IS_PATTERN_USAGE(1) && close<lower-m_limit_out*width)
      result=m_pattern_1;
//--- return the result
   return(result);
  }
//+------------------------------------------------------------------+

Now, we will be working on modifications of some parts of the code.

To avoid confusion, the modified code will be highlighted:

//+------------------------------------------------------------------+
//|                                                     MySignal.mqh |
//|                              Copyright © 2013, Vladimir Karputov |
//|                                           http://wmua.ru/slesar/ |
//+------------------------------------------------------------------+

The modified code is the code that needs to be copied and pasted into the trading signal generator. I hope that such highlighting will help you better understand the code.

Since we are writing our own class of the trading signal generator, its name should be different from the name of the base class. We therefore replace CSignalEnvelopes with CMySignalEnvelopes throughout the entire code:

Fig. 12. Renaming the class

Fig. 12. Renaming the class

To ensure that the trading signal generator class is displayed in the MQL5 Wizard under its name, change the class name in the description block

//| Title=Signals of indicator 'Envelopes'                           |

to

//| Title=Signals of indicator 'MySignalEnvelopes'                   |

Change the MA period value

//| Parameter=PeriodMA,int,45,Period of averaging                    |

to 13 (this is only my suggestion, you can set any value you prefer)

//| Parameter=PeriodMA,int,13,Period of averaging                    |

In addition, we also modify the Deviation parameter

//| Parameter=Deviation,double,0.15,Deviation                        |

by setting a greater value

//| Parameter=Deviation,double,1.15,Deviation                        |

According to our implementation logic, we need to declare an internal variable that will store the pointer to the main signal.

Since this must be an internal variable (within the trading signal generator class scope only), it will be added to the following code block:

protected:
   CiEnvelopes       m_env;          // object-indicator
   //--- adjusted parameters
   int               m_ma_period;    // the "period of averaging" parameter of the indicator
   int               m_ma_shift;     // the "time shift" parameter of the indicator
   ENUM_MA_METHOD    m_ma_method;     // the "method of averaging" parameter of the indicator
   ENUM_APPLIED_PRICE m_ma_applied;    // the "object of averaging" parameter of the indicator
   double            m_deviation;    // the "deviation" parameter of the indicator
   //--- "weights" of market models (0-100)
   int               m_pattern_0;      // model 0
   CExpertSignal    *m_signal;         // storing the pointer to the main signal

Please also note that I deleted the unnecessary variables from the code. 

The method for storing the pointer to the main signal will be declared in another code block - the 'method of setting the pointer to the main signal'. Here, I also deleted some irrelevant methods.

public:
                     CMySignalEnvelopes(void);
                    ~CMySignalEnvelopes(void);
   //--- methods of setting adjustable parameters
   void              PeriodMA(int value)                 { m_ma_period=value;        }
   void              Shift(int value)                    { m_ma_shift=value;         }
   void              Method(ENUM_MA_METHOD value)        { m_ma_method=value;        }
   void              Applied(ENUM_APPLIED_PRICE value)   { m_ma_applied=value;       }
   void              Deviation(double value)             { m_deviation=value;        }
   //--- methods of adjusting "weights" of market models
   void              Pattern_0(int value)                { m_pattern_0=value;        }
   //--- method of verification of settings
   virtual bool      ValidationSettings(void);
   //--- method of creating the indicator and timeseries
   virtual bool      InitIndicators(CIndicators *indicators);
   //--- methods of checking if the market models are formed
   virtual int       LongCondition(void);
   virtual int       ShortCondition(void);
   //--- method of setting the pointer to the main signal
   virtual bool      InitSignal(CExpertSignal *signal=NULL);

Let's now specify some modified parameters in the constructor and delete the variables that are no longer needed:

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CMySignalEnvelopes::CMySignalEnvelopes(void) : m_ma_period(13),
                                               m_ma_shift(0),
                                               m_ma_method(MODE_SMA),
                                               m_ma_applied(PRICE_CLOSE),
                                               m_deviation(1.15),
                                               m_pattern_0(50)  

At this point, we can proceed to modifying the trading signal generation logic according to our trading system.

The code block responsible for a buy signal:

int CMySignalEnvelopes::LongCondition(void)
  {
   int result=0;
   int idx   =StartIndex();
   double close=Close(idx);
   double upper=Upper(idx);
   double lower=Lower(idx);
   double width=upper-lower;
//--- if the model 0 is used and price is in the rollback zone, then there is a condition for buying
   if(IS_PATTERN_USAGE(0) && close<lower+m_limit_in*width && close>lower-m_limit_out*width)
      result=m_pattern_0;
//--- if the model 1 is used and price is above the rollback zone, then there is a condition for buying
   if(IS_PATTERN_USAGE(1) && close>upper+m_limit_out*width)
      result=m_pattern_1;
//--- return the result
   return(result);
  }

will be as shown below, following the necessary changes:

int CMySignalEnvelopes::LongCondition(void) //---buy
  {
   int result=0;
   int idx   =StartIndex();
   double open=Open(idx);
   double close=Close(idx);
   double prlevel;
      if(IS_PATTERN_USAGE(0) && close<open)
        {
         prlevel=GetPriceLevelStopp(open,Open(0));
         m_signal.PriceLevel(prlevel);
         result=m_pattern_0;
        }
//--- return the result
   return(result);
  }

The code block responsible for a sell signal:

int CMySignalEnvelopes::ShortCondition(void)
  {
   int result  =0;
   int idx     =StartIndex();
   double close=Close(idx);
   double upper=Upper(idx);
   double lower=Lower(idx);
   double width=upper-lower;
//--- if the model 0 is used and price is in the rollback zone, then there is a condition for selling
   if(IS_PATTERN_USAGE(0) && close>upper-m_limit_in*width && close<upper+m_limit_out*width)
      result=m_pattern_0;
//--- if the model 1 is used and price is above the rollback zone, then there is a condition for selling
   if(IS_PATTERN_USAGE(1) && close<lower-m_limit_out*width)
      result=m_pattern_1;
//--- return the result
   return(result);
  }

will be as shown below, following the necessary changes:

int CMySignalEnvelopes::ShortCondition(void) //---sell
  {
   int result  =0;
   int idx     =StartIndex();
   double open=Open(idx);
   double close=Close(idx);
   double prlevel;
      if(IS_PATTERN_USAGE(0) && close>open)
        {
         prlevel=GetPriceLevelStopp(Open(0),open);
         m_signal.PriceLevel(prlevel);
         result=m_pattern_0;
        }
//--- return the result
   return(result);
  }


8. A Few Comments on the Signal Code Block

If the required condition for a certain signal is met, we call the GetPriceLevelStopp method that returns a number like "20" or "15" - the value of the distance from the current price.

This is followed by calling the PriceLevel method of the m_signal object (which sets the distance for determining the pending order level price). It should be reminded that m_signal is the CExpertSignal class object that stores the pointer to the main signal.

The code of the GetPriceLevelStopp method is provided below:

double CMySignalEnvelopes::GetPriceLevelStopp(double price_0,double min)
  {
   double level;
   double temp;
   temp-=(price_0-min)/PriceLevelUnit();
   level=NormalizeDouble(temp,0);
   return(level);
  }

We need to declare this method in the class header:

protected:
   //--- method of initialization of the indicator
   bool              InitMA(CIndicators *indicators);
   //--- methods of getting data
   double            Upper(int ind)                      { return(m_env.Upper(ind)); }
   double            Lower(int ind)                      { return(m_env.Lower(ind)); }
   double            GetPriceLevelStopp(double price,double min);
  };

Another method that we will need is the method of passing the pointer to the main signal to the internal variable:

bool CMySignalEnvelopes::InitSignal(CExpertSignal *signal)
  {
   m_signal=signal;
   return(true);
  }

 After that we should create an Expert Advisor in the MQL5 Wizard and include in it the signal module 'MySignalEnvelopes'.

We also need to add the InitSignal method call to the code of the Expert Advisor generated using the MQL5 Wizard:

//--- Set filter parameters
   filter0.PeriodMA(Signal_Envelopes_PeriodMA);
   filter0.Shift(Signal_Envelopes_Shift);
   filter0.Method(Signal_Envelopes_Method);
   filter0.Applied(Signal_Envelopes_Applied);
   filter0.Deviation(Signal_Envelopes_Deviation);
   filter0.Weight(Signal_Envelopes_Weight);
   filter0.InitSignal(signal);
//...

For better visualization of the operation of the Expert Advisor, I have provided a short video:

The code of the Expert Advisor generated using the MQL5 Wizard, as well as the code of the signal module, is attached to the article.

Below you can see the testing results of the Expert Advisor. It was tested for EURUSD and USDJPY with the following parameters: testing period 2013.01.01 - 2013.09.01, time frame - D1, Stop Loss level = 85, Take Profit level = 195.

Fig. 13. Testing for EURUSD on D1

Fig. 13. Testing for EURUSD on D1

Fig. 14. Testing for USDJPY on D1

Fig. 14. Testing for USDJPY on D1


Conclusion

We have just seen how we can modify the code of the trading signal module for the implementation of the functionality allowing us to set pending orders at any distance from the current price: it may be the Close or Open price of the previous bar or the value of the moving average. There are plenty of options. Important is that you can set any opening price for a pending order.

The article has demonstrated how we can access the pointer to the main signal, and hence the CExpertSignal class methods.  I believe that the article will prove useful to traders who trade with pending orders.