Loops and Closing or Deleting Orders

 

This is one of the most common errors I see, probably due in part to the likes of garbage such as Expert Advisor Builder. So I thought it was time for a thread dedicated to the subject so that it can be linked to for future reference.

The Problem

Let's take a simple example; we want a function to close all open orders for our EA, there are plenty of examples but let's create one from scratch.

We need a loop because we want to close all our orders for a specific EA, within this loop we will have code to select the order, code to check it is the correct symbol and magic number and finally code to close the order:

int PositionIndex;    //  <-- this variable is the index used for the loop

int TotalNumberOfOrders;   //  <-- this variable will hold the number of orders currently in the Trade pool

TotalNumberOfOrders = OrdersTotal();    // <-- we store the number of Orders in the variable

for(PositionIndex = 0; PositionIndex < TotalNumberOfOrders; PositionIndex++)  //  <-- for loop to loop through all Orders
   {
   if( ! OrderSelect(PositionIndex, SELECT_BY_POS, MODE_TRADES) ) continue;   // <-- if the OrderSelect fails advance the loop to the next PositionIndex
   
   if( OrderMagicNumber() == MagicNo       // <-- does the Order's Magic Number match our EA's magic number ? 
      && OrderSymbol() == Symbol()         // <-- does the Order's Symbol match the Symbol our EA is working on ? 
      && ( OrderType() == OP_BUY           // <-- is the Order a Buy Order ? 
      ||   OrderType() == OP_SELL ) )      // <-- or is it a Sell Order ?

      if ( ! OrderClose( OrderTicket(), OrderLots(), OrderClosePrice(), Slippage ) )               // <-- try to close the order
         Print("Order Close failed, order number: ", OrderTicket(), " Error: ", GetLastError() );  // <-- if the Order Close failed print some helpful information 
      
   } //  end of For loop

This code is bad . . . DO NOT USE IT . . . I will explain why in the next section . . .

The Explanation

Let's work through the code above . . . line by line, Order by Order . . .

Let's assume we have the following Orders that we want to close, they all have the same magic number and Symbol as our EA so we want our code to close them all:

Position Ticket Number
0111
1222
2 333
3444
4555

1st run through the loop:

the initial value of PositionIndex is 0 so the order at position 0 is selected, ticket number 111, this order is successfully deleted and the remaining Orders change position as follows:

Position Ticket Number
0222
1 333
2444
3555

2nd run through the loop:

now the value of PositionIndex is 1 so the order at position 1 is selected, ticket number 333, this order is successfully deleted and the remaining Orders change position as follows:

Position Ticket Number
0222
1 444
2555

3rd run through the loop:

now the value of PositionIndex is 2 so the order at position 2 is selected, ticket number 555, this order is successfully deleted and the remaining Orders change position as follows:

Position Ticket Number
0222
1 444

4th run through the loop:

now the value of PositionIndex is 3 OrderSelect() tries to select the Order at position 3 and fails, the continue takes execution of the code to the next value in the loop . .


5th and last run through the loop:

now the value of PositionIndex is 4 OrderSelect() tries to select the Order at position 4 and fails, the continue takes execution of the code to the next value in the loop . . . the loop has finished.


We are now left with 2 Orders, tickets 222 and 444 which should have been closed but were not . . . next, how to resolve this issue.

The Solution

The following code is the correct approach when closing open orders or deleting pending orders . . .

The key difference is that the loop decrements from ( TotalNumberOfOrders - 1 ) to 0

int PositionIndex;    //  <-- this variable is the index used for the loop

int TotalNumberOfOrders;   //  <-- this variable will hold the number of orders currently in the Trade pool

TotalNumberOfOrders = OrdersTotal();    // <-- we store the number of Orders in the variable

for(PositionIndex = TotalNumberOfOrders - 1; PositionIndex >= 0 ; PositionIndex --)  //  <-- for loop to loop through all Orders . .   COUNT DOWN TO ZERO !
   {
   if( ! OrderSelect(PositionIndex, SELECT_BY_POS, MODE_TRADES) ) continue;   // <-- if the OrderSelect fails advance the loop to the next PositionIndex
   
   if( OrderMagicNumber() == MagicNo       // <-- does the Order's Magic Number match our EA's magic number ? 
      && OrderSymbol() == Symbol()         // <-- does the Order's Symbol match the Symbol our EA is working on ? 
      && ( OrderType() == OP_BUY           // <-- is the Order a Buy Order ? 
      ||   OrderType() == OP_SELL ) )      // <-- or is it a Sell Order ?
   
      if ( ! OrderClose( OrderTicket(), OrderLots(), OrderClosePrice(), Slippage ) )               // <-- try to close the order
         Print("Order Close failed, order number: ", OrderTicket(), " Error: ", GetLastError() );  // <-- if the Order Close failed print some helpful information 
      
   } //  end of For loop

Once again let's work through the code above . . . line by line, Order by Order . . .

We have the same orders as before:

Position Ticket Number
0111
1222
2333
3444
4555

1st run through the loop:

the initial value of PositionIndex is TotalNumberOfOrders - 1 which is equal to 5 - 1 = 4, so the order at position 4 is selected, ticket number 555, this order is successfully deleted and the remaining Orders change position as follows:

Position Ticket Number
0111
1222
2333
3444

2nd run through the loop:

