保持敬畏之心
交易是一场持久战

​MQL4(16):OrderClose() - 平仓函数详解

平仓操作

市价单:平仓操作是基于当前的市价来结束一个已开立的交易头寸。具体规则是:平掉买单使用当前的买价 (Bid),平掉卖单使用当前的卖价 (Ask)。

挂单:对于尚未被市场价格触发的挂单,结束它的操作不是“平仓”,而是删除 (Delete) 或取消。(删除挂单的函数 OrderDelete() )。

OrderClose() 函数

此函数用于向交易服务器发送平掉一个已成交的市价单(或已被触发的挂单)的请求。

语法:

bool OrderClose(
   int    ticket,       // 要平仓的市价单的订单号
   double lots,         // 要平掉的手数 (可以小于等于订单手数,用于部分平仓)
   double price,        // 提供一个当前的市价作为参考 (买单平仓用 Bid, 卖单平仓用 Ask)
   int    slippage,     // 允许成交价与参考价的最大滑点 (单位: points)
   color  arrow_color=clrNONE // 在图表标记平仓位置的箭头颜色 (可选)
);
  • ticket: 目标市价单的订单号。
  • lots: 要平掉的手数。若小于订单当前手数,则为部分平仓(需经纪商支持)。
  • price: 提供平仓时的参考市价(平买单提供 Bid,平卖单提供 Ask)。
  • slippage: 允许最终成交价与您提供的price之间存在多少points的差异。。
  • arrow_color: 可选,标记平仓位置的箭头颜色。

返回值 (bool 类型):

  • true: 表示平仓指令已成功发送到服务器。这不保证订单已立即成交,可能因网络延迟或服务器处理需要时间。需要后续检查订单状态确认是否真正平仓。
  • false: 表示平仓指令未能成功发送(例如,参数错误、无网络连接等)。调用 GetLastError() 获取原因。

关于部分平仓:

虽然 OrderClose() 支持,但一般不推荐在EA中进行部分平仓,因为它会显著增加订单跟踪和管理的复杂度。如果策略需要分批离场,通常更简单可靠的做法是最初就将总头寸拆分成多个独立的订单。本书示例将始终完全平掉整个订单。

平仓示例 (平掉一个买单):

int ticketToClose = ...;  // 假设这是要平仓的买单订单号
int slippagePoints = ...; // 假设这是计算好的滑点 points 值 (e.g., GetSlippage() 的结果)

// 1. 选中订单
if (OrderSelect(ticketToClose, SELECT_BY_TICKET))
{
    // 2. 确认是未平仓的买单 (OrderCloseTime()==0 且 OrderType()==OP_BUY)
    if (OrderCloseTime() == 0 && OrderType() == OP_BUY)
    {
        // 3. 准备平仓参数
        double lotsToClose = OrderLots(); // 平掉全部手数
        double closePrice = Bid;         // 买单平仓用当前 Bid 价
        RefreshRates(); // (可选但推荐) 确保使用的是最新的报价

        // 4. 发送平仓指令
        bool result = OrderClose(ticketToClose, lotsToClose, closePrice, slippagePoints, Red); // 红色箭头标记

        // 5. 处理发送结果
        if (result)
        {
            Print("成功发送平仓指令给买单 #", ticketToClose);
            // 注意:这里只是指令发送成功,不代表已成交。
            // 实际应用中可能需要等待一段时间或在下一 Tick 检查 OrderSelect 是否还可选用来确认。
        }
        else
        {
            Print("发送平仓指令失败 for #", ticketToClose, " Error: ", GetLastError());
        }
    }
    else
    {
        Print("订单 #", ticketToClose, " 不是一个未平仓的买单。");
    }
}
else
{
    Print("无法选中订单 #", ticketToClose, ",错误代码: ", GetLastError());
}

平掉卖单: 逻辑完全一致,只需:

  • 检查 OrderType() == OP_SELL
  • 使用 Ask 作为 closePrice
// 假设 ticketToClose 是卖单订单号, slippagePoints 已计算
if (OrderSelect(ticketToClose, SELECT_BY_TICKET))
{
    if (OrderCloseTime() == 0 && OrderType() == OP_SELL)
    {
        double lotsToClose = OrderLots();
        double closePrice = Ask; // 卖单平仓用 Ask 价
        RefreshRates();
        bool result = OrderClose(ticketToClose, lotsToClose, closePrice, slippagePoints, Red);
        if (!result) Print("发送平仓指令失败 for #", ticketToClose, " Error: ", GetLastError());
        else Print("成功发送平仓指令给卖单 #", ticketToClose);
    }
}

OrderDelete() 函数 (用于删除挂单) 对于尚未被触发的挂单 (Pending Orders),我们不使用 OrderClose() 来“平仓”,而是使用 OrderDelete() 函数将其从交易服务器上删除取消。与 OrderClose() 不同,删除挂单不需要提供价格、手数或滑点信息。 语法:

bool OrderDelete(int ticket, color arrow_color=clrNONE);
  • ticket (整数): 要删除的挂单的订单号。
  • arrow_color (颜色, 可选): 在图表上标记删除位置的箭头颜色。如果省略或设为 clrNONE,则不绘制箭头。

返回值 (bool 类型):

  • true: 表示删除指令已成功发送到服务器。
  • false: 表示删除指令发送失败。调用 GetLastError() 获取原因。

删除挂单示例 (删除一个买入止损挂单):

int ticketToDelete = ...; // 假设这是要删除的挂单订单号

// 1. 选中订单
if (OrderSelect(ticketToDelete, SELECT_BY_TICKET))
{
    // 2. 确认是未成交的挂单 (OrderCloseTime()==0 且 OrderType是挂单类型之一)
    int type = OrderType();
    if (OrderCloseTime() == 0 && (type == OP_BUYSTOP || type == OP_SELLSTOP || type == OP_BUYLIMIT || type == OP_SELLLIMIT))
    {
        // 3. 发送删除指令
        bool result = OrderDelete(ticketToDelete, Red); // 红色箭头标记

        // 4. 处理发送结果
        if (result)
        {
            Print("成功发送删除指令给挂单 #", ticketToDelete);
        }
        else
        {
            Print("发送删除指令失败 for #", ticketToDelete, " Error: ", GetLastError());
        }
    }
    else
    {
        Print("订单 #", ticketToDelete, " 不是一个可以删除的挂单 (可能已被触发或已取消).");
    }
}
else
{
    Print("无法选中订单 #", ticketToDelete, ", 错误代码: ", GetLastError());
}

与平仓操作类似,删除挂单前也需要先用 OrderSelect() 选中订单,并通过 OrderType()OrderCloseTime() 确认其状态确实是未成交的挂单 (类型为 OP_BUYSTOP, OP_SELLSTOP, OP_BUYLIMITOP_SELLLIMIT 之一)。

提示: 如果一个挂单的价格条件被市场触及并已成功执行,那么它就不再是挂单了,而是转变成了一个已开仓的市价单。在这种情况下,您必须使用 OrderClose() 函数来将其平仓,而不能再用 OrderDelete()

赞(0)
未经允许不得转载:图道交易 » ​MQL4(16):OrderClose() - 平仓函数详解