MQL4 Book  Creation of a Normal Program  Trade Functions

Trade Functions


As a rule, a normal Expert Advisor contains a number of trade functions. They can be divided into two categories - control functions and executive functions. In most cases, only one control function and several executive functions are used in an EA.

A trading strategy in a normal EA is realized on the basis of two functions - a function defining trading criteria and a control trade function. There mustn't be any indications of the trading strategy anywhere else in the program. The controlling trade function and the function defining trading criteria must be coordinated with each other in the values of the parameters they pass.

Each executive trade function has a special range of tasks. According to the requirements of the trading strategy, trade functions intended for the following tasks can be used in an EA:

  • opening a market order of the preset type;
  • closing one market order of the preset type;
  • partly closing one market order of the preset type;
  • closing all market order of the preset type;
  • closing two opposite market orders in the preset volume;
  • closing all market orders;
  • modification of stop orders of a market order of the preset type;
  • placing a pending order of the preset type;
  • deletion of one pending order of the preset type;
  • deletion of all pending orders of the preset type;
  • deletion of all pending orders;
  • modification of a pending order of the preset type.

A general trading sequence in a normal Expert Advisor consists in the following: On the basis of calculated (according to the strategy used) trading criteria, the controlling trade function (also realizing the strategy) calls some or other executive trade functions that, in their turn, form the necessary trade requests.

User-Defined Controlling Function Trade()

int Trade( int Trad_Oper )

It's the basic function that realizes your strategy.

Parameter Trad_Oper can take the following values corresponding with the trading criteria:
10 - triggered a trading criterion for opening a market order Buy;
20 - triggered a trading criterion for opening a market order Sell;
11 - triggered a trading criterion for closing a market order Buy;
21 - triggered a trading criterion for closing a market order Sell;
0 - no important criteria available;
-1 - the symbol used is not EURUSD.

To execute the function, the following trade functions are required:

  • Close_All() - function closing all market orders of the preset type;
  • Open_Ord() - function opening one market order of the preset type;
  • Tral_Stop() - function modifying StopLoss of a market order of the preset type;
  • Lot() - function detecting the amount of lots for new orders.

The control trade function Trade() is formed as include file Trade.mqh:

//------------------------------------------------------------------------
// Trade.mqh
// The code should be used for educational purpose only.
//------------------------------------------------------------------------
// Trade function.
//------------------------------------------------------------------- 1 --
int Trade(int Trad_Oper) // User-defined function
{
// Trad_Oper - trade operation type:
// 10 - opening Buy
// 20 - opening Sell
// 11 - closing Buy
// 21 - closing Sell
// 0 - no important criteria available
// -1 - another symbol is used
switch(Trad_Oper)
{
//------------------------------------------------------------- 2 --
case 10: // Trading criterion = Buy
Close_All(1); // Close all Sell
if (Lot()==false) // Not enough money for min.
return; // Exit the user-defined function
Open_Ord(0); // Open Buy
return; // Having traded, leave
//---------------------------------------------------------- 3 --
case 11: // Trading criterion = closing Buy
Close_All(0); // Close all Buy
return; // Having traded, leave
//---------------------------------------------------------- 4 --
case 20: // Trading criterion = Sell
Close_All(0); // Close all Buy
if (Lot()==false)
return; // Exit the user-defined function
Open_Ord(1); // Open Sell
return; // Having traded, leave
//---------------------------------------------------------- 5 --
case 21: // Trading criterion = closing Sell
Close_All(1); // Close all Sell
return; // Having traded, leave
//---------------------------------------------------------- 6 --
case 0: // Retaining opened positions
Tral_Stop(0); // Trailing stop Buy
Tral_Stop(1); // Trailing stop Sell
return; // Having traded, leave
//---------------------------------------------------------- 7 --
}
}
//------------------------------------------------------------------- 8 --

The control trade Trade() is called from the special function start() of the Expert Advisor usualexpert.mq4. The value returned by the function defining trading criteria Criterion() is given as the passed parameter in the function Trade().

In block 1-2 of the function Trade(), the trading criteria considered by the realized trading strategy are described. In the function, we use the operator switch() (blocks 2-7) that allows us to activate the required group of functions to trade according to the trading criterion. According to the trading strategy, the EA opens and closes market orders. No operations with pending orders are provided by this trading strategy.

In the section named Function Defining Trading Criteria, it was specified that for some trading criteria the program can form several trade requests. Thus, in case of important criterion for buying (the value of the variable Trad_Oper is equal to 10), the control is passed to the mark 'case 10' (block 2-3) during execution of the operator switch(). In this case, the program first calls to function Close_All(1). The execution of this function results in closing of all market orders Sell opened for the symbol EURUSD. After all orders Sell have been closed, the available money is checked for whether it is enough to make the next trade. For this purpose, the user-defined function Lot() is called (see Volume Detecting Function). If this function returns 'false', it means that the money available on the account is not enough to open order Buy with the minimum allowed amount of lots. In this case, the function Trade() ends its operations. If there is enough money, the trade function Open_Ord(0) is called to open one market order Buy with the amount of lots calculated at the execution of function Lot(). The described set of actions represents the Expert Advisor's response to the situation on the market (according to the given trade criterion).

If the criterion is important that points out at the necessity to close market orders Buy, the control is passed to the mark 'case 11' in block 3-4. In this case, only one function Close_All(0) is called to close all the orders of the Buy type available. Blocks 4-6 are built in the way similar to blocks 2-4, the control is passed to marks 'case 20' and 'case 21', if the criteria for selling or closing market orders Sell become important.

Please note that all executive trade functions that form trade requests are called in the function Trade() that, in its turn, is called at the execution of the EA's special function start() launched by the client terminal as a result of a new tick incoming. The code of the function Trade() is written in such a way that the control is not returned to the function start() (and, at the end, to the client terminal) until all required executive trade functions are executed. This is why all trades intended for each trading criterion are made by the EA one by one, without breaks. The exception may be the cases of critical errors occurring during making of trades (see Error Processing Function).

If no trading criterion is detected as important (variable Trad_Oper is equal to 0) at the execution of the function Criterion(), the control is passed to the mark 'case 0', which results in double call to function Tral_Stop() to modify the requested values of the market orders of different types. The trading strategy realized in this EA allows the availability of only one market order, so the sequence of calls to the functions Tral_Stop(0) and Tral_Stop(1) doesn't matter. In this case, it is a random choice.

If the function Criterion() has returned the value of -1, this means that the EA is attached to the window of a symbol that is not EURUSD. In this case, the function Trade() does not call to any executive trade functions and returns the control to the special function start() that has called it.


User-Defined Executive Trade Function Close_All()

int Close_All( int Tip)

The function closes all market orders of the given type.

The parameter Tip can take the following values corresponding with the types of orders to be closed:
0 - closing Buy orders;
1 - closing Sell orders.

To execute the function, it is necessary to apply the order accounting function Terminal(), the event tracking function Events() and the error processing function Errors() in the program. To display messages, the function implies using of the data function Inform(). If the function Inform() is not included in the EA, no messages will be displayed.

The values of the following global arrays are used:

  • Mas_Ord_New - the array of characteristics of orders available as of the moment of the function Terminal() execution;
  • Mas_Tip - the array of the total amount of orders of all types as of the moment of the last execution of the function Terminal().

The executive trade function Close_All() is formed as the include file Close_All.mqh:

//---------------------------------------------------------------------------------
// Close_All.mqh
// The code should be used for educational purpose only.
//---------------------------------------------------------------------------- 1 --
// Function closing all market orders of the given type
// Global variables:
// Mas_Ord_New Last known order array
// Mas_Tip Order type array
//---------------------------------------------------------------------------- 2 --
int Close_All(int Tip) // User-defined function
{
// int Tip // Order type
int Ticket=0; // Order ticket
double Lot=0; // Amount of closed lots
double Price_Cls; // Order close price
//---------------------------------------------------------------------------- 3 --
while(Mas_Tip[Tip]>0) // As long as the orders of the ..
{ //.. given type are available
for(int i=1; i<=Mas_Ord_New[0][0]; i++)// Cycle for live orders
{
if(Mas_Ord_New[i][6]==Tip && // Among the orders of our type
Mas_Ord_New[i][5]>Lot) // .. select the most expensive one
{ // This one was found at earliest.
Lot=Mas_Ord_New[i][5]; // The largest amount of lots found
Ticket=Mas_Ord_New[i][4]; // Its order ticket is that
}
}
if (Tip==0) Price_Cls=Bid; // For orders Buy
if (Tip==1) Price_Cls=Ask; // For orders Sell
Inform(12,Ticket); // Message about an attempt to close
bool Ans=OrderClose(Ticket,Lot,Price_Cls,2);// Close order !:)
//---------------------------------------------------------------------- 4 --
if (Ans==false) // Failed :(
{ // Check for errors:
if(Errors(GetLastError())==false)// If the error is critical,
return; // .. then leave.
}
//---------------------------------------------------------------------- 5 --
Terminal(); // Order accounting function
Events(); // Event tracking
}
return; // Exit the user-defined function
}
//---------------------------------------------------------------------------- 6 --

In block 1-2, the global variables used are described. In block 2-3, local variables are opened and described. The condition Mas_Tip[Tip]>0 in the heading of the cycle operator 'while' (blocks 3-6) implies that the function will hold the control until it fulfills its intended purpose, namely, until all orders of the given type are closed. The element of the global array Mas_Tip[Tip] contains the value equal to the amount of orders of the given type Tip. For example, if the function Close_All() is called with the transferred parameters equal to 1, this means that the function must close all market orders Sell (see Types of Trades). In this case, the value of the array element Mas_Tip[1] will be equal to the amount of available orders Sell (last known as of the moment of the execution of the function Terminal()). Thus, the cycle operator 'while' will be executed so many times as many Sell orders are available.

If the trader doesn't intervene into the operations of the EA (i.e., he or she doesn't place orders manually), then only one market order of one type or another may be available in trading. However, if the trader has additionally placed one or several market orders on his or her own initiative, then a certain sequence of orders must be kept at the execution of the function Close_All(). The preferable sequence of closing orders is to close larger ones first. For example, if there are three orders Sell as of the moment of starting to execute the function Close_All(), one of them being opened for 5 lots, another one being opened for 1 lot, and the third one being opened for 4 lots, then the orders will be closed in the following sequence according to the above reasoning: the first order to be closed will be that of 5 lots, then that of 4 lots, and the last will be the order of 1 lot.

Please note that the amount of lots is the only criterion used to determine the sequence of closing orders. The order's profit/loss, open price, as well as other parameters characterizing the order (the requested stop-order prices, time and reason for closing, etc.) are not considered.

All market orders of a certain type must be closed, if the criterion for closing of orders of this type is important, the sequence of closing being from the larger to the smaller volumes.

To keep the above sequence of closing order, in block 3-4, the cycle 'for' is used, in which the largest (in volume) order is selected among all orders of the given type. This order is searched for on the basis of analysis of the values of global array Mas_Ord_New containing the information about all order available in trading. After the ticket of this order has been detected, according to the order type, the requested close price will be calculated that is equal to the corresponding value of the last known two-way quote. If the orders to be closed are of Buy type, the close price must be requested on the basis of Bid value. If they are Sell orders, then use Ask values.

Directly before forming a trade request, the information about the attempt to close the order is displayed. The program uses function call Inform() for this purpose. The trade request for closing of the order is formed in the line:

      bool Ans=OrderClose(Ticket,Lot,Price_Cls,2);// Close order !:)

The calculated values are used as parameters: Ticket - order number, Lot - volume in lots, Price_Cls - requested close price, 2 - slippage.

In block 4-5, the trade results are analyzed. If the function OrderClose() has returned 'true', this means that the trade has completed successfully, i.e., the order has been closed. In this case, the control is passed to block 5-6, where the information about orders available at the current moment is updated. After the execution of functions Terminal() and Events(), the current iteration of the cycle 'while' ends (the amount of available orders can change within the function execution time and during making trades, so the execution of the order accounting function is obligatory at each iteration of the cycle 'while'). If the orders of the given type are still available in trading, they will be closed at the next iteration of the cycle 'while', the new values of the elements of arrays Mas_Ord_New and Mas_Tip obtained at the execution of the function Terminal() being used for determining of the parameters of the next order to be closed.

