Monday 28 March 2016

Metatrader Tip: Code for Cancelling All Pending Orders

There's a rather nasty "gotcha" that one has to look out for when working with MetaTrader. It's to do with iterating through a list of orders when you're actually making changes to the order list. Take a look at this code to cancel all pending open orders.

void CancelOpenOrders()
{
   for(int i = 0; i< OrdersTotal(); i++)
   {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES) == false) break;
           
      if ( OrderType() == OP_BUYSTOP || OrderType() == OP_SELLSTOP )
      {
         if (!OrderDelete( OrderTicket() ))
            Print("Delete Open Order failed: ",GetLastError(), 

             " => ",ErrorDescription( GetLastError() ) ); 
      }
   }
}


At first glance there doesn't look to be anything wrong with this code but if you come to use it you'll find that it won't delete all your open orders.  The reason why it doesn't work is rather subtle but as it crops up regularly it's worth getting to recognise it. Think about what happens if there are two open orders so OrdersTotal() returns 2. The first iteration (i = 0) it deletes the first order successfully, and then at the head of the for loop then it increments i  so now i = 1 and does the test to see if i < OrdersTotal(). Since we've now deleted one order, OrdersTotal() now returns 1 as there is only one outstanding order. This means that the i < OrdersTotal() condition now fails and it finishes the loop without deleting the second order.

The correct way to do it is to save the original order total in a variable and to iterate downwards so that you're deleting the last order first. This way you're not affecting the remaining order indices as you delete orders.

void CancelOpenOrders()
{
   int origOT = OrdersTotal();
  
   for(int i= origOT-1; i>=0; i--)
   {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES) == false) break;
           
      if ( OrderType() == OP_BUYSTOP || OrderType() == OP_SELLSTOP )
      {
         if (!OrderDelete( OrderTicket() ))
            Print("Delete Open Order failed: ",GetLastError(), 

          " => ",ErrorDescription( GetLastError() ) ); 
      }
   }
}


As a matter of interest, this same issue crops up in other programming situations where you're deleting or altering things as you iterate through them so it's always worth be aware of when you're doing this.

No comments:

Post a Comment