now the value of PositionIndex is 3 so the order at position 3 is selected, ticket number 444, this order is successfully deleted and the remaining Orders change position as follows:

Position Ticket Number
0111
1222
2333

3rd run through the loop:

now the value of PositionIndex is 2 so the order at position 2 is selected, ticket number 333, this order is successfully deleted and the remaining Orders change position as follows:

Position Ticket Number
0111
1222

4th run through the loop:

now the value of PositionIndex is 1 so the order at position 1 is selected, ticket number 222, this order is successfully deleted and the remaining Orders change position as follows:

Position Ticket Number
0111

5th and last run through the loop:

now the value of PositionIndex is 0 so the order at position 0 is selected, ticket number 111, this order is successfully deleted, value 0 is the last valid value for the loop . . . the loop has finished.

We have successfully deleted all our matching orders . . .

Link to this thread: Loops and Closing or Deleting Orders

 

Lets take a more complex example . . .

Lets assume we have the following Orders that we want to close, they all have the same magic number but some have a different Symbol as our EA, we want our code to close the orders for the same symbol as our EA, EURUSD:

Position Ticket Number Symbol
0111 EURUSD
1222 EURUSD
2333GBPUSD
3444 EURUSD
4555 EURUSD


1st run through the loop:

the initial value of PositionIndex is TotalNumberOfOrders - 1 which is equal to 5 - 1 = 4, so the order at position 4 is selected, ticket number 555, this order matches magic number and Symbol so is successfully deleted and the remaining Orders change position as follows:

Position Ticket Number Symbol
0111EURUSD
1222EURUSD
2333GBPUSD
3444EURUSD

2nd run through the loop:

now the value of PositionIndex is 3 so the order at position 3 is selected, ticket number 444, this order matches magic number and Symbol so is successfully deleted and the remaining Orders change position as follows:

Position Ticket Number Symbol
0111EURUSD
1222EURUSD
2333GBPUSD


3rd run through the loop:

now the value of PositionIndex is 2 so the order at position 2 is selected, ticket number 333, this order matches magic number but NOT Symbol so it is not deleted, the remaining Orders do not change:

Position Ticket Number Symbol
0111EURUSD
1222EURUSD
2333GBPUSD

4th run through the loop:

now the value of PositionIndex is 1 so the order at position 1 is selected, ticket number 222, this order matches magic number and Symbol so is successfully deleted and the remaining Orders change position as follows:

Position Ticket Number Symbol
0111EURUSD
1333GBPUSD

5th and last run through the loop:

now the value of PositionIndex is 0 so the order at position 0 is selected, ticket number 111, this order is successfully deleted, value 0 is the last valid value for the loop . . . the loop has finished.

We have successfully deleted all our matching orders leaving the one order that did not match our symbol, ticket number 333 now at position 0 . . .

Position Ticket Number Symbol
0333GBPUSD


Link to this thread: Loops and Closing or Deleting Orders

 

Thank you Raptor for this important explanation.

Y.

 
This is extremely helpful to me, King of the garbage expert advisor builder! Oh, how I do enjoy hacking away at the resulting code. Many thanks.
 

Wow. All that information for closing an order.

I wonder how much information it would take to net 50+ pips a day, consistently, everyday (on average) - without fail, through the last 137 trades.

Show me how to do something like that, and I would consider it extremely helpful information and Guru, shall be your title, forever and ever, Amen.

 
CFx:

Wow. All that information for closing an order.

I wonder how much information it would take to net 50+ pips a day, consistently, everyday (on average) - without fail, through the last 137 trades.

I have no interest in pips . . . what can I do with them ? I can't spend them, what is the GBPPIPS rate ? you show your ignorance by counting success in pips . . .
 
CFx:

I wonder how much information it would take to net 50+ pips a day, consistently, everyday (on average) - without fail, through the last 137 trades.

Show me how to do something like that, and I would consider it extremely helpful information and Guru, shall be your title, forever and ever, Amen.

  1. Don't Hijack thread with off topic information
  2. We are NOT going to show you that because you didn't read the rules Any discussions except of concerning MetaQuotes Language 4 and auto trading are forbidden
 

Raptor,i do know at 1st glance of ur post that u r quite n expert in mql4.this thread again helps clear my doubts!keep up the good works.tnx

 

Just another idea:

for(PositionIndex = 0; PositionIndex < OrdersTotal() ; PositionIndex ++)  //  <-- for loop to loop through all Orders . .   COUNT DOWN TO ZERO !
   {
   if( ! OrderSelect(PositionIndex, SELECT_BY_POS, MODE_TRADES) ) continue;   // <-- if the OrderSelect fails advance the loop to the next PositionIndex
   
   if( OrderMagicNumber() == MagicNo       // <-- does the Order's Magic Number match our EA's magic number ? 
      && OrderSymbol() == Symbol()         // <-- does the Order's Symbol match the Symbol our EA is working on ? 
      && ( OrderType() == OP_BUY           // <-- is the Order a Buy Order ? 
      ||   OrderType() == OP_SELL ) )      // <-- or is it a Sell Order ?
   
         add_trade_to_close_queue( OrderTicket());  // <--  You need to model the queue mechanism ...
      
   } //  end of For loop


Regards.

 
abstract_mind:


Just another idea:


Regards.

yes, understand the logic behind of MT4, it is up to you to code increase or decrease counter.
Reason: