MQL4 Book  Programming of Trade Operations  Closing and Deleting Orders

Closing and Deleting Orders


Closing Market Orders


Trade requests for closing of market orders are formed using the function OrderClose().

Function OrderClose()

bool OrderClose (int ticket, double lots, double price, int slippage, color Color=CLR_NONE)

It is a function used to close a market order. The function returns TRUE, if the trade is performed successfully. It returns FALSE, if the trade fails.

Parameters:

ticket - the unique number of the order.

lots - the amount of lots to be closed. It is allowed to specify a value that is less than the available amount of lots in the order. In this case, if the trade request is successfully executed, the order will be closed partly.

price - close price. This parameter is set according to the requirements and limitations accepted for performing of trades (see Order Characteristics and Rules for Making Trades and Appendix 3). If there is no requested price available for closing of the market order in the price flow or if it is outdated, this trade request will be rejected; if the price is outdated, but found in the price flow and, at the same time, its deviation from the current price ranges within the value of slippage, the trade request will be accepted by the client terminal and sent to the trade server.

slippage - the maximum allowed deviation of the requested price for closing of the order from the market price (in points).

Color - the color of the closing arrow in a chart. If this parameter is unavailable or its value is equal to that of CLR_NONE, the arrow will not be displayed in the chart.


If the program contains information about the type of the order to be closed, about its unique number, as well as about the amount of lots to be closed, then it is very easy to close the order. For this, you should use in the program code the OrderClose() function call with preset parameters. For example, if the unique number of the order Buy is 12345 and if you want to close 0.5 lot, the call to the function closing the order may look like this:

OrderClose( 12345, 0.5, Bid, 2 );

In order to decide about what orders and in what sequence should be closed, you have to have data of all orders opened in the current situation. In MQL4, there is a number of functions that can be used to get various data that characterize any order. For example, the function OrderOpenPrice() returns the value of the order open price (or of the requested price for pending orders), the function OrderLots() returns the amount of lots, the function OrderType() returns the type of the order, etc. All functions that return the values of an order characteristic call at their execution to the order that has been selected by the function OrderSelect().

Function OrderSelect()


In order to get the parameters of any of your orders (no matter market or pending, closed or deleted ones), you should first select it using the function OrderSelect().

bool OrderSelect(int index, int select, int pool=MODE_TRADES)

OrderSelect is a function that selects an order for further operations with it. It returns TRUE, if the function is executed successfully. Otherwise, it returns FALSE.

Parameters:

index - the order position or number, it depends on the second parameter.

select - the flag of selection method. Parameter 'select' can take one of two possible values:

SELECT_BY_POS - in the parameter 'index', the order number in the list is returned (the numbering starts with 0),

SELECT_BY_TICKET - in the parameter 'index', the ticket number (the unique order number) is returned.

pool - the data source for selection. The parameter 'pool' is used, when the parameter 'select' is equal to the value of SELECT_BY_POS. The parameter 'pool' is ignored, if the order is selected by the ticket number (SELECT_BY_TICKET). The parameter 'pool' can take on of two possible values:

MODE_TRADES (by default) - the order is selected in open and pending orders, i.e., among the orders displayed in the "Trade" tab of the "Terminal" window;

MODE_HISTORY - the order is selected in closed and deleted orders, i.e., among the orders displayed in the "Account History" tab of the "Terminal" window. In this case, the depth of history specified by the user for displaying of closed and deleted orders is important.


In order to demonstrate the method of using trade functions for closing of market orders, let's solve a problem:

Problem 28. Write a script that closes one of the market orders available on the account. The script execution must result in closing of the order closest to the location of the script attached to the symbol window with the mouse.

Suppose there are three market orders opened in the terminal for the symbol Eur/Usd and a pending order opened for Usd/Chf:


Fig. 90. Displaying several orders opened for different symbols in the terminal window.

We should write such a script that can be dragged by the mouse from the "Navigator" window into the symbol window, which should result in closing of one of the market orders, namely, the order closest to the cursor (as of the moment when the user released the mouse button). In Fig. 91, you can see the alternative, at which the cursor is closest to order Sell 4372889. It is this order that must be closed as a result of the script execution.


Fig. 91. Script closeorder.mq4 used for closing of the selected order.