If the execution of the request results in that the function OrderClose() returns 'false', this means that the order has not been closed. In order to find out about the reasons for this failure, the program analyzes the last error occurred at the attempt to make the trade. For this purpose, it calls to the function Errors() (see Error Processing Function). If, at execution of this function, the program detects that the error is critical (for example, trading is prohibited), the function Close_All() ends its operations and returns the control to the control trade function Trade(), which finally results in that the special function start90 of the EA ends its execution, as well. At the next tick, the terminal will launch the function start() for execution again. If the closing criterion remains actual at that moment, this will produce the call to the function closing all orders, Close_All().


User-Defined Executive Trade Function Open_Ord()

int Open_Ord ( int Tip)

The function opens one market order of the given type.

The parameter Tip can take the following values corresponding with the types of the orders to be opened:
0 - the type Buy of orders to be opened;
1 - the type Sell of orders to be opened.

To execute the function, you should use in the program the order accounting function Terminal(), the event tracking function Events() and the error processing function Errors(). To display messages, the function implies the data function Inform(). If the function Inform() is not included in the EA, no messages will be displayed.

The values of the following global variables are used:

  • Mas_Tip - the array of the total amount of orders of all types as of the moment of the last execution of the function Terminal();
  • StopLoss - the value of StopLoss (amount of points);
  • TakeProfit - the value of TakeProfit (amount of points).

The executive trade function Open_Ord() is formed as include file Open_Ord.mqh:

//---------------------------------------------------------------------------------
// Open_Ord.mqh
// The code should be used for educational purpose only.
//---------------------------------------------------------------------------- 1 --
// Function opening one market order of the given type
// Global variables:
// int Mas_Tip Order type array
// int StopLoss The value of StopLoss (amount of points)
// int TakeProfit The value of TakeProfit (amount of points)
//---------------------------------------------------------------------------- 2 --
int Open_Ord(int Tip)
{
int Ticket, // Order ticket
MN; // MagicNumber
double SL, // StopLoss (as related to the price)
TP; // TakeProf (as related to the price)
//---------------------------------------------------------------------------- 3 --
while(Mas_Tip[Tip]==0) // Until they ..
{ //.. succeed
if (StopLoss<Level_new) // If it is less than allowed..
StopLoss=Level_new; // .. then the allowed one
if (TakeProfit<Level_new) // If it is less than allowed..
TakeProfit=Level_new; // ..then the allowed one
MN=TimeCurrent(); // Simple MagicNumber
Inform(13,Tip); // Message about an attempt to open
if (Tip==0) // Let's open a Buy
{
SL=Bid - StopLoss* Point; // StopLoss (price)
TP=Bid + TakeProfit*Point; // TakeProfit (price)
Ticket=OrderSend(Symbol(),0,Lots_New,Ask,2,SL,TP,"",MN);
}
if (Tip==1) // Let's open a Sell
{
SL=Ask + StopLoss* Point; // StopLoss (price)
TP=Ask - TakeProfit*Point; // TakeProfit (price)
Ticket=OrderSend(Symbol(),1,Lots_New,Bid,2,SL,TP,"",MN);
}
//---------------------------------------------------------------------- 4 --
if (Ticket<0) // Failed :(
{ // Check for errors:
if(Errors(GetLastError())==false)// If the error is critical,
return; // .. then leave.
}
Terminal(); // Order accounting function
Events(); // Event tracking
}
//---------------------------------------------------------------------------- 5 --
return; // Exit the user-defined function
}
//---------------------------------------------------------------------------- 6 --

In blocks 1-3 of the function Open_Ord(), the global variables are described, the values of which are used at the execution of the function, and local variables are opened and described. The basic code of the function is concentrated in the cycle operator 'while' (blocks 3-5) that is executed as long as no orders of the given type Tip are available in trading.

The trading strategy implies opening orders that have non-zero stop orders. In a general case, a trader may set such values of stop orders that will not comply with the requirements of the dealing center, namely, less than the allowed minimum distance from the market price. This is why the necessary checks are made before opening an order: If the last known minimum distance (Level_new) exceeds the value of the external variable StopLoss or TakeProfit, the value of this variable is increased and set to be equal to Level_new.

Each order to be opened has its unique MagicNumber equal to the current server time. As a result of the execution of one EA for a symbol, only one market order can be open (or placed, if it is a pending order) at a time. This provides all market orders with unique MagicNumbers. Before opening an order, the function Inform() is executed, which results in displaying of a message informing about an attempt to make a trade.

