Download MetaTrader 5

MQL5 Cookbook: Using Indicators to Set Trading Conditions in Expert Advisors

24 May 2013, 10:07
Anatoli Kazharski
3
6 980

Introduction

In this article, the Expert Advisor will be enhanced with indicators whose values will be used to check position opening conditions. To spice it up, we will create a drop-down list in the external parameters to be able to select one out of three trading indicators.

Please be reminded, just in case: we continue to modify the Expert Advisor we have been working on throughout the preceding articles of the MQL5 Cookbook series. The last version of the Expert Advisor can be downloaded from the article entitled "MQL5 Cookbook: The History of Deals And Function Library for Getting Position Properties".

In addition, this article will feature a function that we will create to check whether trading operations can or cannot be performed. The position opening function will be modified so as to enable the Expert Advisor to determine the trade mode (Instant Execution and Market Execution).

Since the code of the Expert Advisor, following all the enhancements and improvements made in the previous articles, already exceeds 1,500 lines, it will be getting less and less convenient with every new feature added. So, the logical solution is to divide it into several categories as separate library files. Now that the objectives have been set, let's start.

 

Expert Advisor Development

We place the source code of the Expert Advisor (*.mq5) from the previous article into a separate folder, TestIndicatorConditions, in which we need to create the Include sub-folder. This is the folder where we will be creating include files (*.mqh). They can be generated using the MQL5 Wizard (Ctrl+N) or created manually in the required directory as standard text files (*.txt) and further renamed to *.mqh.

Below are the names of and comments to all the include files created:

  • Enums.mqh will contain all enumerations;
  • InfoPanel.mqh will feature functions for setting the info panel, creating and deleting graphical objects;
  • Errors.mqh will cover all functions that return error codes and deinitialization reasons;
  • TradeSignals.mqh will feature functions that fill arrays with prices and indicator values, as well as signal block;
  • TradeFunctions.mqh will contain trading functions;
  • ToString.mqh will cover functions that convert numerical values to string values;
  • Auxiliary.mqh will be used for other auxiliary functions.

To include these libraries to the main file, we use the #include directive. Since the main file of the Expert Advisor and the include file folder (Include) are located in the same folder, the code for including files will be as follows:

//--- Include custom libraries
#include "Include\Enums.mqh"
#include "Include\InfoPanel.mqh"
#include "Include\Errors.mqh"
#include "Include\TradeSignals.mqh"
#include "Include\TradeFunctions.mqh"
#include "Include\ToString.mqh"
#include "Include\Auxiliary.mqh"

Then, we will be able to open and modify them and move a part of the source code from the main file of the Expert Advisor.

To correctly navigate through the code, references to the adjacent header files, as well as to the main file of the Expert Advisor will be added to each header file. For example, for our library of trading functions, TradeFunctions.mqh, this will look like this:

//--- Connection with the main file of the Expert Advisor
#include "..\TestIndicatorConditions.mq5"
//--- Include custom libraries
#include "Enums.mqh"
#include "InfoPanel.mqh"
#include "Errors.mqh"
#include "TradeSignals.mqh"
#include "ToString.mqh"
#include "Auxiliary.mqh"

For files at the same nesting level, it is sufficient to simply specify the name. In order to go one level up, you need to put two dots before the back slash in the path.

Let's add enumeration for indicators in the Enums.mqh file. For illustrative purposes, in this Expert Advisor we will use two standard indicators (Moving Average and Commodity Channel Index) and one custom indicator (MultiRange_PCH). The enumeration will be as follows:

//--- Indicators
enum ENUM_INDICATORS
  {
   MA       = 0, // Moving Average
   CCI      = 1, // CCI
   PCH      = 2  // Price Channel
  };

The external parameters are modified as follows:

//--- External parameters of the Expert Advisor
sinput   long              MagicNumber=777;        // Magic number
sinput   int               Deviation=10;           // Slippage
input    ENUM_INDICATORS   Indicator=MA;           // Indicator
input    int               IndicatorPeriod=5;      // Indicator period
input    int               IndicatorSegments=2;    // Number of one direction indicator segments
input    double            Lot=0.1;                // Lot
input    double            VolumeIncrease=0.1;     // Position volume increase
input    double            VolumeIncreaseStep=10;  // Step for volume increase
input    double            StopLoss=50;            // Stop Loss
input    double            TakeProfit=100;         // Take Profit
input    double            TrailingStop=10;        // Trailing Stop
input    bool              Reverse=true;           // Position reversal
sinput   bool              ShowInfoPanel=true;     // Display of the info panel