To solve the problem, we should select (using the function OrderSymbol()) among all orders only those opened for the symbol, in the window of which the script is dropped. Then we should find the open prices of all selected market orders (i.e., execute the function OrderOpenPrice() successively for each order). Knowing the order open prices, we can easily select one of them that corresponds with the statement of the problem. To specify the proper values of parameters in the function OrderClose(), we will also need to know some other data about the selected order: the amount of lots (determined by the function OrderLots()) and the unique order number (determined by the function OrderTicket()). Besides, to find one or another price of a two-way quote, we have to know the type of the order (determined by the function OrderType()).

Let's consider what parameters must be specified in the function OrderSelect() in order to obtain the above order characteristics.

First of all, it is necessary to choose the order selection method. In our problem, the selection method is determined by the problem statement itself: The data about order numbers is supposed to be unavailable in the program as of the moment of launching the script for execution, i.e., the program is considered to contain a block that would determine those order numbers. This means that we should check all orders one by one displayed in "Terminal" (Fig. 64.1), so we have to use the parameter SELECT_BY_POS.

The source for selection of orders is obvious, as well. To solve the problem, there is no need to analyze closed and deleted orders. In this case, we are interested in market orders only, so we will search in them using the parameter MODE_TRADES in the function OrderSelect(). For the parameter 'pool', the default value of MODE_TRADES is specified in the function header, so it can be skipped.

Below is shown how a block for analyzing of market and pending orders can be built:

   for (int i=1; i<=OrdersTotal(); i++)       //Cycle for all orders..
{ //displayed in the terminal
if(OrderSelect(i-1,SELECT_BY_POS)==true)//If there is the next one
{
// Order characteristics..
// ..must be analyzed here
}
} //End of the cycle body

In the heading of the cycle operator, the initial value is specified as i=1, whereas the condition to exit the cycle is the expression i<=OrdersTotal(). Function OrdersTotal() returns the total amount of market and pending orders, i.e., those orders that are shown in the "Trade" tab of the "Terminal" window. This is why there will be as many iterations in the cycle as many orders participate in trading.

At each iteration, when the condition is calculated in the operator 'if', the function OrderSelect(i-1,SELECT_BY_POS) will be executed. The following important matter must be noted here:

The numbering of orders in the list of market and pending orders starts with zero.

This means that the first order in the list (Fig. 90) is placed in zero position, the position of the second order is numbered as 1, that of the third order is numbered as 2, etc. This is why, in the function call OrderSelect(), the value of index is given as i-1. Thus, for all selected orders, this index will always be 1 less than the value of the variable i (that coincides with the number of the next iteration).

The function OrderSelect() returns true, if the order is successfully selected. It means that it is possible that an order selection can fail. This can happen, if the amount of orders changed during their processing. When programming in MQL4, you should well remember that an application program will work in the real-time mode and that, while it is processing some parameters, the values of these parameters may change. For example, the amount of market orders can change as a result of both opening/closing of orders and modifying of pending orders into market ones. This is why you should keep to the following rule when programming order processing: Orders must be processed as soon as possible, whereas the program block responsible for this processing should not, if possible, contain redundant program lines.

According to the code represented in Fig. 64.3, in the header of the operator 'if', the program analyzes whether the next order is available in the order list at the moment when it is selected. If the next order is available, the control will be passed into the body of the operator 'if' to process the order parameters. It must be noted that such construction does not help much, in case of possible conflicts, because the order can be lost (closed) during processing of its parameters. However, this solution turns out to be most efficient if, as of the moment of its selection, the order is not available anymore. In the body of the operator 'if', the parameters of the selected order are analyzed. When executing the functions OrderOpenPrice(), OrderTicket(), OrderType() and others of the kind, each of them will return the value of a certain characteristic of the order selected as a result of execution of the function OrderSelect().

All the above reasoning was used in the program that would solve Problem 28.

An example of a simple script intended for closing of a market order, the open price of which is closer to the location of the script attachment than the open prices of other orders (closeorder.mq4).