According to the order type, the body of one of the operators 'if' is executed. For example, if the value of the transferred parameter Tip is equal to 0, this means that an order Buy must be opened. In this case, the values of StopLoss and TakeProfit are calculated that correspond with the Buy order type, then the control is passed to line

         Ticket=OrderSend(Symbol(),0,Lots_New,Ask,2,SL,TP,"",MN);

to form a trade request for opening a market order Buy. Similar calculations are made, if the value of the parameter Tip is 1, i.e., an order Sell should be opened.

Errors in all user-defined executive trade functions are processed in a similar way. If a trade is made successfully, the function ends its operations (because no next iteration of the cycle 'while' will be performed, since the value of the element of array Mas_Tip[Tip] will be equal to 1 after the execution of the function Terminal()). However, if the trade request is not executed, the errors are analyzed (block 4-5). In this case, the error detecting function Errors() is called. If it returns 'false' (the error is critical), the execution of the function Open_Ord() ends, the control is consecutively passed to the control trade function Trade(), to the special function start() and then to the client terminal. However, if the error is overcomable, then, after updating of order arrays in the function Terminal(), the control is passed to the consecutive iteration of the cycle 'while', which results in one more attempt to open an order.

Thus, the function Open_Ord() holds the control until an order is opened or a critical error is got at the execution of the trade request.


User-Defined Executive Trade Function Tral_Stop()

int Tral_Stop ( int Tip)

The function modifies all market orders of the given type.

The parameter Tip can take the following values corresponding with the type of orders to be modified:
0 - the type Buy of orders to be modified;
1 - the type Sell of orders to be modified.

To execute the function, it is necessary to use in the program the order accounting function Terminal(), the event tracking function Events(), and the error processing function Errors(). To display messages, the function implies the data function Inform(). If the function Inform() is not included in the EA, no messages will be displayed.

The values of the following global variables are used:

  • Mas_Ord_New - the array of characteristics of orders available as of the moment of the last execution of the function Terminal();
  • TralingStop - the distance between the market price and the desired value of the requested price for StopLoss (amount of points).

The executive trade function Tral_Stop() is formed as include file Tral_Stop.mqh:

//---------------------------------------------------------------------------------
// Tral_Stop.mqh
// The code should be used for educational purpose only.
//---------------------------------------------------------------------------- 1 --
// Function modifying StopLosses of all orders of the given type
// Global variables:
// Mas_Ord_New Last known order array
// int TralingStop Value of TralingStop (amount of points)
//---------------------------------------------------------------------------- 2 --
int Tral_Stop(int Tip)
{
int Ticket; // Order ticket
double
Price, // Market order open price
TS, // TralingStop (as related to the price)
SL, // Value of order StopLoss
TP; // Value of order TakeProfit
bool Modify; // A criterion to modify.
//---------------------------------------------------------------------------- 3 --
for(int i=1;i<=Mas_Ord_New[0][0];i++) // Cycle for all orders
{ // Searching for orders of the given type
if (Mas_Ord_New[i][6]!=Tip) // If this is not our type..
continue; //.. skip the order
Modify=false; // It is not assigned to be modified
Price =Mas_Ord_New[i][1]; // Order open price
SL =Mas_Ord_New[i][2]; // Value of order StopLoss
TP =Mas_Ord_New[i][3]; // Value of order TakeProft
Ticket=Mas_Ord_New[i][4]; // Order ticket
if (TralingStop<Level_new) // If it is less than allowed..
TralingStop=Level_new; // .. then the allowed one
TS=TralingStop*Point; // The same in the relat, price value
//---------------------------------------------------------------------- 4 --
switch(Tip) // Go to Order type
{
case 0 : // Order Buy
if (NormalizeDouble(SL,Digits)<// If it is lower than we want..
NormalizeDouble(Bid-TS,Digits))
{ // ..then modify it:
SL=Bid-TS; // Its new StopLoss
Modify=true; // Assigned to be modified.
}
break; // Exit 'switch'
case 1 : // Order Sell
if (NormalizeDouble(SL,Digits)>// If it is higher than we want..
NormalizeDouble(Ask+TS,Digits)||
NormalizeDouble(SL,Digits)==0)//.. or zero(!)
{ // ..then modify it
SL=Ask+TS; // Its new StopLoss
Modify=true; // Assigned to be modified.
}
} // End of 'switch'
if (Modify==false) // If there is no need to modify it..
continue; // ..then continue the cycle
bool Ans=OrderModify(Ticket,Price,SL,TP,0);//Modify it!
//---------------------------------------------------------------------- 5 --
if (Ans==false) // Failed :(
{ // Check for errors:
if(Errors(GetLastError())==false)// If the error is critical,
return; // .. then leave.
i--; // Decreasing counter
}
Terminal(); // Order accounting function
Events(); // Event tracking
}
return; // Exit the user-defined function
}
//---------------------------------------------------------------------------- 6 --

In blocks 1-3, the global variables are described that are used in the function, as well as local variables are opened and described. In the cycle 'for' (blocks 3-6), the orders of the given type are selected and, if the StopLoss of any of those orders is further from the current price than it was set by the user, the order is modified.

To make the code more human-oriented, the values of some elements of the order array Mas_Ord_New are assigned to simple variables (block 3-4). Then the necessary check will be made for the variable TralingStop: If the value of this variable is less than the minimum allowed distance set by the dealing center, it will be increased up to the minimum allowed value.

In block 4-5, according to the order type, necessary calculations are made. For example, if the value of the transferred parameter Tip is 1 (an order Sell should be modified), the control will be passed to the mark 'case 1' of the operator 'switch'. The necessity to modify the order StopLoss is checked here (according to the rules that apply to this order type, see Requirements and Limitations in Making Trades). If no StopLoss is set or if it is set on a distance further than the value of TralingStop from the current market price, the desired new value of StopLoss is calculated. Trade request for modification of the order is formed in line:

      bool Ans = OrderModify(Ticket,Price,SL,TP,0);//Modify it!

It was noted before that the trading strategy considered here implied the availability of only one market order. Nevertheless, the function Tral_Stop() provides the possibility to modify several market orders of one type. If the trader does not intervene into trading during the work of the EA, no necessity to modify several orders occurs. However, if the trader opens a market order manually (in addition to those already opened), we have to decide which of the orders available should be modified as the first and why.

When considering the sequence of closing several orders, we mentioned that the criterion defining the priority in closing of orders was the amount of lots. This solution is obvious - the more lots (of the total amount) are closed, the sooner the EA will response to the triggering of the closing criterion. The problem of order modification sequence has no unambiguous solution. In all cases, the criterion for order modification sequence is determined by the essence of the trading strategy. This criterion may be both the amount of lots, the fact of no StopLoss at one of the orders, the distance from StopLoss to the current price. In a number of cases, this criterion may be expressed through an overall index - the size of loss that may result from sharp price changes, i.e., when all market orders are automatically closed by StopLoss at the same time.

In the above example of the function Tral_Stop(), a random sequence of order modification is realized - the orders are modified in the sequence, in which they occur in the lost of open market orders and placed pending orders. In each specific case, the function must be refined upon - the order modification sequence must be programmed according to the rules of your specific trading strategy.

Special attention should be paid to the fact that all trades are made in the real-time mode. If there are too many orders, the EA will generate a great variety of trade requests. Obviously, the market may turn around while those requests are being executed. However, the function doesn't return the control to the function Trade() that has called to it until all orders that must be modified are modified. This means that the danger of omitting a trade request for closing or opening of orders may occur. For this reason, any strategy must be coded in such a way that not to allow a considerable amount of market orders to be available at a time.

In block 5-6, the errors got during the execution of trade requests are analyzed. If the error is critical, the function will end its operations. However, if an overcomable error has been got, the value of the counter 'i' is decreased by 1. It will be done in order to produce one more attempt to modify the same order at the next iteration of the cycle 'for'.

In most cases, the above code will comply with the necessity to modify several orders. At the same time, if any changes take place in the orders (for example, an order will be closed when the market price reaches one of the stop levels) within the period of several failed attempts to modify orders, the sequence of orders in the array Mas_Ord_New may also change. This will result in that an order may be omitted and not modified within the period of the last launching of the special function start(). This situation can be improved at the next tick, at the next launch of the function start().