Lite_EXPERT2.mqh: Functional Kit for Developers of Expert Advisors

Nikolay Kositsin | 8 October, 2013

Introduction

In the articles of the series "Expert Advisors Based on Popular Trading Systems and Alchemy of Trading Robot Optimization" 1, 2, 3, 4, 5, 6, 7, I introduced the novice EA developers with my approach to writing an Expert Advisor that allows you to easily transform trading strategies into a very simple and quickly implemented program code using ready-made custom trade functions of the Lite_EXPERT1.mqh. It is quite natural that in order to ensure maximum simplicity of information, the number of custom functions used in this file was minimal, being sufficient to, so to say, get the grasp of it without any trouble.

However, the functionality offered by that file is not quite sufficient for working with the program code at broader scale. Lite_EXPERT2.mqh was written with this objective in view and contains a more universal set of custom functions which is yet more complex for a first-time user. It is assumed that the reader is already familiar with the information provided in the article "Expert Advisors Based on Popular Trading Systems and Alchemy of Trading Robot Optimization 1" and considers this new article as the next step in further development and improvement of his skills necessary to use such custom functions.


The Lite_EXPERT2.mqh File Content

Generally speaking, all the functions available in Lite_EXPERT2.mqh can be shown in the form of the flowchart as follows:

Description of functions

In addition to functions, Lite_EXPERT2.mqh contains the integer variable int LastTime declared in global scope and used in all trading functions, as well as the integer variable extern int Slippage_ for slippage in points, which will be visible from the external parameters of the Expert Advisor.


1. Position Opening Functions

All functions of this block can be divided into two large groups. Functions of the first group have "Open" at the beginning of their names, while function names of the second group start with dOpen. Functions of the first group use relative distances from the position opening price expressed in points as the external variables of the Stop Loss and Take Profit, i.e. they are represented by integer variables.

bool OpenBuyOrder1_
        (bool& BUY_Signal, int MagicNumber, datetime TimeLevel,
                           double Money_Management, int Margin_Mode, 
                                         int STOPLOSS, int TAKEPROFIT)
                                         
bool OpenSellOrder1_
        (bool& SELL_Signal, int MagicNumber, datetime TimeLevel, 
                            double Money_Management, int Margin_Mode, 
                                          int STOPLOSS, int TAKEPROFIT)
                                          
bool OpenBuyOrder2_
        (bool& BUY_Signal, int MagicNumber, datetime TimeLevel,
                           double Money_Management, int Margin_Mode, 
                                          int STOPLOSS, int TAKEPROFIT)
                                          
bool OpenSellOrder2_
        (bool& SELL_Signal, int MagicNumber, datetime TimeLevel, 
                            double Money_Management, int Margin_Mode, 
                                          int STOPLOSS, int TAKEPROFIT)

The Stop Loss and Take Profit in the functions of the second group are represented by floating-point variables. In this case, values of those variables are absolute values of the corresponding orders as obtained from the price chart. This makes writing the code of an Expert Advisor that serves a specific purpose much more convenient.

bool dOpenBuyOrder1_
        (bool& BUY_Signal, int MagicNumber, datetime TimeLevel,
                           double Money_Management, int Margin_Mode, 
                                  double dSTOPLOSS, double dTAKEPROFIT)
                                  
bool dpenSellOrder1_
        (bool& SELL_Signal, int MagicNumber, datetime TimeLevel,
                           double Money_Management, int Margin_Mode, 
                                  double dSTOPLOSS, double dTAKEPROFIT)
                                  
bool dOpenBuyOrder2_
        (bool& BUY_Signal, int MagicNumber, datetime TimeLevel,
                           double Money_Management, int Margin_Mode, 
                                   double dSTOPLOSS, double dTAKEPROFIT)
                                   
bool dOpenSellOrder2_
        (bool& SELL_Signal, int MagicNumber, datetime TimeLevel, 
                            double Money_Management, int Margin_Mode, 
                                   double dSTOPLOSS, double dTAKEPROFIT)

All functions whose names end in "1_" are intended for brokers that allow setting Stop Loss and Take Profit right when executing a deal. Functions whose names contain "2_" are used for brokers who allow setting these orders for positions that are already open.