As mentioned above, you will be able to select one out of the three indicators in the drop-down list of the Indicator parameter.

There is only one parameter applicable to all indicators where the indicator period can be set - IndicatorPeriod. The NumberOfBars parameter from the previous version of the Expert Advisor has been renamed to IndicatorSegments and now denotes the number of bars during which a given indicator must be going up/down to satisfy the position opening condition.

Further, we have added another external parameter, VolumeIncreaseStep, that can be used to set the step for volume increase in points.

The value of the AllowedNumberOfBars variable (now AllowedNumberOfSegments) used to be adjusted in the GetBarsData() custom function. It will now be placed into a separate function and only called at initialization.

Since the position opening condition will now be checked using indicator values, the value to be assigned will always be greater by two. In other words, if the IndicatorSegments external variable is assigned the value of 1, the AllowedNumberOfSegments variable will be assigned the value of 3, since in order to satisfy the condition (e.g. for a BUY), the indicator value on the completed bar must be greater than that on the previous bar. For this purpose, we need to get the last three indicator values.

Below is the CorrectInputParameters() function code:

//+------------------------------------------------------------------+
//| Adjusting input parameters                                       |
//+------------------------------------------------------------------+
void CorrectInputParameters()
  {
//--- Adjust the number of bars for the position opening condition
   if(AllowedNumberOfSegments<=0)
     {
      if(IndicatorSegments<=1)
         AllowedNumberOfSegments=3;                     // At least three bars are required
      if(IndicatorSegments>=5)
         AllowedNumberOfSegments=5;                     // but no more than 7
      else
         AllowedNumberOfSegments=IndicatorSegments+1;   // and always greater by two
     }
  }

Before we start dealing with the indicators, let's create a function that will check whether trading is allowed - CheckTradingPermission(). If trading is not allowed for any of the reasons listed in the function, zero value will be returned. This will mean that the next try will have to be made on the next bar.

//+------------------------------------------------------------------+
//| Checking if trading is allowed                                   |
//+------------------------------------------------------------------+
bool CheckTradingPermission()
  {
//--- For real-time mode
   if(IsRealtime())
     {
      //--- Checking server connection
      if(!TerminalInfoInteger(TERMINAL_CONNECTED))
         return(1);
      //--- Permission to trade at the running program level
      if(!MQL5InfoInteger(MQL5_TRADE_ALLOWED))
         return(2);
      //--- Permission to trade at the terminal level
      if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
         return(3);
      //--- Permission to trade for the current account
      if(!AccountInfoInteger(ACCOUNT_TRADE_ALLOWED))
         return(4);
      //--- Permission to trade automatically for the current account
      if(!AccountInfoInteger(ACCOUNT_TRADE_EXPERT))
         return(5);
     }
//---
   return(0);
  }

Let's now get down to the main point of the article. To get access to values of the indicator, we need to first get its handle. This is done using special functions whose names are made of the short name of the indicator and the 'i' symbol preceding it.

For example, the Moving Average indicator has the corresponding function iMA(). All standard indicator handles in the MetaTrader 5 terminal can be obtained using these functions. The full list is available in the MQL5 Reference section called Technical Indicators. If you need to get a handle of a custom indicator, use the iCustom() function.

We will implement the GetIndicatorHandle() function where depending on the indicator selected in the Indicator parameter the handle value of the corresponding indicator will be assigned to the indicator_handle global variable. The function code can be found in our library of trading signal functions (the \Include\TradeSignals.mqh file), while the variable with the indicator handle is located in the main file of the Expert Advisor.

//+------------------------------------------------------------------+
//| Getting the indicator handle                                     |
//+------------------------------------------------------------------+
void GetIndicatorHandle()
  {
//--- If the Moving Average indicator is selected
   if(Indicator==MA)
      indicator_handle=iMA(_Symbol,Period(),IndicatorPeriod,0,MODE_SMA,PRICE_CLOSE);
//--- If the CCI indicator is selected
   if(Indicator==CCI)
      indicator_handle=iCCI(_Symbol,Period(),IndicatorPeriod,PRICE_CLOSE);
//--- If the MultiRange_PCH indicator is selected
   if(Indicator==PCH)
      indicator_handle=iCustom(_Symbol,Period(),"MultiRange_PCH",IndicatorPeriod);
//--- If the indicator handle could not be obtained
   if(indicator_handle==INVALID_HANDLE)
      Print("Failed to get the indicator handle!");
  }