//--------------------------------------------------------------------------------------
// closeorder.mq4
// The code should be used for educational purpose only.
//--------------------------------------------------------------------------------- 1 --
int start() // Special function 'start'
{
string Symb=Symbol(); // Symbol
double Dist=1000000.0; // Presetting
int Real_Order=-1; // No market orders yet
double Win_Price=WindowPriceOnDropped(); // The script is dropped here
//-------------------------------------------------------------------------------- 2 --
for(int i=1; i<=OrdersTotal(); i++) // Order searching cycle
{
if (OrderSelect(i-1,SELECT_BY_POS)==true) // If the next is available
{ // Order analysis:
//----------------------------------------------------------------------- 3 --
if (OrderSymbol()!= Symb) continue; // Symbol is not ours
int Tip=OrderType(); // Order type
if (Tip>1) continue; // Pending order
//----------------------------------------------------------------------- 4 --
double Price=OrderOpenPrice(); // Order price
if (NormalizeDouble(MathAbs(Price-Win_Price),Digits)< //Selection
NormalizeDouble(Dist,Digits)) // of the closest order
{
Dist=MathAbs(Price-Win_Price); // New value
Real_Order=Tip; // Market order available
int Ticket=OrderTicket(); // Order ticket
double Lot=OrderLots(); // Amount of lots
}
//----------------------------------------------------------------------- 5 --
} //End of order analysis
} //End of order searching
//-------------------------------------------------------------------------------- 6 --
while(true) // Order closing cycle
{
if (Real_Order==-1) // If no market orders available
{
Alert("For ",Symb," no market orders available");
break; // Exit closing cycle
}
//-------------------------------------------------------------------------- 7 --
switch(Real_Order) // By order type
{
case 0: double Price_Cls=Bid; // Order Buy
string Text="Buy "; // Text for Buy
break; // Из switch
case 1: Price_Cls=Ask; // Order Sell
Text="Sell "; // Text for Sell
}
Alert("Attempt to close ",Text," ",Ticket,". Awaiting response..");
bool Ans=OrderClose(Ticket,Lot,Price_Cls,2);// Order closing
//-------------------------------------------------------------------------- 8 --
if (Ans==true) // Got it! :)
{
Alert ("Closed order ",Text," ",Ticket);
break; // Exit closing cycle
}
//-------------------------------------------------------------------------- 9 --
int Error=GetLastError(); // Failed :(
switch(Error) // Overcomable errors
{
case 135:Alert("The price has changed. Retrying..");
RefreshRates(); // Update data
continue; // At the next iteration
case 136:Alert("No prices. Waiting for a new tick..");
while(RefreshRates()==false) // To the new tick
Sleep(1); // Cycle sleep
continue; // At the next iteration
case 146:Alert("Trading subsystem is busy. Retrying..");
Sleep(500); // Simple solution
RefreshRates(); // Update data
continue; // At the next iteration
}
switch(Error) // Critical errors
{
case 2 : Alert("Common error.");
break; // Exit 'switch'
case 5 : Alert("Old version of the client terminal.");
break; // Exit 'switch'
case 64: Alert("Account is blocked.");
break; // Exit 'switch'
case 133:Alert("Trading is prohibited");
break; // Exit 'switch'
default: Alert("Occurred error ",Error);//Other alternatives
}
break; // Exit closing cycle
}
//------------------------------------------------------------------------------- 10 --
Alert ("The script has finished operations -----------------------------");
return; // Exit start()
}
//------------------------------------------------------------------------------- 11 --

The whole code of the program closeorder.mq4 is concentrated in the special function start(). In block 1-2, some variables are initialized. The variable Dist is the distance from the location where the script has been dropped to the closest order. The variable Real_Order is a flag that displays the availability of at least one market order in the client terminal (nonnegative value). The variable Win_Price is the price, at which the user has attached the script to the symbol window. In block 2-6, the order is analyzed: One of the orders available is assigned to be closed. Block 6-10 is the block of closing the order and of processing the errors that can occur during performing of the trade.

Starting from the moment when the user attached the script to the symbol window, the values of the variables are calculated in block 1-2, the variable Win_Price taking the value of the price, at the level of which the user attached the script. It is now necessary to find the order (with its characteristics) that is closest to this location.

In the cycle 'for' (block 2-6), the orders are searched in. In block 2-3, the program checks whether there is an order in the next line of the "Terminal". If an order is found, the control is passed to the body of the operator 'if' to get and analyze the characteristics of that order. In block 3-4, the orders opened for wrong symbols (not the symbol, for which the program is being executed) are filtered out. In our case, it is order 4372930 opened for Usd/Chf. Function OrderSymbol() returns the symbol name of the selected order. If this symbol name is other than that, for which the program is being executed, the current iteration is broken, preventing the order opened for another symbol from being processed. If the order under analysis turns out to be opened for "our" symbol, one more check will be performed. The order type is determined using the function OrderType() (see Types of Trades). If the order type turns out to be more than 1, it means that the order is a pending one. In this case, the current iteration is interrupted, too, because we are not interested in pending orders. In our example, we have such an order, but it is opened for another symbol, so it has already been filtered out. All orders that pass block 3-4 successfully are market ones.

