Programming EA's Modes Using Object-Oriented Approach

Denis Kirichenko | 28 January, 2015

Introduction

In this article we are going to discuss programming modes, in which an MQL5 EA can work. The objective of this article is to describe the idea that "each mode is implemented in its own way". The author believes that this approach allows completion of tasks at different stages of development of an EA more efficiently.

At first, we consider what stages the development of an EA consists of. Then the modes, in which an EA in MetaTrader 5 can work and its helper applications are explored. Development of the hierarchy of classes for implementing the above idea finishes this article.


1. Development Stages

Development of a trading robot (EA) is a multi-aspect process. The key blocks here are algorithmization of the idea and testing it. Notably, both EA's trading logic and the code algorithm get tested.

As a scheme, the stages of this process can be represented as follows (Fig.1).

Fig.1. Development stages and implementation of an EA

Fig.1. Development stages and implementation of an EA

The fifth stage "Algorithmic Trading" showcases the work of the developers, programmers, analysts and other specialists involved. It often happens that all these roles are fulfilled by one person. Let us assume, that it is a trader-programmer.

This scheme can be updated and extended. In my opinion, it illustrates the most important points in development of an EA. The cyclical pattern of this scheme allows improving and modifying the EA's code through its lifetime.

It should be noted that every stage requires certain tools, knowledge and skills.

In my opinion, the developer comes across the following simple variant matrix (Fig.2).

Fig.2. Variant matrix

Fig.2. Variant matrix

Clearly, only the robot implementing a winning trading strategy with high quality code is to make it to the fifth stage "Algorithmic Trading".


2. The Expert Advisor Modes in MQL5

The MQL5 environment allows working with an EA in different modes. There are 7 of them. We are going to consider each of them further down.

From the perspective of the program file type, 2 groups can be distinguished:

  1. Modes requiring the source code file and the executable file;
  2. Modes requiring the executable file only.

Debug and profiling modes belong to the first group.

Another criterion of mode classification is work of an EA in a stream of real or historical quotes. All testing modes are connected with historical quotes.

6 modes are defined by programming. A conclusion if an EA is working in a standard (release) mode or not can be made based on the results. A ready program (file with the *.ex5 extension), which was coded for work on financial markets, is supposed to work in this very mode. At the same time, a ready program enables using other modes in the Strategy Tester too.

Let us create an enumeration of the operational modes of the MQL program called ENUM_MQL_MODE:

//+------------------------------------------------------------------+
//| MQL Mode                                                         |
//+------------------------------------------------------------------+
enum ENUM_MQL_MODE
  {
   MQL_MODE_RELEASE=0,       // Release
   MQL_MODE_DEBUG=1,         // Debugging
   MQL_MODE_PROFILER=2,      // Profiling  
   MQL_MODE_TESTER=3,        // Testing
   MQL_MODE_OPTIMIZATION=4,  // Optimization
   MQL_MODE_VISUAL=5,        // Visual testing 
   MQL_MODE_FRAME=6,         // Gathering frames
  };

Later on, this will be required for recognizing the mode type in which an EA is working.


2.1. Function of Identifying and Checking the Mode

Write a simple function that will iterate over all modes and print information in the journal.

//+------------------------------------------------------------------+
//| Checking all MQL modes                                           |
//+------------------------------------------------------------------+
void CheckMqlModes(void)
  {
//--- if it is debug mode
   if(MQLInfoInteger(MQL_DEBUG))
      Print("Debug mode: yes");
   else
      Print("Debug mode: no");
//--- if it is code profiling mode
   if(MQLInfoInteger(MQL_PROFILER))
      Print("Profile mode: yes");
   else
      Print("Profile mode: no");
//--- if it is test mode
   if(MQLInfoInteger(MQL_TESTER))
      Print("Tester mode: yes");
   else
      Print("Tester mode: no");
//--- if it is optimization mode
   if(MQLInfoInteger(MQL_OPTIMIZATION))
      Print("Optimization mode: yes");
   else
      Print("Optimization mode: no");
//--- if it is visual test mode
   if(MQLInfoInteger(MQL_VISUAL_MODE))
      Print("Visual mode: yes");
   else
      Print("Visual mode: no");
//--- if it is frame gathering optimization result mode
   if(MQLInfoInteger(MQL_FRAME_MODE))
      Print("Frame mode: yes");
   else
      Print("Frame mode: no");
  }