Further, we create the GetDataIndicators() function where using the obtained indicator handles, we can get their values. This is done using the CopyBuffer() function in the way similar to getting bar values using the CopyTime(), CopyClose(), CopyOpen(), CopyHigh() and CopyLow() functions considered in the article called "MQL5 Cookbook: Analyzing Position Properties in the MetaTrader 5 Strategy Tester".

Since the indicator can have several buffers (rows of values), the buffer index is passed to the CopyBuffer() function as the second parameter. Buffer indices for standard indicators can be found in MQL5 Reference. For custom indicators, buffer indices can be found in the code, provided the source code is available. If there is no code, you will need to find the index by way of experiment, by observing how conditions are satisfied in the visualization mode of the Strategy Tester.

Prior to that, we need to create dynamic arrays for indicator buffer values in the main file of the Expert Advisor:

//--- Arrays for indicator values
double indicator_buffer1[];
double indicator_buffer2[];

The code of the GetIndicatorsData() is provided below:

//+------------------------------------------------------------------+
//| Getting indicator values                                         |
//+------------------------------------------------------------------+
bool GetIndicatorsData()
  {
//--- If the indicator handle has been obtained
   if(indicator_handle!=INVALID_HANDLE)
     {
      //--- For the Moving Average or CCI indicator
      if(Indicator==MA || Indicator==CCI)
        {
         //--- Reverse the indexing order (... 3 2 1 0)
         ArraySetAsSeries(indicator_buffer1,true);
         //--- Get indicator values
         if(CopyBuffer(indicator_handle,0,0,AllowedNumberOfSegments,indicator_buffer1)<AllowedNumberOfSegments)
           {
            Print("Failed to copy the values ("+
                  _Symbol+"; "+TimeframeToString(Period())+") to the indicator_buffer1 array! Error ("+
                  IntegerToString(GetLastError())+"): "+ErrorDescription(GetLastError()));
            return(false);
           }
        }
      //--- For the MultiRange_PCH indicator
      if(Indicator==PCH)
        {
         //--- Reverse the indexing order (... 3 2 1 0)
         ArraySetAsSeries(indicator_buffer1,true);
         ArraySetAsSeries(indicator_buffer2,true);
         //--- Get indicator values
         if(CopyBuffer(indicator_handle,0,0,AllowedNumberOfSegments,indicator_buffer1)<AllowedNumberOfSegments || 
            CopyBuffer(indicator_handle,1,0,AllowedNumberOfSegments,indicator_buffer2)<AllowedNumberOfSegments)
           {
            Print("Failed to copy the values ("+
                  _Symbol+"; "+TimeframeToString(Period())+") to the indicator_buffer1 or indicator_buffer2 array! Error ("+
                  IntegerToString(GetLastError())+"): "+ErrorDescription(GetLastError()));
            return(false);
           }
        }
      //---
      return(true);
     }
//--- If the indicator handle has not been obtained, retry
   else
      GetIndicatorHandle();
//---
   return(false);
  }

The GetTradingSignal() function has substantially changed. The conditions are different in the absence of the position and where the position exists. For the Moving Average and CCI indicators, the conditions are the same. For MultiRange_PCH, they are arranged in a separate block. To make the code more readable and to avoid repetitions, we create an auxiliary function, GetSignal(), that returns a signal for position opening or reversal, provided that such position exists and the relevant action is allowed by the external parameter.

Below is the code of the GetSignal() function:

//+------------------------------------------------------------------+
//| Checking the condition and returning a signal                    |
//+------------------------------------------------------------------+
ENUM_ORDER_TYPE GetSignal()
  {
//--- Check conditions for the Moving Average and CCI indicators
   if(Indicator==MA || Indicator==CCI)
     {
      //--- A Sell signal
      if(AllowedNumberOfSegments==3 && 
         indicator_buffer1[1]<indicator_buffer1[2])
         return(ORDER_TYPE_SELL);
      //---
      if(AllowedNumberOfSegments==4 && 
         indicator_buffer1[1]<indicator_buffer1[2] && 
         indicator_buffer1[2]<indicator_buffer1[3])
         return(ORDER_TYPE_SELL);
      //---
      if(AllowedNumberOfSegments==5 && 
         indicator_buffer1[1]<indicator_buffer1[2] && 
         indicator_buffer1[2]<indicator_buffer1[3] && 
         indicator_buffer1[3]<indicator_buffer1[4])
         return(ORDER_TYPE_SELL);
      //---
      if(AllowedNumberOfSegments==6 && 
         indicator_buffer1[1]<indicator_buffer1[2] && 
         indicator_buffer1[2]<indicator_buffer1[3] && 
         indicator_buffer1[3]<indicator_buffer1[4] && 
         indicator_buffer1[4]<indicator_buffer1[5])
         return(ORDER_TYPE_SELL);
      //---
      if(AllowedNumberOfSegments>=7 && 
         indicator_buffer1[1]<indicator_buffer1[2] && 
         indicator_buffer1[2]<indicator_buffer1[3] && 
         indicator_buffer1[3]<indicator_buffer1[4] && 
         indicator_buffer1[4]<indicator_buffer1[5] && 
         indicator_buffer1[5]<indicator_buffer1[6])
         return(ORDER_TYPE_SELL);

      //--- A Buy signal
      if(AllowedNumberOfSegments==3 && 
         indicator_buffer1[1]>indicator_buffer1[2])
         return(ORDER_TYPE_BUY);
      //---
      if(AllowedNumberOfSegments==4 && 
         indicator_buffer1[1]>indicator_buffer1[2] && 
         indicator_buffer1[2]>indicator_buffer1[3])
         return(ORDER_TYPE_BUY);
      //---
      if(AllowedNumberOfSegments==5 && 
         indicator_buffer1[1]>indicator_buffer1[2] && 
         indicator_buffer1[2]>indicator_buffer1[3] && 
         indicator_buffer1[3]>indicator_buffer1[4])
         return(ORDER_TYPE_BUY);
      //---
      if(AllowedNumberOfSegments==6 && 
         indicator_buffer1[1]>indicator_buffer1[2] && 
         indicator_buffer1[2]>indicator_buffer1[3] && 
         indicator_buffer1[3]>indicator_buffer1[4] && 
         indicator_buffer1[4]>indicator_buffer1[5])
         return(ORDER_TYPE_BUY);
      //---
      if(AllowedNumberOfSegments>=7 && 
         indicator_buffer1[1]>indicator_buffer1[2] && 
         indicator_buffer1[2]>indicator_buffer1[3] && 
         indicator_buffer1[3]>indicator_buffer1[4] && 
         indicator_buffer1[4]>indicator_buffer1[5] && 
         indicator_buffer1[5]>indicator_buffer1[6])
         return(ORDER_TYPE_BUY);
     }
//--- Block that checks conditions for the MultiRange_PCH indicator
   if(Indicator==PCH)
     {
      //--- A Sell signal
      if(close_price[1]<indicator_buffer2[1] && 
         open_price[1]>indicator_buffer2[1])
         return(ORDER_TYPE_SELL);
      //--- A Buy signal
      if(close_price[1]>indicator_buffer1[1] && 
         open_price[1]<indicator_buffer1[1])
         return(ORDER_TYPE_BUY);
     }
//--- No signal
   return(WRONG_VALUE);
  }

The GetTradingSignal() function code is now as follows:

//+------------------------------------------------------------------+
//| Determining trading signals                                      |
//+------------------------------------------------------------------+
ENUM_ORDER_TYPE GetTradingSignal()
  {
//--- If there is no position
   if(!pos.exists)
     {
      //--- A Sell signal
      if(GetSignal()==ORDER_TYPE_SELL)
         return(ORDER_TYPE_SELL);
      //--- A Buy signal
      if(GetSignal()==ORDER_TYPE_BUY)
         return(ORDER_TYPE_BUY);
     }
//--- If the position exists
   if(pos.exists)
     {
      //--- Get the position type
      GetPositionProperties(P_TYPE);
      //--- Get the last deal price
      GetPositionProperties(P_PRICE_LAST_DEAL);
      //--- Block that checks conditions for the Moving Average and CCI indicators
      if(Indicator==MA || Indicator==CCI)
        {
         //--- A Sell signal
         if(pos.type==POSITION_TYPE_BUY && 
            GetSignal()==ORDER_TYPE_SELL)
            return(ORDER_TYPE_SELL);
         //---
         if(pos.type==POSITION_TYPE_SELL && 
            GetSignal()==ORDER_TYPE_SELL && 
            close_price[1]<pos.last_deal_price-CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point))
            return(ORDER_TYPE_SELL);
         //--- A Buy signal
         if(pos.type==POSITION_TYPE_SELL && 
            GetSignal()==ORDER_TYPE_BUY)
            return(ORDER_TYPE_BUY);
         //---
         if(pos.type==POSITION_TYPE_BUY && 
            GetSignal()==ORDER_TYPE_BUY && 
            close_price[1]>pos.last_deal_price+CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point))
            return(ORDER_TYPE_BUY);
        }
      //--- Block that checks conditions for the MultiRange_PCH indicator
      if(Indicator==PCH)
        {
         //--- A Sell signal
         if(pos.type==POSITION_TYPE_BUY && 
            close_price[1]<indicator_buffer2[1] && 
            open_price[1]>indicator_buffer2[1])
            return(ORDER_TYPE_SELL);
         //---
         if(pos.type==POSITION_TYPE_SELL && 

            close_price[1]<pos.last_deal_price-CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point))
            return(ORDER_TYPE_SELL);
         //--- A Buy signal
         if(pos.type==POSITION_TYPE_SELL && 
            close_price[1]>indicator_buffer1[1] && 
            open_price[1]<indicator_buffer1[1])
            return(ORDER_TYPE_BUY);
         //---
         if(pos.type==POSITION_TYPE_BUY && 
            close_price[1]>pos.last_deal_price+CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point))
            return(ORDER_TYPE_BUY);
        }
     }
//--- No signal
   return(WRONG_VALUE);
  }

Now, we only need to see into the Instant Execution and Market Execution modes that are part of symbol properties and to modify the code of the OpenPosition() position opening function accordingly. The modes whose names are self-explanatory can also be found in MQL5 Reference:

  • Instant Execution
  • Market Execution

Please be reminded that when dealing with the Market Execution mode, you cannot open a position with the set Stop Loss and Take Profit levels: you need to first open a position and then modify it, by setting the levels.

Starting with build 803, Stop Loss and Take Profit can be set when opening a position for the Market Execution and Exchange Execution modes.

Let's add the execution mode to the structure of symbol properties:

//--- Symbol properties
struct symbol_properties
  {
   int               digits;           // Number of decimal places in the price
   int               spread;           // Spread in points
   int               stops_level;      // Stops level
   double            point;            // Point value
   double            ask;              // Ask price
   double            bid;              // Bid price
   double            volume_min;       // Minimum volume for a deal
   double            volume_max;       // Maximum volume for a deal
   double            volume_limit;     // Maximum permissible volume for a position and orders in one direction
   double            volume_step;      // Minimum volume change step for a deal
   double            offset;           // Offset from the maximum possible price for a transaction
   double            up_level;         // Upper Stop level price
   double            down_level;       // Lower Stop level price
   ENUM_SYMBOL_TRADE_EXECUTION execution_mode; // Execution mode
  };

Accordingly, we need to modify the ENUM_SYMBOL_PROPERTIES enumeration

//--- Enumeration of position properties
enum ENUM_SYMBOL_PROPERTIES
  {
   S_DIGITS          = 0,
   S_SPREAD          = 1,
   S_STOPSLEVEL      = 2,
   S_POINT           = 3,
   S_ASK             = 4,
   S_BID             = 5,
   S_VOLUME_MIN      = 6,
   S_VOLUME_MAX      = 7,
   S_VOLUME_LIMIT    = 8,
   S_VOLUME_STEP     = 9,
   S_FILTER          = 10,
   S_UP_LEVEL        = 11,
   S_DOWN_LEVEL      = 12,
   S_EXECUTION_MODE  = 13,
   S_ALL             = 14
  };

and the GetSymbolProperties() function:

case S_EXECUTION_MODE: symb.execution_mode=(ENUM_SYMBOL_TRADE_EXECUTION)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_EXEMODE);   break;
      //---
      case S_ALL           :
         symb.digits=(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS);
         symb.spread=(int)SymbolInfoInteger(_Symbol,SYMBOL_SPREAD);
         symb.stops_level=(int)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL);
         symb.point=SymbolInfoDouble(_Symbol,SYMBOL_POINT);
         symb.ask=NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),symb.digits);
         symb.bid=NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),symb.digits);
         symb.volume_min=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
         symb.volume_max=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX);
         symb.volume_limit=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_LIMIT);
         symb.volume_step=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP);
         symb.offset=NormalizeDouble(CorrectValueBySymbolDigits(lot_offset*symb.point),symb.digits);
         symb.up_level=NormalizeDouble(symb.ask+symb.stops_level*symb.point,symb.digits);
         symb.down_level=NormalizeDouble(symb.bid-symb.stops_level*symb.point,symb.digits);
         symb.execution_mode=(ENUM_SYMBOL_TRADE_EXECUTION)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_EXEMODE);                       break;
         //---