Block 4-5 is intended for selecting only one order of all market orders that have successfully passed the preceding block. This order must be the closest to the predefined price (the value of the variable Win_Price). The user is not required to "pinpoint" the order line with his or her mouse cursor. The order that is closer than any other orders to the cursor as of the moment of launching the script for execution will be selected. The open price of the order processed is found using the function OrderOpenPrice(). If the absolute value of the distance between the price of the current order and the "cursor price" is less than the same distance for the preceding order, the current order will be selected (the absolute value of the distance is necessary for excluding of the influence of the cursor position - under or above the order line). In this case, this order will be memorized at the current iteration of the cycle 'for' as a front-runner for being closed. For this order, the ticket number (the individual number of the order) and the amount of lots are calculated at the end of block 4-5. In this example (Fig. 90), the total amount of orders is four (three market ones and one pending order), so there will be four iterations executed in the cycle 'for', which will result in finding all necessary data for closing of one selected order.

Then the control in the executing program will be passed to the cycle operator 'while' (block 6-10). In block 6-7, the market orders found are checked for availability. If no market orders are found in block 2-4 (it is quite possible, in general), the value of the flag Real_Order remains equal to -1, which means the unavailability of market orders. If the checking in block 6-7 detects no market orders, the execution of the cycle 'while' is broken, the program then finishes its operations. If the value of the variable Real_Order turns out to be equal to 0 or 1, this means that a market is predefined for closing and must be closed.

In block 7-8, according to the order type, the close price of the order is calculated. It is the value of Bid for Buy orders, and the value of Ask for Sell orders (see Requirements and Limitations in Making Trades).

In block 7-8, the values of the auxiliary variable Text are calculated. The trade request for closing of the order is formed in the function OrderClose() in the line below:

      bool Ans=OrderClose(Ticket,Lot,Price_Cls,2);// Order closing

Trade function OrderClose() returns true, if the trade is made successfully, and false, if not. If the trade request is successfully executed on the server, the value 'true' will be assigned to the variable Ans (answer). In this case, when executing block 8-9, the program will inform the user about successful order closing. After that, the execution of the cycle operator 'while' will be stopped, and the program will end its operations. Otherwise, the control will be passed to block 9-10 in order to analyze the error returned by the client terminal to the program.

At the beginning of block 9-10, the error code is calculated. After that, according to the error code, either program exit or repeated operation are executed. In the first operator 'switch', the program processes the errors that are implicitly overcomable, i.e., the errors can be considered as temporary difficulties in performing of the trade. All necessary actions are taken for each of such errors, then the current iteration is stopped and the execution of the cycle 'while' restarts. (Please note that, in this example, we use for error processing the operator 'switch' that is exited as a result of using of the operator 'continue' that, as such, is not intended for passing of the control outside the operator 'switch'. This construction works just because the operator 'switch' is a part of contents of the external cycle operator 'while' and the operator 'continue' interrupts the current iteration by passing of the control to the header of the operator 'while').

If the error code is not processed in the first operator 'switch', this error is considered to be critical. In this case, the control is passed to the second operator 'switch', which is executed in order to inform the user that one or another critical error has occurred. Further, the program uses the operator 'break' that interrupts the execution of the cycle 'while'. Exiting the cycle 'while', for any reason, will result in passing of the control to block 9-10 that produces a message about the end of the program operations. The operator 'return' stops the execution of the special function start(), and the program finishes its operations.

Practical result obtained after launching of the script under the stated conditions (see Fig. 90 and 91) is shown below. The trade was successfully made on the server.


Fig. 92. Messages received as a result of successful execution of the script closeorder.mq4.

As a result of closing of one of the orders, there are two orders left in the window of Eur/Usd.


Fig. 93. Execution of the script closeorder.mq4 results in closing of one of the orders.

Order closing has also been displayed in the "Terminal" window:


Fig. 94. After Execution of the Script closeorder.mq4, Two Market Orders Are Displayed in the "Terminal" Window.

Later, the other two orders are closed using this script, too.


Deleting Pending Orders


Trade requests for deleting of pending orders are formed using the function OrderDelete().

Function OrderDelete()

bool OrderDelete(int ticket, color arrow_color=CLR_NONE)

The function deletes the previously placed pending order. It returns TRUE, if it has worked successfully. Otherwise, it returns FALSE.