In contrast to the functions featured in Lite_EXPERT1.mqh, these eight functions have two new external variables (datetime TimeLevel and int Margin_Mode). So the first thing we should do is have a closer look at them. The value of the TimeLevel variable represents a certain time limit after the execution of the current deal. All trading functions of this file will not open any new positions or orders with the current magic number till the specified time limit is reached. The value of this external variable when executing a deal is saved in a global variable on the hard drive of the computer and it will therefore not be lost when restarting the trading terminal or the Windows operating system. The most basic use of this variable is to block the reopening of a position or setting a pending order on the same bar.

//----
   static datetime TimeLevel;
   TimeLevel = Time[0] + Period() * 60;
   
   //---- 
   if (!OpenBuyOrder1_
        (BUY_Signal, MagicNumber, TimeLevel,
                           Money_Management, Margin_Mode, 
                                         STOPLOSS, TAKEPROFIT))
                                                          return(-1);

It is assumed that the TimeLevel static variable will be initialized in the same block as the BUY_Signal variable. Now, if the OpenBuyOrder1_() function opens a position, it will save the TimeLevel variable value in the global variable on the hard drive. And the functions of the Lite_EXPERT2.mqh file that open positions or pending orders will not open any order with that magic number until the last quote time becomes greater than or equal to this value.

So, basically, the trading functions of this file do not zero out the external variable of the bool& BUY_Signal type by reference as this is not necessary. Zeroing out will only be performed if the TimeLevel variable is initialized to "-1"! If we set the value of this variable equal to zero, the position opening function will not zero out or save anything and will open positions based on signals of the BUY_Signal external variable at any time when there are no orders with the magic number equal to the value of the int MagicNumber external variable.

The string name that is used for a global variable saved on the hard drive is generated for testing and optimization using the following formula:

string G_Name_ = "TimeLevel", "_", AccountNumber(), "_", 
                                "_Test_", OrderSymbol(), "_", OrderMagicNumber());

In other cases:

string G_Name_ = "TimeLevel", "_", AccountNumber(), 
                                     "_", OrderSymbol(), "_", OrderMagicNumber());

This name must not be used for other global variables!

Trading functions available in Lite_EXPERT1.mqh use only one method of lot calculation (MM based on free margin). This method of lot size calculation may not be suitable for every strategy. This issue has been taken into account in the trading functions provided in Lite_EXPERT2.mqh and the lot size calculation method is determined using the int Margin_Mode external variable. In determining the lot size calculation method, the Margin_Mode external variable may take on values from zero to five:

Please bear in mind that if you use the second or third lot size calculation method and your Stop Loss is dynamic, i.e. it varies from deal to deal, you should take into account the boundary values of the Stop Loss and MM. E.g. if the variables have the following values: Money_Management = 0.1, Margin_Mode = 3 and int STOPLOSS = 100 (five decimal places), the Expert Advisor will use the entire deposit in opening a position!

Just in case, I will once again explain these two variants for values of the Margin_Mode variable (2 and 3). Here, the lot size calculation function takes either the free margin or account balance value and multiplies it by the value of the Money_Management variable. The resulting value represents the amount of losses that may arise if the position will be closed at the Stop Loss level! Those losses do not depend on the Stop Loss size. Thus, the lot size calculation function determines the position volume based on the Stop Loss size so that losses from the Stop Loss are hard-set!

Where the Margin_Mode variable value is equal to 4 or 5, the trading functions can calculate the lot size using two variants at the same time and choose the smallest value. For example, if Margin_Mode = 5, a trading function will calculate the lot size based on the account balance and based on losses on the account balance and will then use the smallest value.

Once again, I would like to mention here that if the value of the Money_Management variable is negative, all these functions will disregard the Margin_Mode variable values and use the values of the Money_Management variable as the lot size. When using such values, the minus sign will be discarded and the value itself will be rounded to the nearest standard value which cannot be greater than the available one. In calculating the lot size, these eight functions always check the free margin to be sufficient for execution of a certain deal and reduce the calculated lot size to the permissible value, if necessary.


2. Functions for Placing Pending Orders

This is the second, large group of functions divided into two large groups, similarly to the previous ones.

bool OpenBuyLimitOrder1_
        (bool& Order_Signal, int MagicNumber, datetime TimeLevel,
                            double Money_Management, int Margin_Mode, 
                                           int STOPLOSS, int TAKEPROFIT,
                                              int LEVEL, datetime Expiration) 
bool OpenBuyStopOrder1_
        (bool& Order_Signal, int MagicNumber, datetime TimeLevel, 
                             double Money_Management, int Margin_Mode, 
                                           int STOPLOSS, int TAKEPROFIT,
                                               int LEVEL, datetime Expiration)
bool OpenSellLimitOrder1_
        (bool& Order_Signal, int MagicNumber, datetime TimeLevel, 
                            double Money_Management, int Margin_Mode, 
                                           int STOPLOSS, int TAKEPROFIT,
                                               int LEVEL, datetime Expiration)
bool OpenSellStopOrder1_
        (bool& Order_Signal, int MagicNumber, datetime TimeLevel,
                            double Money_Management, int Margin_Mode,
                                           int STOPLOSS, int TAKEPROFIT,
                                               int LEVEL, datetime Expiration)
bool dOpenBuyLimitOrder1_
        (bool& Order_Signal, int MagicNumber, datetime TimeLevel,
                            double Money_Management, int Margin_Mode, 
                                    double dSTOPLOSS, double dTAKEPROFIT,
                                           double dLEVEL, datetime Expiration)
bool dOpenBuyStopOrder1_
        (bool& Order_Signal, int MagicNumber, datetime TimeLevel, 
                             double Money_Management, int Margin_Mode, 
                                    double dSTOPLOSS, double dTAKEPROFIT,
                                            double dLEVEL, datetime Expiration)
bool dOpenSellLimitOrder1_
        (bool& Order_Signal, int MagicNumber, datetime TimeLevel, 
                            double Money_Management, int Margin_Mode, 
                                    double dSTOPLOSS, double dTAKEPROFIT,
                                            double dLEVEL, datetime Expiration)
bool dOpenSellStopOrder1_
        (bool& Order_Signal, int MagicNumber, datetime TimeLevel,
                            double Money_Management, int Margin_Mode,
                                    double dSTOPLOSS, double dTAKEPROFIT,
                                            double dLEVEL, datetime Expiration)

Everything that was said earlier regarding the previous functions is also true for these eight functions. There are only two facts that can be considered as exceptions. It is basically impossible to calculate the lot size based on what will be happening when the order is being placed. And if the lot size is calculated at the point of placing a pending order, which is how it is done, one can hardly expect the calculation to be in strict accordance with the Money_Management variable value. For the same reason, these functions do not check if there are sufficient funds for the lot size.


3. Functions for Closing Open Positions

This block only consists of four functions

bool CloseBuyOrder1_(bool& CloseStop, int MagicNumber)

bool CloseSellOrder1_(bool& CloseStop, int MagicNumber)

bool CloseAllBuyOrders1_(bool CloseStop)

bool CloseAllSellOrders1_(bool CloseStop)

These functions are quite simple and do not require any additional explanations. The first two functions close positions with the specified magic numbers by the symbol from the chart on which the Expert Advisor is running. The other two functions close all open positions available.


4. Functions for Deleting Pending Orders

The list of functions in this section consists of only two basic functions

bool CloseOrder1_(bool& CloseStop, int cmd, int MagicNumber)
bool CloseAllOrders1_(bool CloseStop, int cmd)

the external variables of which contain the new variable - int cmd. Its values are provided below:


5. Position Modification and Trailing Stop Functions

This block includes three function groups:

1) position modifiers

bool dModifyOpenBuyOrder_
       (bool& Modify_Signal, int MagicNumber, 
                     datetime ModifyTimeLevel_, double dSTOPLOSS, double dTAKEPROFIT)
                         
bool dModifyOpenSellOrder_
       (bool& Modify_Signal, int MagicNumber, 
                     datetime ModifyTimeLevel_, double dSTOPLOSS, double dTAKEPROFIT)
                         
bool dModifyOpenBuyOrderS (bool& Modify_Signal, double dSTOPLOSS, double dTAKEPROFIT)
                         
bool dModifyOpenSellOrderS(bool& Modify_Signal, double dSTOPLOSS, double dTAKEPROFIT)

All four functions of this group use absolute values of the Stop Loss and Take Profit on a price chart scale and are represented by floating point variables. Everything written with respect to the variables of the first and second group is true and applies to the variables of this group, as well.

Please note that the datetime ModifyTimeLevel_ variable value is only used in the first two functions of this group and nowhere else! This variable is absent altogether from the last two functions. To be able to call one of the last two functions in the code of the Expert Advisor, you need to first select an order of OP_BUY or OP_SELL type to continue working with them, using the OrderSelect() function! These functions are intended for working with open positions that do not have magic numbers. The formulas for the string name of the global variable for the purpose of saving the ModifyTimeLevel_ variable value on the hard drive are as follows:

string G_Name_ = "ModifyTimeLevel_", "_", AccountNumber(), 
                                          "_", "_Test_", Symbol(), "_", MagicNumber;
string G_Name_ = "ModifyTimeLevel_", "_", AccountNumber(),
                                                    "_", Symbol(), "_", MagicNumber;  

2) Trailing Stops

bool Make_BuyTrailingStop_
             (bool& TreilSignal, int MagicNumber, datetime TrailTimeLevel, int TRAILINGSTOP)

bool Make_SellTrailingStop_
             (bool& TreilSignal, int MagicNumber, datetime TrailTimeLevel, int TRAILINGSTOP)
        
bool dMake_BuyTrailingStop_
        (bool& TreilSignal, int MagicNumber, datetime TrailTimeLevel_, double dTRAILINGSTOP)
        
bool dMake_SellTrailingStop_
        (bool& TreilSignal, int MagicNumber, datetime TrailTimeLevel_, double dTRAILINGSTOP)

This group contains four classical Trailing Stops for forcing the Stop Loss against the current price. Two of them have Trailing Stop value in points relative to the current price as the external parameter, while the other two use the Trailing Stop absolute value for the same purpose. Like the previous functions, these four functions use time limits in the form of the TrailTimeLevel and TrailTimeLevel_ variables with the similar value. If you intend to change Trailing Stops on every tick, these variables should be set to zero.

3) and one more group of four position modifiers

bool BuyStoplossCorrect
           (int MagicNumber, int ExtPointProfit, int StoplossProfit)
           
bool SellStoplossCorrect
           (int MagicNumber, int ExtPointProfit, int StoplossProfit)
           
bool AllBuyStoplossCorrects (int ExtPointProfit, int StoplossProfit)
           
bool AllSellStoplossCorrects(int ExtPointProfit, int StoplossProfit)

that perform one-time changes of Stop Loss levels. The first two functions check for profit in points with respect to an open position with the fixed magic number and if it is not less than the value of the ExtPointProfit variable, the Stop Loss is moved to the current price at the StoplossProfit distance from the position opening price.

The last two functions of this group track the profit of all open positions for the current symbol with any magic number and perform one-time changes of their corresponding Stop Loss levels.


6. Additional Functions

This is the last and probably the largest group of functions in the Lite_EXPERT2.mqh file. Many functions of this group are used as additional ones within the code of other functions described above and therefore are, in many cases, of little practical interest. So I will limit myself here to the review of the most essential of them.

First of all, I would like to turn your attention to the TimeLevelGlobalVariableDel() function:

void TimeLevelGlobalVariableDel(string symbol, int MagicNumber)

After testing and optimization, this function deletes all global variables that were generated by the trading functions featured in the file and saved on the hard drive of your computer. This function should be called in the Expert Advisor deinitialization block, e.g. as follows:

//+X================================================================X+
//| Custom Expert deinitialization function                          |
//+X================================================================X+  
int deinit()
  {
//----+
    TimeLevelGlobalVariableDel(Symbol(), 1);
    TimeLevelGlobalVariableDel(Symbol(), 2);
    TimeLevelGlobalVariableDel(Symbol(), 3);
    TimeLevelGlobalVariableDel(Symbol(), 4);
    //---- Completing deinitialization of the Expert Advisor
    return(0);
//----+ 
  }

