MQL4 Book  Creation of a Normal Program  Order Accounting

Order Accounting

We mentioned above that there were no strict rules for making program algorithms. At the same time, the overwhelming majority of algorithms imply making one's trading decisions according to the current status of the orders available. In some cases, for example, opening a market order needs no other market orders available as of the moment of the trade. In other cases, no stop orders available on the market order can be a necessary condition for placing of a pending order. We also know some algorithms that imply placing two differently directed pending orders.

In order to have met the requirements of one or another tactic or strategy by the moment of decision making, you should know about the current status - what market and pending orders are available and what characteristics do they have? You may use one of the two possible solutions.

According to the first solution, the necessary program code fragment (in which the orders are analyzed) is written directly in the location in the program, where the available set of orders and their characteristics should be found out. This solution is technically feasible, but it turns out to be inefficient, if you want to make changes in the algorithm. In this case, the programmer has to analyzes all locations in the program where order statuses are analyzed, and make changes in each location. Another, more effective solution is to create a universal order accounting function once and use it every time, when you want to update the information about the current order statuses. On the one hand, this solution allows you to reduce the program code. On the other hand, it allows the programmer to use this ready-made function when coding other programs.

In order to create an order accounting function correctly, you should first decide what parameters must be accounted. In most cases, the values of the following parameters are used in making trade decisions:

  • total amount of orders;
  • the amount of orders of each type (for example, the amount of Buy orders, SellStop orders, or BuyLimit orders, etc.);
  • all characteristics of each order (ticket, StopLoss and TakeProfit levels, volume in lots, etc.).

The above information must be available to other functions, namely to those, in which this information is processed. For this reason, all parameters that characterize order statuses are the values of global arrays. Totally, three arrays are provided for order accounting:

  • the array of current orders, Mas_Ord_New, that contains information about all characteristics of all market and pending orders available at the current moment, namely, within the period of the last execution of the function;
  • the array of old orders, Mas_Ord_Old, that contains information about all characteristics of all market and pending orders available at the moment of the preceding execution of the function;
  • the array Mas_Tip, the values of which are the amounts of orders of different types (at the current moment).

Arrays Mas_Ord_New and Mas_Ord_Old are similar and equidimensional; the difference between them is that the former one reflects the current status of orders, whereas the latter one shows the preceding status. Let's give a closer consideration to the values contained in the elements of those arrays.

Table 4. Correspondence of the elements of arrays Mas_Ord_New and Mas_Ord_Old with order characteristics.

Not defined Open Price StopLoss TakeProfit Order Number

in lots

Order Type Magic Number Comment
Indexes 0 1 2 3 4 5 6 7 8
0 2.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
1 0.0 1.2583 1.2600 1.2550 123456.0 1.4 1.0 1177102416.0 1.0
2 0.0 1.2450 1.2580 1.2415 123458.0 2.5 2.0 1177103358.0 0.0
3 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
. . . 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
30 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0

The first index of the array (lines) defines the number of the order in the array. The characteristics of the first order detected (among all opened market orders and placed pending orders) are placed in the first line of the array, those of the second order detected will be placed in the second line, etc. The array size for the first index is equal to 31, thus, the array is intended to store information about 30 orders at the most, if they are simultaneously available on one trading account. If the trading strategy allows the availability of more than thirty orders simultaneously, you should specify the corresponding value for the first index when you declare the array. (In most cases, the value of 30 considerably exceeds the real need usually ranging from 2 to 10-15 orders. We use the value of 30 in this example, because we suppose that the function can be used for very unusual trading strategies, as well).

The second index in the array (columns) represents order characteristics. Each element of the array with the second index equal to 1 contains the value of the order open price, with index 2 - they contain the value of StopLoss order, 3 - TakeProfit, etc. (see Table 4). Array element with index [0][0] has a value that is equal to the total amount of orders available in the array. No array elements having the first or the second indexes equal to 0 are used (except element having index [0][0]).