Parameters:

ticket - the unique number of an order.

arrow_color - the color of an arrow in a chart. If this parameter is unavailable or its value is equal to that of CLR_NONE, the arrow will not be displayed in the chart.

It's easy to see that the function OrderDelete( ) does not contain a specification of the volume and the close price of the order to be deleted.

The order is deleted regardless any market prices. The partly deletion of an order is impossible, too. You can decrease the amount of lots in a pending order in two stages: delete the existing order and then place a new pending order with the decreased (any) amount of lots.

The algorithm of the program that will delete a pending order can be quite identical to that of market order closing. A slight difference is in that no close price is needed to delete a pending order, so the program below does not contain the block that updates market prices.

An example of a simple script intended for deletion of a pending order, the requested price of which is closer to the location of the script attachment than the prices of other pending orders (deleteorder.mq4).

//-------------------------------------------------------------------------------------
// deleteorder.mq4
// The code should be used for educational purpose only.
//-------------------------------------------------------------------------------- 1 --
int start() // Special function 'start'
{
string Symb=Symbol(); // Symbol
double Dist=1000000.0; // Presetting
int Limit_Stop=-1; // No pending orders yet
double Win_Price=WindowPriceOnDropped(); // The script is dropped here
//-------------------------------------------------------------------------------- 2 --
for(int i=1; i<=OrdersTotal(); i++) // Order searching cycle
{
if (OrderSelect(i-1,SELECT_BY_POS)==true) // If the next is available
{ // Order analysis:
//----------------------------------------------------------------------- 3 --
if (OrderSymbol()!= Symb) continue; // Symbol is not ours
int Tip=OrderType(); // Order type
if (Tip>2) continue; // Market order
//----------------------------------------------------------------------- 4 --
double Price=OrderOpenPrice(); // Order price
if (NormalizeDouble(MathAbs(Price-Win_Price),Digits)> //Selection
NormalizeDouble(Dist,Digits)) // of the closest order
{
Dist=MathAbs(Price-Win_Price); // New value
Limit_Stop=Tip; // Pending order available
int Ticket=OrderTicket(); // Order ticket
} // End of 'if'
} //End of order analysis
} // End of order searching
//-------------------------------------------------------------------------------- 5 --
switch(Limit_Stop) // By order type
{
case 2: string Text= "BuyLimit "; // Text for BuyLimit
break; // Exit 'switch'
case 3: Text= "SellLimit "; // Text for SellLimit
break; // Exit 'switch'
case 4: Text= "BuyStopt "; // Text for BuyStopt
break; // Exit 'switch'
case 5: Text= "SellStop "; // Text for SellStop
break; // Exit 'switch'
}
//-------------------------------------------------------------------------------- 6 --
while(true) // Order closing cycle
{
if (Limit_Stop==-1) // If no pending orders available
{
Alert("For ",Symb," no pending orders available");
break; // Exit closing cycle
}
//-------------------------------------------------------------------------- 7 --
Alert("Attempt to delete ",Text," ",Ticket,". Awaiting response..");
bool Ans=OrderDelete(Ticket); // Deletion of the order
//-------------------------------------------------------------------------- 8 --
if (Ans==true) // Got it! :)
{
Alert ("Deleted order ",Text," ",Ticket);
break; // Exit closing cycle
}
//-------------------------------------------------------------------------- 9 --
int Error=GetLastError(); // Failed :(
switch(Error) // Overcomable errors
{
case 4: Alert("Trade server is busy. Retrying..");
Sleep(3000); // Simple solution
continue; // At the next iteration
case 137:Alert("Broker is busy. Retrying..");
Sleep(3000); // Simple solution
continue; // At the next iteration
case 146:Alert("Trading subsystem is busy. Retrying..");
Sleep(500); // Simple solution
continue; // At the next iteration
}
switch(Error) // Critical errors
{
case 2 : Alert("Common error.");
break; // Exit 'switch'
case 64: Alert("Account is blocked.");
break; // Exit 'switch'
case 133:Alert("Trading is prohibited");
break; // Exit 'switch'
case 139:Alert("The order is blocked and is being processed");
break; // Exit 'switch'
case 145:Alert("Modification is prohibited. ",
"The order is too close to the market");
break; // Exit 'switch'
default: Alert("Occurred error ",Error);//Other alternatives
}
break; // Exit closing cycle
}
//------------------------------------------------------------------------------- 10 --
Alert ("The script has finished operations -----------------------------");
return; // Exit start()
}
//------------------------------------------------------------------------------- 11 --

The error-processing block has also been slightly changed. You should consider the possibility of errors related to price changes (errors 135 and 136) when closing market orders, but such errors don't occur when deleting pending orders. For the same reason, the function RefreshRates() is used nowhere in the program.

Processing such errors as error 4 and error 137 (see Error Codes) can be a bit difficult. For example, when getting error 137, the program can take into consideration that "broker is busy". However, a natural question arises: When is the broker free, for the user to continue his or her trading? Error 137does not provide such information. This is why the programmer must decide him or herself how to build the program processing such errors properly. In a simple case, the request can be repeated after a certain pause (in our example, in 3 seconds). On the other hand, after a series of unsuccessful attempts to delete (or, in a common case, to close, open or modify) an order, the server may return error 141 - too many requests. This error results in that the script deleteorder.mq4 stops working. Generally, such conflicts are not the matters of programming. In such cases, you should contact the dealing center's support service and clarify the reasons for the rejection to execute the trade request.

Error 145 can occur, if a pending order (in a common case, it can be a stop order of a market order) is too close to the market price. This error does not occur, if you are steadily trading on a calm market. If prices change rapidly, your broker may decide that a certain order will be opened soon, so the broker will not allow to delete or modify it. This error is considered in the script as a critical one and results in termination of the program (it doesn't make any sense to bother the broker with trade requests). If the price changes after a while, you can try to delete the order by launching the script for execution again.

Generally, the occurrence of error 145 can be prevented, if you consider the freeze level set by the dealing center. Freeze level is a value that determines the price band, within which the order is considered as 'frozen', i.e., it can be prohibited to delete it. For example, if a pending order is placed at 1.2500 and the freeze level is equal to 10 points, it means that, if the price ranges from 1.2490 through 1.2510, the deletion of the pending order is prohibited. You can get the freeze level value having executed the function MarketInfo() with the request identifier of MODE_FREEZELEVEL.

Closing Opposite Orders


Opposite (Counter) Order is a market order opened in the direction opposite to the direction of another market order opened for the same symbol.

If you have two opposite orders for a certain symbol, you can close them simultaneously, one by another, using the function OrderCloseBy(). You will save one spread if you perform such an operation.

Function OrderCloseBy()

bool OrderCloseBy(int ticket, int opposite, color Color=CLR_NONE)

The function closes one market order by another market order opened for the same symbol in the opposite direction. The function returns TRUE, if it is completed successfully, and FALSE, if not.

Parameters:

ticket - the unique number of the order to be closed.

opposite - the unique number of the opposite order.

Color - the color of the closing arrow in a chart. If this parameter is unavailable or its value is equal to that of CLR_NONE, the arrow will not be displayed in the chart.

It is not necessary that opposite orders have the same volume. If you close an order by an opposite order, the trade will be perform in the volume of the order that has the smaller volume.

Let's consider an example. Let there be two market orders of the same volume in the client terminal, one Buy and one Sell. If we close each of them separately using the function OrderClose(), our economic output will be the sum of the profits obtained from each order:


Fig. 95. Result of separate closing of orders using the function OrderClose().

However, if we use in this situation the function OrderCloseBy() intended for opposite closing of orders, the economic output will be better (as compared to the preceding alternative) by the amount proportional to the cost of one order's spread:


Fig. 96. Result of closing orders by other orders using the function OrderCloseBy().

It is obvious that, if there are opposite orders to be closed in the terminal, it would be economically sound to use the function OrderCloseBy(), not OrderClose().

As to saving a spread at closing of opposite orders, we should give some more general explanations. As a matter of fact, opening an order (for example, a Buy order) is implicitly a trade that is opposite to opening of an order in the opposite direction (i.e., a Sell order) to the same degree as closing the order (the Buy order). In other words, it is economically the same which of the alternatives to use: just to close a market order or to open an opposite order of the same volume (and then close both orders by each other). The difference between these two alternatives may only consist in different methods used in different dealing centers to calculate the money to be diverted to support market orders (see Fig. 85 and Fig. 88).

It is also easy to see that the close price is not necessary to be specified in the function OrderCloseBy() for closing of opposite orders. It is unnecessary, because the profit and the loss of two opposite orders repay mutually, so the total economic output does not depend on the market price. Of course, this rule is effective only for orders of the same volume. If, for example, we have two orders for one symbol: a Buy order of 1 lot and a Sell order of 0.7 lot, this trade only depends on the market price as related to the Buy order part of 0.3 lot, whereas 0.7 lot of both orders don't depend on the symbol price.

Opposite orders do not influence the total trading results. This is why trading tactics based on opening of opposite orders don't have any informal contents (for this reason, some dealing centers forcedly close any opposite orders within the coinciding amounts of lots). The only (negative) influence of such tactics may consist in diverting of money according to the rules accepted in some dealing centers. Besides, the availability of several opposite orders provides more difficulties in the context of programmed trading, than one order does. If we consider various commissions and swaps (for each market order separately), the necessity to close opposite orders becomes obvious.

An example of a simple script that closes all opposite orders for a symbol (closeby.mq4).

//--------------------------------------------------------------------
// closeby.mq4
// The code should be used for educational purpose only.
//--------------------------------------------------------------- 1 --
int start()                                     // Special function 'start'
  {
   string Symb=Symbol();                        // Symbol
   double Dist=1000000.0;                       // Presetting
//--------------------------------------------------------------- 2 --
   while(true)                                  // Processing cycle..
     {                                          // ..of opposite orders
      double Hedg_Buy = -1.0;                   // Max. cost of Buy
      double Hedg_Sell= -1.0;                   // Max. cost of Sell
      for(int i=1; i<=OrdersTotal(); i++)       // Order searching cycle
        {
         if(OrderSelect(i-1,SELECT_BY_POS)==true)// If the next is available
           {                                    // Order analysis:
            //--------------------------------------------------- 3 --
            if (OrderSymbol()!= Symb) continue; // Symbol is not ours
            int Tip=OrderType();                // Order type
            if (Tip>1) continue;                // Pending order  
            //--------------------------------------------------- 4 --
            switch(Tip)                         // By order type
              {
               case 0:                          // Order Buy
                  if (OrderLots()>Hedg_Buy)
                    {
                     Hedg_Buy=OrderLots();      // Choose the max. cost
                     int Ticket_Buy=OrderTicket();//Order ticket
                    }
                  break;                        // From switch
               case 1:                          // Order Sell
                  if (OrderLots()>Hedg_Sell)
                    {
                     Hedg_Sell=OrderLots();     // Choose the max. cost
                     int Ticket_Sell=OrderTicket();//Order ticket
                    }
              }                                 //End of 'switch'
           }                                    //End of order analysis
        }                                       //End of order searching
      //--------------------------------------------------------- 5 --
      if (Hedg_Buy<0 || Hedg_Sell<0)            // If no order available..
        {                                       // ..of some type
         Alert("All opposite orders are closed :)");// Message  
         return;                                // Exit start()
        }
      //--------------------------------------------------------- 6 --
      while(true)                               // Closing cycle
        {
         //------------------------------------------------------ 7 --
         Alert("Attempt to close by. Awaiting response..");
        
bool Ans=OrderCloseBy(Ticket_Buy,Ticket_Sell);// Закрытие
         //------------------------------------------------------ 8 --
         if (Ans==true)                         // Got it! :)
           {
            Alert ("Performed closing by.");
            
break;                              // Exit closing cycle
           }
         //------------------------------------------------------ 9 --
         int Error=GetLastError();              // Failed :(
         switch(Error)                          // Overcomable errors
           {
            case  4: Alert("Trade server is busy. Retrying..");
              
Sleep(3000);                     // Simple solution
               continue;                        // At the next iteration
            case 137:Alert("Broker is busy. Retrying..");
              
Sleep(3000);                     // Simple solution
               continue;                        // At the next iteration
            case 146:Alert("Trading subsystem is busy. Retrying..");
              
Sleep(500);                      // Simple solution
               continue;                        // At the next iteration
           }
         switch(Error)                          // Critical errors
           {
            case 2 : Alert("Common error.");
              
break;                           // Exit 'switch'
            case 64: Alert("Account is blocked.");
              
break;                           // Exit 'switch'
            case 133:Alert("Trading is prohibited");
              
break;                           // Exit 'switch'
            case 139:Alert("The order is blocked and is being processed");
              
break;                           // Exit 'switch'
            case 145:Alert("Modification is prohibited. ",
                                
"The order is too close to market");
              
break;                           // Exit 'switch'
            default: Alert("Occurred error ",Error);//Other alternatives  
           }
         Alert ("The script has finished operations --------------------------");
        
return;                                // Exit start()
        }
     }                                          // End of the processing cycle
//-------------------------------------------------------------- 10 --
  }                                             // End of start()
//--------------------------------------------------------------------

The algorithm of the above script is a bit different than the preceding ones. This difference consists in that the same code must be executed many times in order to close several orders (the amount of orders to be closed in not limited) successfully. The script was tested on a random set of market orders. 5 orders of different volumes are represented in Fig. 97 below.


Fig. 97. Market orders opened for one symbol.

In order to close the available opposite orders, we should predefine the selection criteria. This criterion in the given algorithm is the order size - the orders of larger volumes are closed first, then the orders of smaller volumes are closed. After the opposite orders of different volumes have been closed, the orders of the resting volumes remain. For example, the closing of opposite orders Buy (1 lot) and Sell (0.8 lot) will result in that order Buy (0.2 lot) remains opened. This is why, after each successful closing, the program must refer to the updated list of orders to find two other largest opposite orders in this updated list.

The above calculations are realized in a (conditionally) continuous cycle 'while', in blocks 2-10. Фе the beginning of the cycle, at each iteration the program supposes that there are no orders of a certain type anymore. For this, the the value of -1 is assigned to the variables Hedg_Buy and Hedg_Sell. The algorithm of the order-processing block is, in general, preserved (see the code of closeby.mq4). In the order-searching cycle 'for', namely in block 3-4, like in the preceding programs, "wrong" orders are filtered out. In this case, these are orders opened for another symbol and pending orders.

In block 4-5, the volume of each order checked in block 3-4 is calculated. If it turns out during calculations that the currently processed order is the largest in volume among all orders processed, its ticket is stored. This means that the order having this ticket is, at this stage of calculations, a candidate for closing of opposite orders. By the moment when the last iteration of the cycle 'for' finishes, the tickets of orders with maximum amount of lots opened in opposite directions have already been known. These orders are selected by the program. If any orders of any types have already become unavailable by this moment, block 5-6 exits the program.

Block 6-10 represents error processing. It is completely the same as those considered above (in this and preceding sections). The trade request for closing of opposite orders is formed in block 7-8 using the function OrderCloseBy(). If it fails, according to the error code, the program passes the control either to retry making the trade (for the same tickets) or to the operator 'return' that ends the program operations.

If a trade is successfully performed, the program exits the error-processing block, and the current iteration of the most external cycle 'while' will end. Фе the next iteration of this cycle, all calculations will be repeated: searching in the orders available, selecting market orders, selected one ticked for each of order types, forming a trade request for opposite closing, and subsequent error analyzing. This cycle is executed until there are no available orders of a certain type (or, in a particular case, of both types) in the terminal. This event will be calculated in block 5-6, then the program ends its operations.

The following messages were received at the execution of the script closeby.mq4 intended for closing of market orders shown in Fig. 97:


Fig. 98. Messages received at execution of the script closeby.mq4.

On the "Account History" tab of the "Terminal" window, you can see that some orders are closed with a zero profit. This is what we save when closing opposite orders. You can compare economic results in Fig. 97 and Fig. 99:


Fig. 99. Account history after execution of the script closeby.mq4.

On the "Journal" tab in the "Terminal" window, you can track the history of order closing (the latest events are on top):


Fig. 100. Events happened during execution of the script closeby.mq4.

Фе the execution of the script, according to the algorithm, the orders of maximum volume available at the moment will be closed. In spite of the fact that the orders were opened in a random sequence (Fig. 97), the first orders to be closed were Buy 778594 and Sell 778595, with the volumes of 1 lot and 0.8 lot, respectively (the lower lines in Fig. 100). Since these orders have different volumes, the opposite closing produced a new order, Buy 778597, with the resting volume of 0.2 lot. Then the program selected orders Buy 778592 and Sell 778593, 0.5 lot each, to be closed as opposite orders. These orders were closed without opening a resting order.

By the moment the third iteration started, two orders had remained in the symbol window in the external cycle: initial order Sell 778596 of 0.3 lot and the order opened as a result of the execution of the script, Buy 778597 of 0.2 lot. In the upper lines of Fig. 100, you can see that those orders are also closed as opposite orders. The volumes of those orders were different, so the last trade resulted in that one market order of 0.1 lot remained in the symbol window (please note the economic results):


Fig. 101. Order Sell with remaining cost of 0.1 Lot.

It is convenient to use the script closeby.mq4 in manual trading, especially in cases of many differently-directed market orders available in the symbol window.