Work of this function in every mode is going to be checked. It can be called in the OnInit() event handler.

For the purpose of the test, let us create a template of the EA called Test1_Modes_EA.mq5.

An option to specify the mode where the EA is going to work is enabled in input parameters. It is important to make sure that the correct mode is named otherwise information will be inaccurate. That was what happened.

Below is the release mode.

CL      0       17:20:38.932    Test1_Modes_EA (EURUSD.e,H1)     Current mode: MQL_MODE_RELEASE
QD      0       17:20:38.932    Test1_Modes_EA (EURUSD.e,H1)     Debug mode: no
KM      0       17:20:38.932    Test1_Modes_EA (EURUSD.e,H1)     Profile mode: no
EK      0       17:20:38.932    Test1_Modes_EA (EURUSD.e,H1)     Tester mode: no
CS      0       17:20:38.932    Test1_Modes_EA (EURUSD.e,H1)     Optimization mode: no
RJ      0       17:20:38.932    Test1_Modes_EA (EURUSD.e,H1)     Visual mode: no
GL      0       17:20:38.932    Test1_Modes_EA (EURUSD.e,H1)     Frame mode: no

For release mode, the flags of all other modes were zeroed. So, the function identified that it was neither debug mode (Debug mode: no), nor profiling mode (Profile mode: no) etc. Using the method of negation, we came to the conclusion that we are working in release mode.

Now we are going to see how debug mode was identified.

HG      0       17:27:47.709    Test1_Modes_EA (EURUSD.e,H1)     Current mode: MQL_MODE_DEBUG
LD      0       17:27:47.710    Test1_Modes_EA (EURUSD.e,H1)     Debug mode: yes
RS      0       17:27:47.710    Test1_Modes_EA (EURUSD.e,H1)     Profile mode: no
HE      0       17:27:47.710    Test1_Modes_EA (EURUSD.e,H1)     Tester mode: no
NJ      0       17:27:47.710    Test1_Modes_EA (EURUSD.e,H1)     Optimization mode: no
KD      0       17:27:47.710    Test1_Modes_EA (EURUSD.e,H1)     Visual mode: no
RR      0       17:27:47.710    Test1_Modes_EA (EURUSD.e,H1)     Frame mode: no

Debug mode was recognized correctly.

Any handbook on programming contains information that debugging facilitates search and error localization in the code. It also highlights peculiarities of the program. More details about debugging in the MQL5 environment can be found in the article "Debugging MQL5 Programs".

This mode is most commonly used at the stages of formalizing and constructing the algorithm of a trading idea.

In programming, debugging is enabled either using the IS_DEBUG_MODE macros or the MQLInfoInteger() function with the MQL_DEBUG identifier.

We are moving on to profiling mode.

GS      0       17:30:53.879    Test1_Modes_EA (EURUSD.e,H1)     Current mode: MQL_MODE_PROFILER
OR      0       17:30:53.879    Test1_Modes_EA (EURUSD.e,H1)     Debug mode: no
GE      0       17:30:53.879    Test1_Modes_EA (EURUSD.e,H1)     Profile mode: yes
QM      0       17:30:53.879    Test1_Modes_EA (EURUSD.e,H1)     Tester mode: no
CE      0       17:30:53.879    Test1_Modes_EA (EURUSD.e,H1)     Optimization mode: no
FM      0       17:30:53.879    Test1_Modes_EA (EURUSD.e,H1)     Visual mode: no
GJ      0       17:30:53.879    Test1_Modes_EA (EURUSD.e,H1)     Frame mode: no

The function correctly estimated that the Profiler was involved.

In this mode it can be checked how quickly the program works. The Profiler passes the information on time expenditure to program blocks. This instrument is supposed to point out bottlenecks of an algorithm. They are not always possible to get rid of but nevertheless this information can be useful.

Profiling can be enabled either through the IS_PROFILE_MODE macros or the MQLInfoInteger() function with the MQL_PROFILER identifier.

Now let us have a look at test mode. This information will appear in the "Journal" tab of the Strategy Tester.

EG      0       17:35:25.397    Core 1  2014.11.03 00:00:00   Current mode: MQL_MODE_TESTER
OS      0       17:35:25.397    Core 1  2014.11.03 00:00:00   Debug mode: no
GJ      0       17:35:25.397    Core 1  2014.11.03 00:00:00   Profile mode: no
ER      0       17:35:25.397    Core 1  2014.11.03 00:00:00   Tester mode: yes
ED      0       17:35:25.397    Core 1  2014.11.03 00:00:00   Optimization mode: no
NL      0       17:35:25.397    Core 1  2014.11.03 00:00:00   Visual mode: no
EJ      0       17:35:25.397    Core 1  2014.11.03 00:00:00   Frame mode: no

Test mode was identified correctly.

This is the EA's default mode when the Strategy Tester gets opened.

There are no macros for this mode and therefore in MQL5 we can only determine it using the MQLInfoInteger() function with the MQL_TESTER identifier.

Now we are moving on to the optimization. A journal with records will be stored in the agent's folder. In my case the path is as follows: %Program Files\MetaTrader5\tester\Agent-127.0.0.1-3000\logs

OH      0       17:48:14.010    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Current mode: MQL_MODE_OPTIMIZATION
KJ      0       17:48:14.010    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Debug mode: no
NO      0       17:48:14.010    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Profile mode: no
FI      0       17:48:14.010    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Tester mode: yes
KE      0       17:48:14.010    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Optimization mode: yes
LS      0       17:48:14.010    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Visual mode: no
QE      0       17:48:14.010    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Frame mode: no

If optimization mode is active, test mode is enabled by default.

Optimization mode is active in the Strategy Tester if the "Optimization" field is not disabled in the "Settings" tab.

To find out if the EA is being tested in optimization mode in MQL5, call either the MQLInfoInteger() function with the MQL_OPTIMIZATION identifier.

We are proceeding to visualization mode.

JQ      0       17:53:51.485    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Current mode: MQL_MODE_VISUAL
JK      0       17:53:51.485    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Debug mode: no
KF      0       17:53:51.485    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Profile mode: no
CP      0       17:53:51.485    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Tester mode: yes
HJ      0       17:53:51.485    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Optimization mode: no
LK      0       17:53:51.485    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Visual mode: yes
KS      0       17:53:51.485    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Frame mode: no

Here we can see that visual testing mode and standard testing mode are involved.

The EA works in this mode in the Strategy Tester if the "Visualization" field in the "Settings" tab is flagged.

Establishing the fact of testing an MQL5 program in visual testing mode can be done using the MQLInfoInteger() function with the MQL_VISUAL_MODE identifier.

The last mode is handling frames mode.

HI      0       17:59:10.177    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Current mode: MQL_MODE_FRAME
GR      0       17:59:10.177    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Debug mode: no
JR      0       17:59:10.177    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Profile mode: no
JG      0       17:59:10.177    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Tester mode: yes
GM      0       17:59:10.177    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Optimization mode: yes
HR      0       17:59:10.177    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Visual mode: no
MI      0       17:59:10.177    Test1_Modes_EA (EURUSD.e,H1)     2014.11.03 00:00:00   Frame mode: no

Interestingly enough, the function recognized only testing and optimization modes as the flag of frames was zeroed. If the call of the function is transferred to the OnTesterInit() handler, the "Experts" journal is going to contain the following entries:

IO      0       18:04:27.663    Test1_Modes_EA (EURUSD.e,H1)     Current mode: MQL_MODE_FRAME
GE      0       18:04:27.663    Test1_Modes_EA (EURUSD.e,H1)     Debug mode: no
ML      0       18:04:27.663    Test1_Modes_EA (EURUSD.e,H1)     Profile mode: no
CJ      0       18:04:27.663    Test1_Modes_EA (EURUSD.e,H1)     Tester mode: no
QR      0       18:04:27.663    Test1_Modes_EA (EURUSD.e,H1)     Optimization mode: no
PL      0       18:04:27.663    Test1_Modes_EA (EURUSD.e,H1)     Visual mode: no
GS      0       18:04:27.663    Test1_Modes_EA (EURUSD.e,H1)     Frame mode: yes

Effectively, now only gathering frames mode was detected.

This mode is used in the Strategy Tester if the "Optimization" field in the "Settings" tab is not disabled. As experience has shown, this mode is defined in the body of the OnTesterInit(), OnTesterPass() and OnTesterDeinit() handlers.

The MQLInfoInteger() function with the MQL_FRAME_MODE identifier can facilitate identifying the fact of testing an EA in gathering frames mode.

Below is the code of the service function MqlMode(), which automatically specifies the mode in which the EA is working.

//+------------------------------------------------------------------+
//| Identify the current MQL mode                                    |
//+------------------------------------------------------------------+
ENUM_MQL_MODE MqlMode(void)
  {
   ENUM_MQL_MODE curr_mode=WRONG_VALUE;

//--- if it is debug mode
   if(MQLInfoInteger(MQL_DEBUG))
      curr_mode=MQL_MODE_DEBUG;
//--- if it is code profiling mode
   else if(MQLInfoInteger(MQL_PROFILER))
      curr_mode=MQL_MODE_PROFILER;
//--- if it is visual test mode
   else if(MQLInfoInteger(MQL_VISUAL_MODE))
      curr_mode=MQL_MODE_VISUAL;
//--- if it is optimization mode
   else if(MQLInfoInteger(MQL_OPTIMIZATION))
      curr_mode=MQL_MODE_OPTIMIZATION;
//--- if it is test mode
   else if(MQLInfoInteger(MQL_TESTER))
      curr_mode=MQL_MODE_TESTER;
//--- if it is frame gathering optimization result mode
   else if(MQLInfoInteger(MQL_FRAME_MODE))
      curr_mode=MQL_MODE_FRAME;
//--- if it is release mode
   else
      curr_mode=MQL_MODE_RELEASE;
//---
   return curr_mode;
  }

Since standard testing is identified at optimization and visual testing mode, then standard testing mode is to be checked after optimization and visualization mode.

If we take a look at the work of the function in the second template of the Test2_Modes_EA.mq5 EA, we can see that a new entry appears in the journal when the template is launched. For instance, for profiling mode the below entry was made:

HG      0       11:23:52.992    Test2_Modes_EA (EURUSD.e,H1)    Current mode: MQL_MODE_PROFILER

We discussed the details of operational modes of the MQL5 Expert for creating class models corresponding to a specified mode. We are going to implement it in the next part of the article.


3. Template of the EA Designed to Work in Different Modes

I suggest going over the development stages of an EA again.

At the stage of algorithmization, a programmer most often does debugging and profiling. For testing historical data, they try all modes of the Strategy Tester. The final mode (release mode) is utilized in online trading.

In my opinion, an EA must be multi-faceted in the sense that requirement of the development and testing stages have to be reflected in its code.

At that, the main algorithm will be preserved and, following it, the EA will have different behavior at different modes. The object - oriented programming tools set suits perfectly for implementing this idea.

Fig.2 Class hierarchy for the EA designed to work in different modes

Fig.3. Class hierarchy for the EA designed to work in different modes

Class hierarchy with implementation of different modes is represented on Fig.3.

The basic class CModeBase encapsulating all common things will have two direct descendants: the CModeRelease and the CModeTester classes. The first one will be a parent to the debugging classes and the second one for the classes connected with testing the EA on historical data.

Let us develop the idea of combining a procedural and modular approach when developing class methods in the context of modes. As an example let us consider the following trading logic:

  1. Open by a signal if there is no open position;
  2. Closing by the signal if there is an open position;
  3. Trailing Stop if there is an open position.

The trading signal is detected by the standard indicator MACD when a new bar appears.

A signal to buy appears when the main line is going upwards and crossing the signal one in the negative zone of the MACD indicator (Fig.4).

Fig.4 Signal to buy

Fig.4. Signal to buy

A signal to sell appears when the main line is going downwards and crosses the signal one in the positive zone of the indicator (Fig. 5).

Fig.5 Signal to sell

Fig.5. Signal to sell

The position gets closed either when the opposite signal appears or by the Stop Loss, which is placed in case the mode of a position support is enabled.

Then the definition of the basic class CModeBase is as follows:

//+------------------------------------------------------------------+
//| Class CModeBase                                                  |
//| Purpose: a base class for MQL-modes                              |            
//+------------------------------------------------------------------+
class CModeBase
  {
//--- === Data members === --- 
private:
   //--- a macd object & values
   CiMACD            m_macd_obj;
   double            m_macd_main_vals[2];
   double            m_macd_sig_vals[2];

protected:
   long              m_pos_id;
   bool              m_is_new_bar;
   uint              m_trailing_stop;
   uint              m_trail_step;
   //--- trade objects
   CSymbolInfo       m_symbol_info;
   CTrade            m_trade;
   CPositionInfo     m_pos_info;
   CDealInfo         m_deal_info;
   //--- mql mode
   ENUM_MQL_MODE     m_mql_mode;

   //--- a new bar object
   CisNewBar         m_new_bar;
   //--- current tick signal flag
   bool              m_is_curr_tick_signal;
   //--- close order type
   ENUM_ORDER_TYPE   m_close_ord_type;
   
//--- === Methods === --- 
public:
   //--- constructor/destructor
   void              CModeBase();
   void             ~CModeBase(void){};
   //--- initialization
   virtual bool      Init(int _fast_ema,int slow_ema,int _sig,ENUM_APPLIED_PRICE _app_price);
   virtual void      Deinit(void){};

   //--- Modules
   virtual void      Main(void){};

   //--- Procedures
   virtual void      Open(void){};
   virtual void      Close(void){};
   virtual void      Trail(void){};

   //--- Service
   static ENUM_MQL_MODE CheckMqlMode(void);
   ENUM_MQL_MODE     GetMqlMode(void);
   void              SetMqlMode(const ENUM_MQL_MODE _mode);
   void              SetTrailing(const uint _trailing,const uint _trail_step);

protected:
   //--- Functions
   ENUM_ORDER_TYPE   CheckOpenSignal(const ENUM_ORDER_TYPE _open_sig);
   ENUM_ORDER_TYPE   CheckCloseSignal(const ENUM_ORDER_TYPE _close_sig);
   ENUM_ORDER_TYPE   CheckTrailSignal(const ENUM_ORDER_TYPE _trail_sig,double &_sl_pr);
   //---
   double            GetMacdVal(const int _idx,const bool _is_main=true);

private:
   //--- Macros
   bool              RefreshIndicatorData(void);
   //--- Normalization
   double            NormalPrice(double d);
   double            NormalDbl(double d,int n=-1);
   double            NormalSL(const ENUM_ORDER_TYPE _ord_type,double op,double pr,
                              uint SL,double stop);
   double            NormalTP(const ENUM_ORDER_TYPE _ord_type,double op,double pr,
                              uint _TP,double stop);
   double            NormalLot(const double _lot);
  };

