//+------------------------------------------------------------------+
//|                                                OrderCanceler.mqh |
//+------------------------------------------------------------------+
#ifndef ORDERCANCELER_MQH
#define ORDERCANCELER_MQH

//+------------------------------------------------------------------+
//| COrderCanceler                                                   |
//| Cancels every pending order using OrderSend() with               |
//| TRADE_ACTION_REMOVE. Iteration runs backward through the order   |
//| list, mirroring CPositionCloser, so that deleting one order never| 
//| disturbs the index of an order still waiting to be processed.    |
//+------------------------------------------------------------------+
class COrderCanceler
  {
private:
   bool              CancelSingleOrder(const ulong ticket);

public:
                     COrderCanceler(void);
                    ~COrderCanceler(void);

   void              CancelAll(int &canceled_count, int &failed_count);
  };

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
COrderCanceler::COrderCanceler(void)
  {
  }

//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
COrderCanceler::~COrderCanceler(void)
  {
  }

//+------------------------------------------------------------------+
//| CancelSingleOrder                                                |
//| Cancels a single pending order by ticket, logging the ticket and |
//| order type on success, or the failure reason on rejection.       |
//| MQL5 has no standalone OrderDelete() function (that is an MQL4   |
//| API); a pending order is canceled the same way every other       |
//| trade action here is performed, through OrderSend() with a       |
//| TRADE_ACTION_REMOVE request.                                     |
//+------------------------------------------------------------------+
bool COrderCanceler::CancelSingleOrder(const ulong ticket)
  {
//--- OrderSelect() must succeed before OrderGetInteger() can read order properties.
   if(!::OrderSelect(ticket))
      return(false);

   long order_type = ::OrderGetInteger(ORDER_TYPE);

   MqlTradeRequest request;
   MqlTradeResult  result;
   ::ZeroMemory(request);
   ::ZeroMemory(result);

//--- TRADE_ACTION_REMOVE cancels a pending order by ticket; no price,
//--- volume, or symbol fields are needed for this action type
   request.action = TRADE_ACTION_REMOVE;
   request.order  = ticket;

   bool send_ok = ::OrderSend(request, result);

   if(send_ok && (result.retcode == TRADE_RETCODE_DONE || result.retcode == TRADE_RETCODE_PLACED))
     {
      ::PrintFormat("COrderCanceler: canceled ticket=%I64u type=%d", ticket, order_type);
      return(true);
     }

   ::PrintFormat("COrderCanceler: failed to cancel ticket=%I64u type=%d retcode=%d comment=%s",
                 ticket, order_type, result.retcode, result.comment);
   return(false);
  }

//+------------------------------------------------------------------+
//| CancelAll                                                        |
//| Cancels every pending order, iterating backward through the      |
//| order list for the same reason CPositionCloser iterates          |
//| backward through the position list.                              |
//+------------------------------------------------------------------+
void COrderCanceler::CancelAll(int &canceled_count, int &failed_count)
  {
   canceled_count = 0;
   failed_count   = 0;

//--- Backward loop: OrdersTotal() shrinks by one after every cancel
   for(int i = ::OrdersTotal() - 1; i >= 0; i--)
     {
      ulong ticket = ::OrderGetTicket(i);
      if(ticket == 0)
         continue;

      if(CancelSingleOrder(ticket))
         canceled_count++;
      else
         failed_count++;
     }
  }

#endif // ORDERCANCELER_MQH
//+------------------------------------------------------------------+