封装平仓函数
最后,我们将订单平仓的逻辑也封装成一个可重用的函数。这个函数将专注于关闭单个指定的市价订单。当您需要精确地关闭某一个特定的订单时(例如,基于订单号)这时下面这个函数就很有用,同时加入了必要的检查和错误处理。
关闭指定买单 (CloseBuyOrder
)
/**
* @brief 关闭一个指定的市价买单 (Buy Market Order)。
* @param argSymbol 订单的交易品种名称 (用于获取当前价格)
* @param argCloseTicket 要关闭的买单的订单号 (Ticket)
* @param argSlippagePoints 允许的滑点 (单位: points)
* @return bool true: 平仓指令成功发送; false: 操作失败或订单无需/无法关闭
*/
bool CloseBuyOrder(string argSymbol, int argCloseTicket, int argSlippagePoints)
{
bool closedSuccess = false; // 初始化函数返回值,默认为失败
// 1. 尝试选中指定的订单
if (OrderSelect(argCloseTicket, SELECT_BY_TICKET))
{
// 2. 确认订单是【未平仓】的【市价买单】
if (OrderCloseTime() == 0 && OrderType() == OP_BUY)
{
// 3. 等待交易环境空闲 (假设 WaitForTradeContext 是封装好的函数)
if (!WaitForTradeContext()) {
Print("等待交易环境超时,无法关闭订单 #", argCloseTicket);
return(false); // 等待失败,直接返回 false
}
// 4. 准备平仓所需参数
double lotsToClose = OrderLots(); // 获取订单的全部手数进行平仓
RefreshRates(); // 获取最新的市场报价
// !!! 关键修正:平掉买单必须使用当前的【买价 Bid】 !!!
double closePrice = MarketInfo(argSymbol, MODE_BID); // 使用 MarketInfo 获取指定品种的 Bid 价
// 5. 发送平仓指令
closedSuccess = OrderClose(argCloseTicket, lotsToClose, closePrice, argSlippagePoints, Red); // 使用红色箭头标记
// 6. 处理平仓指令的发送结果
if (!closedSuccess)
{
// 调用统一的错误处理函数记录错误详情
HandleTradeError(StringFormat("关闭买单 #%d", argCloseTicket), GetLastError());
/*
// 或者直接在此处理:
int errorCode = GetLastError();
string errorDesc = ErrorDescription(errorCode); // 需要 #include <stdlib.mqh>
Alert("关闭买单失败: Error ", errorCode, ": ", errorDesc);
Print("OrderClose(Buy) failed for #", argCloseTicket, ". Error: ", errorCode, " ", errorDesc,
". Bid=", closePrice); // 记录使用的 Bid 价
*/
}
else
{
Print("成功发送平仓指令 for 买单 #", argCloseTicket);
// 注意:这里仅表示指令发送成功,不代表已最终成交。
}
}
// else Print("订单 #", argCloseTicket, " 不是一个未平仓的买单."); // 可选的调试信息
}
// else Print("无法选中订单 #", argCloseTicket, ", Error: ", GetLastError()); // 可选的调试信息
// 返回平仓指令是否成功发送
return(closedSuccess);
}
-
函数逻辑:
- 函数接收品种名称
argSymbol
、要关闭的订单号argCloseTicket
和滑点argSlippagePoints
(points 单位) 作为参数。 - 首先调用
OrderSelect()
选中订单。 - 然后检查
OrderCloseTime() == 0
确认订单未关闭,并检查OrderType() == OP_BUY
确认是买单。 - 关键修正: 在获取平仓价格时,必须使用当前的
Bid
价(通过MarketInfo(argSymbol, MODE_BID)
获取)来平掉买单。 - 调用
OrderClose()
发送平仓指令。 - 对
OrderClose()
的返回值进行判断,如果发送失败 (false
),则执行错误处理逻辑(建议调用封装的HandleTradeError
函数),记录错误信息,并返回false
。 - 如果指令发送成功 (
true
),则函数返回true
。 - 如果订单一开始就无法选中,或者不是未平仓的买单,函数也会返回初始化的
false
值。
- 函数接收品种名称
-
关闭卖单 (
CloseSellOrder
): 关闭卖单的函数 (CloseSellOrder
) 逻辑与CloseBuyOrder
完全相同,唯一的区别在于:- 需要检查订单类型为
OrderType() == OP_SELL
。 - 在获取平仓价格时必须使用当前的 Ask 价 (
MarketInfo(argSymbol, MODE_ASK)
)。
- 需要检查订单类型为
通过将这些常用的交易操作封装成函数,可以极大地提高代码的复用性和整洁度,使得主程序能更专注于交易策略的核心逻辑。
关闭挂单函数 (ClosePendingOrder
)
除了关闭市价单,我们也需要函数来处理挂单的取消。由于挂单是删除而非平仓,且不涉及价格和滑点,其函数相对简单。这个函数设计为可以关闭(删除)任何类型的未成交挂单(买/卖,止损/限价)。
/**
* @brief 关闭 (删除) 一个指定的、尚未成交的挂单。
* @param argSymbol 订单的交易品种名称 (主要用于错误日志记录当前价格)
* @param argCloseTicket 要删除的挂单的订单号 (Ticket)
* @return bool true: 删除指令成功发送; false: 操作失败或订单无需/无法删除
*/
bool ClosePendingOrder(string argSymbol, int argCloseTicket)
{
bool deletedSuccess = false; // 初始化返回值
// 1. 尝试选中指定的订单
if (OrderSelect(argCloseTicket, SELECT_BY_TICKET))
{
// 2. 确认订单是【未成交】的【挂单】
int orderType = OrderType();
if (OrderCloseTime() == 0 && (orderType >= OP_BUYSTOP && orderType <= OP_SELLLIMIT))
{
// 3. 等待交易环境
(假设 WaitForTradeContext 是封装好的函数) if (!WaitForTradeContext()) return(false); // 4. 发送删除指令 deletedSuccess = OrderDelete(argCloseTicket, Red); // 红色箭头标记 // 5. 处理删除指令的发送结果 if (!deletedSuccess) { // 调用统一的错误处理函数 (假设 HandleTradeError 已定义) HandleTradeError(StringFormat("删除挂单 #%d", argCloseTicket), GetLastError()); /* // 或者直接处理: int errorCode = GetLastError(); string errorDesc = ErrorDescription(errorCode); // 需要 #include <stdlib.mqh> Alert("删除挂单失败: Error ", errorCode, ": ", errorDesc); RefreshRates(); Print("OrderDelete failed for #", argCloseTicket, ". Error: ", errorCode, " ", errorDesc, ". Bid=", MarketInfo(argSymbol, MODE_BID), " Ask=", MarketInfo(argSymbol, MODE_ASK)); */ } else { Print("成功发送删除指令 for 挂单 #", argCloseTicket); } } // else { Print("订单 #", argCloseTicket, " 不是未成交挂单."); } // 可选调试 } // else { Print("无法选中订单 #", argCloseTicket, ", Error: ", GetLastError()); } // 可选调试 // 返回删除指令是否成功发送 return(deletedSuccess); }
- 参数: 函数接收品种名称
argSymbol
(主要用于错误日志)和要删除的挂单号argCloseTicket
。注意,它不需要滑点参数。(译者注:原文此处函数签名误包含argSlippage
,已在翻译中移除)。 - 逻辑:
- 选中订单。
- 检查
OrderCloseTime() == 0
且OrderType()
是挂单类型之一。 - 等待
交易环境
。 - 调用
OrderDelete()
发送删除指令。 - 进行错误处理。
- 返回
OrderDelete()
的执行结果 (true
或false
)。
最近几章会把封装函数的教学放在一起,最后再以早先的简单EA为基础,把这些自定义函数运用到EA当中,一个完善的EA需要不断的添砖加瓦才能稳定的运行。