If this is not done, the global variables with the latest time values remaining after testing or optimization will block the testing and optimization of the Expert Advisor!!!

It is often the case that chart time frames which can only be selected from the standard series of values are used as external variables of the Expert Advisor. One can always make a mistake and set the wrong value when doing it manually. In such cases, you can do the check using the TimeframeCheck() function,

void TimeframeCheck(string TimeframeName, int Timeframe)

that checks time frame values in the external variables when initializing the Expert Advisor.

All calculations that are made in the Expert Advisor for any price level are initially based on price chart values. And it may not always be quite clear what prices are shown in the charts - ASK or BID. So the values obtained from price charts need to be adjusted for that difference prior to be used in trading functions. This can be done using the dGhartVelueCorrect() function:

double dGhartVelueCorrect(int cmd, double& GhartVelue)

The purpose of the cmd variable is absolutely identical to the description provided in the MetaEditor Help. When calling this function, the external parameter GhartVelue can only be represented by a variable whose value is changed to the adjusted one by reference. For example:

//---- get the GhartVelue_ price level
   double GhartVelue_ = Low[0];
   //---- correct the GhartVelue_ price level
   dGhartVelueCorrect(OP_BUY, GhartVelue_);

There are two more functions for selecting orders to be able to continue using them further:

bool OrderSelect_(string symbol, int cmd, int MagicNumber, int pool)
bool Order_Select(string symbol, int MagicNumber)

The pool variable can take on two values only: MODE_TRADES - the order is selected from open and pending orders, and MODE_HISTORY - the order is selected from closed and deleted orders. If successful, the functions return true, otherwise false.

In certain cases, you may need to use MarginCheck(), the function that checks the lot size against the funds available in the account and, if necessary, decreases the lot size to be adequate for the available funds:

bool MarginCheck(string symbol, int Cmd, double& Lot)

The Cmd parameter in this function can only take on two values: OP_BUY and OP_SELL. If the calculation is successful, the function will return true. In case of errors in the function operation, it returns false.

Sometimes you may want to calculate the lot size. For this purpose, we have two more functions:

double BuyLotCount(double Money_Management, int Margin_Mode, int STOPLOSS)
double SellLotCount(double Money_Management, int Margin_Mode, int STOPLOSS)

If there are no errors, the functions return the lot value, otherwise -1.

And there are three more functions for those who like to wrap an indicator code in the code of Expert Advisors:

int IndicatorCounted_(int Number, string symbol, int timeframe)

int ReSetAsIndexBuffer(string symbol, int timeframe, double& array[])

int ReSetAsIndexBuffer_(string symbol, int timeframe, double& Array[], int ArrSize)

The first function is equivalent to the IndicatorCounted() function operating in EAs. The external variable Number represents the function call number in the code of the Expert Advisor (one number per indicator).

The purpose of the second function is to convert a data array declared in global scope to an indicator buffer analog. So the function synchronizes the elements of the array whose name represents the variable double& array[] with the corresponding time series arrays. This function must be called in the start() function, outside the range of loop operators iterating over chart bars.

The third function is a complete analog of the second function but the number of elements in the Array[] array is derived from the limited value of the ArrSize variable. In other words, in this case the array contains the ArrSize number of only the last, most recent bars. This function may be more useful than the previous one in many cases where in the indicator code values are only added to such array and only the ArrSize number of the last values is used in the code of the Expert Advisor.

And finally, the last two functions:

bool IsNewBar(int Number, string symbol, int timeframe)

bool MinBarCheck(string symbol, int timeframe, int MinBarTotal)

The IsNewBar() function returns True at the point of time when the bar is changed in the corresponding time series arrays. In all other cases, this function returns False. The Number variable represents the function call number in the code of the Expert Advisor. The MinBarCheck() function compares the number of bars of the relevant chart against the MinBarTotal variable value. If the number of bars is smaller, it returns False. This function is used in order not to allow an Expert Advisor to trade if the number of bars required for the calculation is not sufficient.


Conclusion

That is basically the entire list of the most needed Lite_EXPERT2.mqh functions which represent the sufficient minimum for convenient and efficient strategy tester writing in MQL4. In the next articles of this series, I will provide specific examples illustrating the use of the above file functions in EAs.