Anything can be included in a basic class as long as it is going to be used in the inheritor classes.

The MACD data will be unavailable for descendants as they are represented by private members.

It must be noted that among those methods there are virtual ones: Main(), Open(), Close(), Trail(). Their implementation will vastly depend on the mode the EA is currently working in. These methods will stay empty for the basic class.

Besides, the basic class comprises methods that have the same trading logic for all MQL modes. All signal methods belong to them:

It should be kept in mind, that this article does not target writing code for all MQL mode types. Standard and visual testing are going to serve an example.


3.1. Test Mode

After algorithm has been coded and compiled, I usually try the strategy out on historical data in the Strategy Tester to check if it works as designed.

Most often it is required to check how precisely the system implements trading signals. In any case, the basic aim at this stage for an EA is to launch and trade.

The CModeTester class for regular testing can be implemented as follows:

//+------------------------------------------------------------------+
//| Class CModeTester                                                |
//| Purpose: a class for the tester mode                             |            
//| Derives from class CModeBase.                                    |
//+------------------------------------------------------------------+
class CModeTester : public CModeBase
  {
//--- === Methods === --- 
public:
   //--- constructor/destructor
   void              CModeTester(void){};
   void             ~CModeTester(void){};

   //--- Modules
   virtual void      Main(void);

   //--- Procedures
   virtual void      Open(void);
   virtual void      Close(void);
   virtual void      Trail(void);
  };

The main module is implemented like:

//+------------------------------------------------------------------+
//| Main module                                                      |
//+------------------------------------------------------------------+
void CModeTester::Main(void)
  {
//--- 1) closure
   this.Close();
//--- 2) opening
   this.Open();
//--- 3) trailing stop
   this.Trail();
  }

For the mode of regular testing, create an opportunity to print information about trading signals in the Journal.

Add strings containing indicator values that are considered to be the source of the trading signal.

Below is an extract from the Journal about a signal to open a position followed by a signal to close.

HE      0       13:34:04.118    Core 1  2014.11.14 22:15:00   ---=== Signal to open: SELL===---
FI      0       13:34:04.118    Core 1  2014.11.14 22:15:00   A bar before the last one, main: 0.002117; signal: 0.002109
DL      0       13:34:04.118    Core 1  2014.11.14 22:15:00   The last bar, main: 0.002001; signal: 0.002118
LO      0       13:34:04.118    Core 1  2014.11.14 22:15:00   market sell 0.03 EURUSD.e (1.25242 / 1.25251 / 1.25242)
KH      0       13:34:04.118    Core 1  2014.11.14 22:15:00   deal #660 sell 0.03 EURUSD.e at 1.25242 done (based on order #660)
GE      0       13:34:04.118    Core 1  2014.11.14 22:15:00   deal performed [#660 sell 0.03 EURUSD.e at 1.25242]
OD      0       13:34:04.118    Core 1  2014.11.14 22:15:00   order performed sell 0.03 at 1.25242 [#660 sell 0.03 EURUSD.e at 1.25242]
IK      0       13:34:04.118    Core 1  2014.11.14 22:15:00   CTrade::OrderSend: market sell 0.03 EURUSD.e [done at 1.25242]
IL      0       13:34:04.118    Core 1  2014.11.17 13:30:20   
CJ      0       13:34:04.118    Core 1  2014.11.17 13:30:20   ---=== Signal to close: SELL===---
GN      0       13:34:04.118    Core 1  2014.11.17 13:30:20   A bar before the last one, main: -0.001218; signal: -0.001148
QL      0       13:34:04.118    Core 1  2014.11.17 13:30:20   The last bar, main: -0.001123; signal: -0.001189
EP      0       13:34:04.118    Core 1  2014.11.17 13:30:20   market buy 0.03 EURUSD.e (1.25039 / 1.25047 / 1.25039)
FG      0       13:34:04.118    Core 1  2014.11.17 13:30:20   deal #661 buy 0.03 EURUSD.e at 1.25047 done (based on order #661)
OJ      0       13:34:04.118    Core 1  2014.11.17 13:30:20   deal performed [#661 buy 0.03 EURUSD.e at 1.25047]
PD      0       13:34:04.118    Core 1  2014.11.17 13:30:20   order performed buy 0.03 at 1.25047 [#661 buy 0.03 EURUSD.e at 1.25047]
HE      0       13:34:04.118    Core 1  2014.11.17 13:30:20   CTrade::OrderSend: market buy 0.03 EURUSD.e [done at 1.25047]

Please note that there is no familiar journal "Experts" in the Strategy Tester. All information can be found in the "Journal" tab, which contains records about actions performed by the Strategy Tester during testing and optimization.

That is why one has to search for the required strings. If the entry information is required to be separated, it can be recorded into a file.

Strategy for standard testing is implemented in the code of the TestMode_tester.mq5 EA.


3.2. Visual Testing Mode

Sometimes it is required to refer to a live chart and see how an EA is handling current situation.

Simple visualization allows not only to see how the trading system is reacting to ticks but also to compare similar price models at the end of testing.

Definition of the CModeVisual class for visual testing can be as follows:

//+------------------------------------------------------------------+
//| Class CModeVisual                                                |
//| Purpose: a class for the tester mode                             |            
//| Derived from class CModeBase.                                    |
//+------------------------------------------------------------------+
class CModeVisual : public CModeTester
  {
//--- === Data members === --- 
private:
   CArrayObj         m_objects_arr;
   double            m_subwindow_max;
   double            m_subwindow_min;
   
//--- === Methods === --- 
public:
   //--- constructor/destructor
   void              CModeVisual(void);
   void             ~CModeVisual(void);

   //--- Procedures
   virtual void      Open(void);
   virtual void      Close(void);

private:
   bool              CreateSignalLine(const bool _is_open_sig,const bool _is_new_bar=true);
   bool              CreateRectangle(const ENUM_ORDER_TYPE _signal);
   void              RefreshRectangles(void);
  };

The class contains hidden members. A member of the class m_objects_arr implements a dynamic array of the CArrayObj type. Graphical objects, for example, lines and rectangles, belong here. Two other class members (m_subwindow_max, m_subwindow_min) control maximum and minimum sizes of the indicator's subwindow.

Private methods are responsible for work with graphical objects.

This class does not contain the Main() and the Trail() methods. Their parent analogues CModeTester::Main() and CModeTester::Trail() are going to be called respectively.

Graphical objects can be created in the visual testing mode. This cannot be done in other modes of the Strategy Tester.

Let a red vertical be drawn on the chart when a signal to enter appears and a blue vertical when a signal to exit is received. Fill the space between the entry and exit points with a rectangle of the relevant color in the indicator's subwindow.

If it is a long position, then the rectangle is light blue. If the position is short, the rectangle is pink (Fig.6).

Fig.6. Graphical objects in the visual testing mode

Fig.6. Graphical objects in the visual testing mode

The height of the rectangle depends on the values of maximum and minimum of the chart's subwindow at the time of creation. To make all rectangles equal in size, a block of changing rectangle coordinates should be added to code in case the coordinates of the chart subwindow change.

So in the subwindow of the MACD indicator we get the following areas: uncolored (no position), pink (short position), light blue (long position).

Strategy for the visual testing mode is implemented in the code of the TestMode_visual_tester.mq5 EA.


Conclusion

In this article I tried to illustrate mode capabilities of the MetaTrader 5 terminal and the MQL5 language. It has to be said that a multi-mode approach to programming of a trading algorithm involves more costs on the one hand and on the other hand there is an opportunity to consider each development stage one after another. The object-oriented programming is a resourceful aid for a programmer in this case.

The optimization and frame gathering modes will be highlighted in the future articles about the statistic properties of a trading system.