Table 4 represents the status of an array that contains information about two orders that are simultaneously available in trading at a certain moment. The array element Mas_Ord_New[0][0] has the value of 2.0 - the total amount of orders is two. The elements in the first line of the array contain the values of the characteristics of the market order Sell (Mas_Ord_New[1][6] = 1.0, see Types of Trades) opened for 1.4 lot (Mas_Ord_New[1][5] =1.4) and having the number 123456 (Mas_Ord_New[1][4] =123456.0). The value of the element Mas_Ord_New[1][8] =1.0 means that this order has non-empty comment field. In the second line of the array, the values that characterize the second order are contained. Particularly, the array element Mas_Ord_New[2][6] has the value of 2.0, it means that it is BuyLimit.

Array Mas_Tip represents the amount of orders of each type. The values of this array indexes are assigned to the types of trades (see Types of Trades). This means that the element of array Mas_Tip with index 0 contains the amount of market orders of the Buy type simultaneously available in trading, index 1 means the amount of Sell orders, index 2 means that of BuyLimit orders, etc. For the situation shown in Table 4, the elements of array Mas_Tip will have the following values:

Table 5. Correspondence of the elements of array Mas_Tip with the amount of orders of different types.

Buy Sell BuyLimit SellLimit BuyStop SellStop
Index 0 1 2 3 4 5
Value 0 1 1 0 0 0

In this case, the values of the elements of array Mas_Tip imply the following: Mas_Tip[1] equal to 1 means that there is one Sell order traded; Mas_Tip[2] equal to 1 means that there is one pending order BuyLimit in trading. Other elements of the array have zero values - this means that there are no orders of those types in trading. If there are several orders of the same type simultaneously available in trading, the corresponding element of the array will have the value equal to the amount of such orders. For example, if there are three orders BuyStop in trading, the element Mas_Tip[4] will have the value of 3.

The order accounting function Terminal() suggested here is formed as include file Terminal.mqh.

User-Defined Function Terminal()

int Terminal()

The function accounts market and pending orders. The execution of the function results in changing of the values of the following global arrays:

  • Mas_Ord_New - the array of characteristics of orders available as of the moment of the function execution;
  • Mas_Ord_Old - the array of characteristics of orders available as of the moment of the preceding execution of the function;
  • Mas_Tip - the array of the total amount of orders of all types.

Include file Terminal.mqh that contains the description of the order accounting function Terminal():

// Terminal.mqh
// The code should be used for educational purpose only.
//------------------------------------------------------------------------------ 1 --
// Order accounting function
// Global variables:
// Mas_Ord_New[31][9]   // The latest known orders array
// Mas_Ord_Old[31][9]   // The preceding (old) orders array
                        // 1st index = order number
                        // [][0] not defined
                        // [][1] order open price (abs. price value)
                        // [][2] StopLoss of the order (abs. price value)
                        // [][3] TakeProfit of the order (abs. price value)
                        // [][4] order number        
                        // [][5] order volume in lots (abs. price value)
                        // [][6] order type 0=B,1=S,2=BL,3=SL,4=BS,5=SS
                        // [][7] order magic number
                        // [][8] 0/1 comment availability
// Mas_Tip[6]           // Array of the amount of orders of all types
                        // [] order type: 0=B,1=S,2=BL,3=SL,4=BS,5=SS
//------------------------------------------------------------------------------ 2 --
int Terminal()
   int Qnt=0;                          // Orders counter

//------------------------------------------------------------------------------ 3 --
   ArrayCopy(Mas_Ord_Old, Mas_Ord_New);// Saves the preceding history
   Qnt=0;                              // Zeroize orders counter
   ArrayInitialize(Mas_Ord_New,0);     // Zeroize the array
   ArrayInitialize(Mas_Tip,    0);     // Zeroize the array
//------------------------------------------------------------------------------ 4 --
   for(int i=0; i<OrdersTotal(); i++) // For market and pending orders
      if((OrderSelect(i,SELECT_BY_POS)==true)     //If there is the next one
(OrderSymbol()==Symbol()))               //.. and our currency pair
         //--------------------------------------------------------------------- 5 --
         Qnt++;                                   // Amount of orders
         Mas_Ord_New[Qnt][1]=OrderOpenPrice();    // Order open price
         Mas_Ord_New[Qnt][2]=OrderStopLoss();     // SL price
         Mas_Ord_New[Qnt][3]=OrderTakeProfit();   // TP price
         Mas_Ord_New[Qnt][4]=OrderTicket();       // Order number
         Mas_Ord_New[Qnt][5]=OrderLots();         // Amount of lots
         Mas_Tip[OrderType()]++;                  // Amount of orders of the type
         Mas_Ord_New[Qnt][6]=OrderType();         // Order type
         Mas_Ord_New[Qnt][7]=OrderMagicNumber();  // Magic number
         if (OrderComment()=="")
            Mas_Ord_New[Qnt][8]=0;                // If there is no comment
            Mas_Ord_New[Qnt][8]=1;                // If there is a comment
         //--------------------------------------------------------------------- 6 --
   Mas_Ord_New[0][0]=Qnt;                         // Amount of orders
//------------------------------------------------------------------------------ 7 --
//------------------------------------------------------------------------------ 8 --

In block 1-2, we give a comment describing the global arrays used in the function. The global arrays are declared in an include file Variables.mqh. In block 3-4, the content of the array Mas_Ord_New is copied to the array Mas_Ord_Old. Thus, the previously known status of orders is stored and can be used further in the program. Then the values of elements of arrays Mas_Ord_New and Mas_Tip showing the new status of orders has been zeroized before the data are updated in block 4-7.

Block 4-7 contains the cycle 'for', in which all market and pending orders are checked one by one for the symbol, to the window of which the EA is attached. The orders are selected using the function OrderSelect() according to the parameter MODE_TRADES set by default. In block 5-6, all required characteristics are calculated for the selected orders, the obtained data are stored in the array of new orders, Mas_Ord_New. At the same time, the amount of orders of all types is calculated, the obtained values being assigned to the corresponding elements of array Mas_Tip. Upon ending of the cycle, the total amount of orders for the symbol is assigned to the element Mas_Ord_New[0][0].

It must be separately noted that closed market orders and deleted pending orders (the execution of the function OrderSelect() with the parameter MODE_HISTORY) are not analyzed. As a rule, the information about closed and deleted orders is not used in trading EAs. The information about closed and deleted orders represent the history of a trading account. This information can be used, for example, to build diagrams that represent the history of capital invested and real trading results. However, it cannot be useful in any way for making new trade decisions. Technically, this part of orders can be accounted in a similar way. However, it is a separate task that has no relation to trading as such.

The events related to orders are analyzed in a program on the basis of comparison of data available in the arrays considered above. For example, if array Mas_Ord_Old contains information about a pending order numbered as 246810, while array Mas_Ord_New contains the data about the same order 246810, but the order is of another type, it means that a pending order has been modified into a market one. It is also necessary to analyze orders when making trades (to be considered later).

Before the function Terminal() is executed for the very first time, arrays Mas_Ord_Old and Mas_Ord_New are empty, i.e., each element of both arrays has zero value. This means that, after the first execution of the function, the array Mas_Ord_Old in the line:

   ArrayCopy(Mas_Ord_Old, Mas_Ord_New);// Store the preceding history

inherits "zero" status from the array Mas_Ord_New, which results in appearance of false event alerts at the execution of the event tracking function. In order to prevent this, the very first execution of the function Terminal() is performed at the stage of initialization, and events are not processed after this execution of the function (see the function init() in Expert Advisor usualexpert.mq4).