删除挂单

使用 TRADE_ACTION_REMOVE 操作在程序水平执行挂单删除:应将该常量分配给 action 字段(属于 MqlTradeRequest 结构体,且需要在调用 OrderSend 函数的一个版本之前进行。除了 action 之外,唯一的必填字段是 order,用于指定要删除的订单号。

MqlTradeSync.mqh 文件中 MqlTradeRequestSync 应用程序结构体中的 remove 方法非常简单。

struct MqlTradeRequestSyncpublic MqlTradeRequest
{
   ...
   bool remove(const ulong ticket)
   {
      if(!OrderSelect(ticket)) return false;
      action = TRADE_ACTION_REMOVE;
      order = ticket;
      ZeroMemory(result);
      return OrderSend(thisresult);
   }

订单删除的事实验证通常是在 completed 方法中完成的。

   bool completed()
   {
      ...
      else if(action == TRADE_ACTION_REMOVE)
      {
         result.order = order;
         return result.removed(timeout);
      }
      ...
   }

等待订单的实际移除是在 MqlTradeResultSync 结构体的 removed 方法中执行的。

struct MqlTradeResultSyncpublic MqlTradeResult
{
   ...
   bool removed(const ulong msc = 1000)
   {
      if(retcode != TRADE_RETCODE_DONE)
      {
         return false;
      }
   
      if(!wait(orderRemovedmsc))
      {
         Print("Order removal timeout: #=" + (string)order);
         return false;
      }
      
      return true;
   }
   
   static bool orderRemoved(MqlTradeResultSync &ref)
   {
      return !OrderSelect(ref.order) && HistoryOrderSelect(ref.order);
   }

EA 交易 (PendingOrderDelete.mq5) 的一个示例演示了我们将几乎完全基于 PendingOrderSend.mq5 构建的订单移除。这是因为在删除之前更便于保证订单存在。因此,在启动后,EA 交易将立即使用指定的参数创建新订单。随后将在 OnDeinit 处理程序中删除订单。如果你更改 EA 交易的输入参数、交易品种或图表时间范围,旧订单也将被删除,并将创建一个新订单。

添加了 OwnOrder 全局变量,用于存储订单号。该变量是在调用 PlaceOrder 后生成的(函数本身不变)。

ulong OwnOrder = 0;
   
void OnTimer()
{
   // execute the code once for the current parameters
   EventKillTimer();
   
   const string symbol = StringLen(Symbol) == 0 ? _Symbol : Symbol;
   OwnOrder = PlaceOrder((ENUM_ORDER_TYPE)TypesymbolVolume,
      Distance2SLTPExpirationUntilMagicComment);
}

以下是一个简单的删除函数 RemoveOrder,其会创建 request 对象并依次调用 removecompleted 方法。

void OnDeinit(const int)
{
   if(OwnOrder != 0)
   {
      RemoveOrder(OwnOrder);
   }
}
   
void RemoveOrder(const ulong ticket)
{
   MqlTradeRequestSync request;
   if(request.remove(ticket) && request.completed())
   {
      Print("OK order removed");
   }
   Print(TU::StringOf(request));
   Print(TU::StringOf(request.result));
}

以下日志显示了将 EA 交易放置在 EURUSD 图表上的结果,在此之后,交易品种被切换为 XAUUSD,然后 EA 交易被删除。

(EURUSD,H1)        Autodetected daily range: 0.0094

(EURUSD,H1)        OK order placed: #=1284920879

(EURUSD,H1)        TRADE_ACTION_PENDING, EURUSD, ORDER_TYPE_BUY_STOP, V=0.01, ORDER_FILLING_FOK, »

» @ 1.11011, ORDER_TIME_GTC, M=1234567890

(EURUSD,H1)        DONE, #=1284920879, V=0.01, Request executed, Req=1

(EURUSD,H1)        OK order removed

(EURUSD,H1)        TRADE_ACTION_REMOVE, EURUSD, ORDER_TYPE_BUY, ORDER_FILLING_FOK, #=1284920879

(EURUSD,H1)        DONE, #=1284920879, Request executed, Req=2

(XAUUSD,H1)        Autodetected daily range: 47.45

(XAUUSD,H1)        OK order placed: #=1284921672

(XAUUSD,H1)        TRADE_ACTION_PENDING, XAUUSD, ORDER_TYPE_BUY_STOP, V=0.01, ORDER_FILLING_FOK, »

» @ 1956.68, ORDER_TIME_GTC, M=1234567890

(XAUUSD,H1)        DONE, #=1284921672, V=0.01, Request executed, Req=3

(XAUUSD,H1)        OK order removed

(XAUUSD,H1)        TRADE_ACTION_REMOVE, XAUUSD, ORDER_TYPE_BUY, ORDER_FILLING_FOK, #=1284921672

(XAUUSD,H1)        DONE, #=1284921672, Request executed, Req=4

我们将在 OnTrade 事件一节中了解另一个删除订单以实现“互损订单”(OCO)策略的示例。