As a result, the OpenPosition() function code is now as follows:

//+------------------------------------------------------------------+
//| Opening a position                                               |
//+------------------------------------------------------------------+
void OpenPosition(double lot,
                  ENUM_ORDER_TYPE order_type,
                  double price,
                  double sl,
                  double tp,
                  string comment)
  {
//--- Set the magic number in the trading structure
   trade.SetExpertMagicNumber(MagicNumber);
//--- Set the slippage in points
   trade.SetDeviationInPoints(CorrectValueBySymbolDigits(Deviation));
//--- The Instant Execution mode
//    A position can be opened with the Stop Loss and Take Profit levels set
   if(symb.execution_mode==SYMBOL_TRADE_EXECUTION_INSTANT)
     {
      //--- If the position failed to open, print the relevant message
      if(!trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,comment))
         Print("Error opening the position: ",GetLastError()," - ",ErrorDescription(GetLastError()));
     }
//--- The Market Execution mode 
//    First open a position and only then set the Stop Loss and Take Profit levels
//    *** Starting with build 803, Stop Loss and Take Profit can be set upon position opening ***
   if(symb.execution_mode==SYMBOL_TRADE_EXECUTION_MARKET)
     {
      //--- If there is no position, first open a position and then set Stop Loss and Take Profit
      if(!pos.exists)
        {
         //--- If the position failed to open, print the relevant message
         if(!trade.PositionOpen(_Symbol,order_type,lot,price,0,0,comment))
            Print("Error opening the position: ",GetLastError()," - ",ErrorDescription(GetLastError()));
         //--- Get the flag of presence/absence of the position
         pos.exists=PositionSelect(_Symbol);
         //--- If the position exists
         if(pos.exists)
           {
            //--- Set Stop Loss and Take Profit
            if(!trade.PositionModify(_Symbol,sl,tp))
               Print("Error modifying the position: ",GetLastError()," - ",ErrorDescription(GetLastError()));
           }
        }
      //--- If the position exists, increase its volume and leave the Stop Loss and Take Profit levels unchanged
      else
        {
         //--- If the position failed to open, print the relevant message
         if(!trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,comment))
            Print("Error opening the position: ",GetLastError()," - ",ErrorDescription(GetLastError()));
        }
     }
  }

We still have to add the final, very important touch to the event handling functions:

  • OnInit
    //+------------------------------------------------------------------+
    //| Expert initialization function                                   |
    //+------------------------------------------------------------------+
    int OnInit()
      {
    //--- Adjust the input parameters
       CorrectInputParameters();
    //--- Get indicator handles
       GetIndicatorHandle();
    //--- Initialize the new bar
       CheckNewBar();
    //--- Get the properties
       GetPositionProperties(P_ALL);
    //--- Set the info panel
       SetInfoPanel();
    //---
       return(0);
      }
  • OnDeinit
    //+------------------------------------------------------------------+
    //| Expert deinitialization function                                 |
    //+------------------------------------------------------------------+
    void OnDeinit(const int reason)
      {
    //--- Print the deinitialization reason to the journal
       Print(GetDeinitReasonText(reason));
    //--- When deleting from the chart
       if(reason==REASON_REMOVE)
         {
          //--- Delete all objects relating to the info panel from the chart
          DeleteInfoPanel();
          //--- Delete the indicator handle
          IndicatorRelease(indicator_handle);
         }
      }
  • OnTick
    //+------------------------------------------------------------------+
    //| Expert tick function                                             |
    //+------------------------------------------------------------------+
    void OnTick()
      {
    //--- If the bar is not new, exit
       if(!CheckNewBar())
         {
          if(IsVisualMode() || IsRealtime())
            {
             //--- Get the properties and update the values on the panel
             GetPositionProperties(P_ALL);
             //--- Set/update the info panel
             SetInfoPanel();
            }
          return;
         }
    
    //--- If there is a new bar
       else
         {
          //--- If trading is allowed
          if(CheckTradingPermission()==0)
            {
             if(!GetIndicatorsData())
                return;
             GetBarsData();          // Get bar data
             TradingBlock();         // Check the conditions and trade
             ModifyTrailingStop();   // Modify the Trailing Stop level
            }
         }
    //--- Get the properties
       GetPositionProperties(P_ALL);
    //--- Update the info panel
       SetInfoPanel();
      }

Now that all functions are ready, we can optimize the parameters. Keep in mind that you need to compile the code from the main program file.

 

Optimizing Parameters and Testing Expert Advisor

The Strategy Tester needs to be set as shown below:

Fig. 1. Strategy Tester settings.

Fig. 1. Strategy Tester settings.

Further, we set the parameters of the Expert Advisor for optimization (see also the attached *.set file with settings):

Fig. 2. Settings of the Expert Advisor.

Fig. 2. Settings of the Expert Advisor.

The optimization took about 40 minutes on a dual-core processor. The optimization chart allows you to partly assess the quality of a trading system based on the results in the profit zone:

Fig. 3. Optimization chart.

Fig. 3. Optimization chart.

Maximum recovery factor test results are as follows:

Fig. 4. Maximum recovery factor test results.

Fig. 4. Maximum recovery factor test results.

 

Conclusion

Attached to the article is the downloadable archive with the source codes of the Expert Advisor. Once it is extracted, you need to place the \TestIndicatorConditions file folder into <Metatrader 5 terminal>\MQL5\Experts. To ensure the correct operation of the Expert Advisor, the MultiRange_PCH indicator should be downloaded and placed into <Metatrader 5 terminal>\MQL5\Indicators.

Translated from Russian by MetaQuotes Software Corp.
Original article: https://www.mql5.com/ru/articles/645

Last comments | Go to discussion (3)
Macgyver75
Macgyver75 | 19 Jun 2013 at 15:08

Very good article.

but I have difficulties to dowload the Zip file that seems to be corrupted 

Macgyver75
Macgyver75 | 19 Jun 2013 at 15:16

It 's OK !


I tried from another PC with another navigator and it works fine !


Sorry

Macgyver75
Macgyver75 | 20 Jun 2013 at 13:58

Hello,

I dont know why but when I try to test the EA with strategy tester, the TP and SL never appear. They are not set when I do not use the trailing stop.

When using the TrailingStop parameter, the SL appears, but it seems to be a modification and not an initial setting in the position. (using the trailing stop allow to set a SL whent the trailing stop is used)

In the same time, when debugging allowing autotrading (on a demo account) , the SL and TP are immediately set (when the position is first set on TradingBlock(); and it is not necessary to wait to ModifyTrailingStop() function to see the SL and TP)

Do someone can explain WHY ?

is it a problem of Broker (Alpari UK) ?

In these condition, it is difficult to evaluate how the EA works when SL and TP are set. 

Thanks if any has an idea.

 

M. 

Step on New Rails: Custom Indicators in MQL5 Step on New Rails: Custom Indicators in MQL5

I will not list all of the new possibilities and features of the new terminal and language. They are numerous, and some novelties are worth the discussion in a separate article. Also there is no code here, written with object-oriented programming, it is a too serous topic to be simply mentioned in a context as additional advantages for developers. In this article we will consider the indicators, their structure, drawing, types and their programming details, as compared to MQL4. I hope that this article will be useful both for beginners and experienced developers, maybe some of them will find something new.

Here Comes the New MetaTrader 5 and MQL5 Here Comes the New MetaTrader 5 and MQL5

This is just a brief review of MetaTrader 5. I can't describe all the system's new features for such a short time period - the testing started on 2009.09.09. This is a symbolical date, and I am sure it will be a lucky number. A few days have passed since I got the beta version of the MetaTrader 5 terminal and MQL5. I haven't managed to try all its features, but I am already impressed.

False trigger protection for Trading Robot False trigger protection for Trading Robot

Profitability of trading systems is defined not only by logic and precision of analyzing the financial instrument dynamics, but also by the quality of the performance algorithm of this logic. False trigger is typical for low quality performance of the main logic of a trading robot. Ways of solving the specified problem are considered in this article.

Using text files for storing input parameters of Expert Advisors, indicators and scripts Using text files for storing input parameters of Expert Advisors, indicators and scripts

The article describes the application of text files for storing dynamic objects, arrays and other variables used as properties of Expert Advisors, indicators and scripts. The files serve as a convenient addition to the functionality of standard tools offered by MQL languages.