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

​MQL4(19):验证止损、止盈和挂单价格

在计算出目标止损价和止盈价之后,我们必须验证它们是否满足经纪商的最小距离要求(即 MODE_STOPLEVEL 对应的价格距离)。需要注意的是,对市价单和挂单的止损验证,其考虑因素略有不同。

  • 止盈验证规则:

    • 买单止盈价必须 >= Ask + StopLevel * Point (UpperStopLevel)。
    • 卖单止盈价必须 <= Bid - StopLevel * Point (LowerStopLevel)。
    • 简单来说,止盈价格只需要考虑距离开仓价(或挂单价)满足 StopLevel 即可。例如,若 StopLevel 为 3 pips (对应价格距离 0.0003),开仓价 1.4500,则买单 TP 必须 >= 1.4503。
  • 止损验证规则:

    • 市价单: 验证市价单的止损时,不仅要考虑 StopLevel,还必须额外考虑当前的点差。这是因为止损触发依赖的是对向价格(买单止损在 Bid 触发,卖单止损在 Ask 触发)。因此,实际要求的距离是 StopLevel 加上点差。
      • 买单止损价必须 <= Bid - StopLevel * Point (LowerStopLevel)。注意是基于 Bid 计算下边界。
      • 卖单止损价必须 >= Ask + StopLevel * Point (UpperStopLevel)。注意是基于 Ask 计算上边界。
      • 示例:若 StopLevel = 3 pips,点差 = 2 pips,买单开仓价 1.4500 (Ask)。假设此时 Bid = 1.4498。StopLevel 价格距离为 0.0003。则买单止损价必须 <= Bid - StopLevel 价格距离 = 1.4498 – 0.0003 = 1.4495。这相当于要求止损距离开仓价至少 (3 pips + 2 pips) = 5 pips。
    • 挂单: 验证挂单的止损时,无需考虑当前点差。只需确保止损价相对于挂单价格满足 StopLevel 的距离要求。
      • 买挂单止损价 <= 挂单价 - StopLevel * Point
      • 卖挂单止损价 >= 挂单价 + StopLevel * Point
      • 示例:若挂单设在 1.4500,StopLevel = 3 pips (价格距离 0.0003)。买挂单的止损价只需 <= 1.4497 即可。

处理无效价格一:

如果计算出的 SL/TP 价格不满足最小距离要求,一种常见的处理方式是自动将其调整到刚好满足要求的边界之外,并附加一个小的缓冲距离,以增加设置成功的概率并避免过于贴近边界。

// --- 价格验证与自动调整示例 ---
// (假设 UpperStopLevelBoundary 和 LowerStopLevelBoundary 已根据当前市价和 StopLevel 计算好)
// (假设 buyStopLossPrice 和 buyTakeProfitPrice 是初步计算的目标价格)
// (假设 g_onePipValue 是 1 pip 的价格值)

double minBufferPips = 5.0; // 设置一个 5 pips 的缓冲
double priceBuffer = minBufferPips * g_onePipValue; // 计算缓冲的价格距离

// 验证和调整买单止损 (必须 <= 下边界)
if (buyStopLossPrice > lowerStopLevelBoundary) // 如果初步计算的止损价太高 (太靠近市价)
{
    Print("买单止损价 ", buyStopLossPrice, " 无效 (高于允许的最高止损价 ", lowerStopLevelBoundary, "), 自动调整...");
    buyStopLossPrice = NormalizeDouble(lowerStopLevelBoundary - priceBuffer, Digits); // 调整到下边界再减去缓冲
    Print("调整后买单止损价: ", buyStopLossPrice);
}

// 验证和调整买单止盈 (必须 >= 上边界)
if (buyTakeProfitPrice < upperStopLevelBoundary) // 如果初步计算的止盈价太低 (太靠近市价)
{
    Print("买单止盈价 ", buyTakeProfitPrice, " 无效 (低于允许的最低止盈价 ", upperStopLevelBoundary, "), 自动调整...");
    buyTakeProfitPrice = NormalizeDouble(upperStopLevelBoundary + priceBuffer, Digits); // 调整到上边界再加上缓冲
    Print("调整后买单止盈价: ", buyTakeProfitPrice);
}

// --- 验证和调整卖单 SL/TP (逻辑类似,注意比较方向和边界) ---
// (假设 sellStopLossPrice 和 sellTakeProfitPrice 是初步计算的目标价格)

// 验证和调整卖单止盈 (必须 <= 下边界)
if (sellTakeProfitPrice > lowerStopLevelBoundary)
{
    Print("卖单止盈价 ", sellTakeProfitPrice, " 无效 (高于允许的最高止盈价 ", lowerStopLevelBoundary, "), 自动调整...");
    sellTakeProfitPrice = NormalizeDouble(lowerStopLevelBoundary - priceBuffer, Digits);
    Print("调整后卖单止盈价: ", sellTakeProfitPrice);
}

// 验证和调整卖单止损 (必须 >= 上边界)
if (sellStopLossPrice < upperStopLevelBoundary)
{
    Print("卖单止损价 ", sellStopLossPrice, " 无效 (低于允许的最低止损价 ", upperStopLevelBoundary, "), 自动调整...");
    sellStopLossPrice = NormalizeDouble(upperStopLevelBoundary + priceBuffer, Digits);
    Print("调整后卖单止损价: ", sellStopLossPrice);
}

// --- 使用调整后的价格进行下单或修改 ---
  • priceBuffer: 计算出一个 N pips 的价格缓冲量。
  • 代码通过比较初步计算出的 SL/TP 是否越过了相应的有效边界 (lowerStopLevelBoundaryupperStopLevelBoundary) 来判断其是否有效。
  • 如果价格无效,则将其自动调整为刚好落在有效边界之外,并额外加上/减去一个 priceBuffer 距离。
  • 使用 NormalizeDouble 确保调整后的价格符合交易品种的价格精度。

处理无效价格二:

另一种处理无效价格的策略是,当检测到问题时不进行自动调整,而是:

  1. 使用 Alert() 函数弹出一个警告窗口,告知用户哪个价格设置无效。
  2. 使用 return(0); 语句立即终止当前 start() 函数的执行。 这样可以阻止后续的下单或修改操作,强制用户必须返回去检查并修正 EA 的输入参数(例如,增大止损点数 StopLoss 的设置)。
// 示例:验证买单止损,若无效则警告并退出
if (buyStopLossPrice > lowerStopLevelBoundary)
{
    string alertMsg = StringFormat("错误:买单止损 %.5f 无效! 价格必须小于或等于 %.5f (距离当前价过近)。\n请检查并调整 'StopLoss' 输入参数。",
                                   buyStopLossPrice, lowerStopLevelBoundary);
    Alert(alertMsg); // 弹出警告框
    return(0);       // 退出 start() 函数,本轮 tick 不再执行任何操作
}
// ... 对其他价格进行类似检查 ...

示例代码更倾向于采用自动调整无效价格的方式,因为通常认为“发送一个经过修正的订单比完全不发送订单要好”。不过,为了便于调试和了解情况,一个好的实践是,在执行自动调整时,使用 Print() 函数将相关信息(例如,原始无效价格、调整后的价格)输出到 EA 的日志(客户端的“EA”标签页)中。

if (buyStopLossPrice > lowerStopLevelBoundary)
{
    double originalSL = buyStopLossPrice; // 保存原始值用于记录
    buyStopLossPrice = NormalizeDouble(lowerStopLevelBoundary - priceBuffer, Digits); // 自动调整
    PrintFormat("警告:买单止损 %.5f 无效 (高于允许的 %.5f), 已自动调整为 %.5f",
                originalSL, lowerStopLevelBoundary, buyStopLossPrice); // 记录到日志
}

验证挂单价格

挂单的触发价格同样需要满足 MODE_STOPLEVEL 的最小距离要求。验证逻辑与验证 SL/TP 类似,需要根据挂单类型判断其应该高于 Ask 还是低于 Bid,并与相应的边界进行比较。

  • 买入止损 (Buy Stop) / 卖出限价 (Sell Limit): 挂单价格必须 >= Ask + StopLevel * Point (upperStopLevelBoundary)。
  • 卖出止损 (Sell Stop) / 买入限价 (Buy Limit): 挂单价格必须 <= Bid - StopLevel * Point (lowerStopLevelBoundary)。

以下是验证并自动调整挂单价格的代码示例(假设 pendingPrice 是计算出的挂单价,orderCmd 是订单类型):

double priceBuffer = ...; // 缓冲距离

// 验证 Buy Stop / Sell Limit 价格 (必须 >= 上边界)
if (orderCmd == OP_BUYSTOP || orderCmd == OP_SELLLIMIT)
{
    if (pendingPrice < upperStopLevelBoundary)
    {
        PrintFormat("挂单价 %.5f 无效 (必须 >= %.5f), 自动调整...", pendingPrice, upperStopLevelBoundary);
        pendingPrice = NormalizeDouble(upperStopLevelBoundary + priceBuffer, Digits); // 调整到上边界之上加缓冲
        Print("调整后挂单价: ", pendingPrice);
    }
}

// 验证 Sell Stop / Buy Limit 价格 (必须 <= 下边界)
else if (orderCmd == OP_SELLSTOP || orderCmd == OP_BUYLIMIT)
{
    if (pendingPrice > lowerStopLevelBoundary) // 检查是否高于下边界 (无效)
    {
        PrintFormat("挂单价 %.5f 无效 (必须 <= %.5f), 自动调整...", pendingPrice, lowerStopLevelBoundary);
        pendingPrice = NormalizeDouble(lowerStopLevelBoundary - priceBuffer, Digits); // 调整到下边界之下减缓冲
        Print("调整后挂单价: ", pendingPrice);
    }
}
// --- 使用调整后的 pendingPrice 进行下单 ---
赞(0)
未经允许不得转载:图道交易 » ​MQL4(19):验证止损、止盈和挂单价格