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

​MQL4(27):处理停止级别 - 封装验证与调整函数

封装验证与调整函数

为了方便地处理前面讨论的停止级别验证问题,我们可以创建两类辅助函数:

  1. 验证函数 (Verification Functions): 这类函数只检查给定的价格(如 SL/TP 或挂单价)是否满足最小停止距离要求,并返回一个布尔值 (truefalse) 表明其有效性,但不修改原始价格。
  2. 调整函数 (Adjustment Functions): 这类函数检查给定的价格,如果发现其不满足最小距离要求(无效),则自动将其调整到一个刚好满足要求的边界之外,并可以选择性地加上一个缓冲距离 (Buffer),然后返回调整后的有效价格。如果原始价格本身就是有效的,则直接返回原始价格。

验证价格是否高于上边界 (VerifyUpperStopLevel)

此函数用于检查一个价格(例如买单止盈、卖单止损、买入止损挂单价、卖出限价挂单价)是否有效地位于上停止级别边界 (Ask + StopLevel*Point) 之上。

/**
 * @brief 验证一个价格是否有效地位亍上停止级别边界之上。
 * 适用于需要设置在 Ask 价上方的价格 (买单TP, 卖单SL, BuyStop挂单价, SellLimit挂单价)。
 * @param argSymbol       交易品种。
 * @param argVerifyPrice  需要验证的目标价格。
 * @param argOpenPrice    计算边界的基准价格 (可选)。
 * 如果为 0 (默认), 则基准为当前 Ask 价 (用于验证市价单SL/TP或挂单价本身)。
 * 如果传入挂单价, 则基准为挂单价 (用于验证该挂单的SL/TP是否距挂单价足够远)。
 * @return bool           true: 价格有效 (argVerifyPrice > UpperStopLevel); false: 价格无效。
 */
bool VerifyUpperStopLevel(string argSymbol, double argVerifyPrice,
                          double argOpenPrice = 0)
{
    // 1. 计算停止级别对应的价格距离
    double stopLevelDist = MarketInfo(argSymbol, MODE_STOPLEVEL) * Point;
    if (stopLevelDist < 0) { // 检查 MarketInfo 返回值
        Print("VerifyUpperStopLevel 错误: 无法获取 MODE_STOPLEVEL for ", argSymbol);
        return false;
    }

    // 2. 确定计算边界的基准价格 (basePrice)
    double basePrice;
    if (argOpenPrice == 0) { // 未指定基准价,使用当前 Ask
        RefreshRates(); // 确保 Ask 最新
        basePrice = MarketInfo(argSymbol, MODE_ASK);
        if (basePrice <= 0) {
             Print("VerifyUpperStopLevel 错误: 无法获取 Ask price for ", argSymbol);
             return false; // 获取 Ask 失败
        }
    } else { // 使用传入的基准价 (例如挂单价)
        basePrice = argOpenPrice;
    }

    // 3. 计算上停止级别边界 (基准价 + 停止距离)
    double upperStopLevelBoundary = NormalizeDouble(basePrice + stopLevelDist, Digits);

    // 4. 比较并返回结果 (目标价格必须严格大于上边界才有效)
    return (argVerifyPrice > upperStopLevelBoundary);
}

参数解释

  • argSymbol: 品种名称。
  • argVerifyPrice: 要检查的目标价格。
  • argOpenPrice (可选): 计算边界所依据的基准价。
    • 默认行为 (argOpenPrice = 0): 函数将使用当前的 Ask 价作为基准来计算上边界。这适用于验证那些需要设置在当前 Ask 价之上的价格,比如市价单的买单止盈/卖单止损,或者挂单本身的价格(Buy Stop 或 Sell Limit)。
    • 指定基准价: 如果传入一个非零值(通常是某个挂单的价格),函数将使用这个传入的价格作为基准来计算上边界。这适用于验证一个挂单所设置的止损/止盈是否距离其自身的挂单价格足够远(例如,验证 Buy Stop 订单的 Take Profit 是否高于 挂单价 + StopLevel*Point)。
  • 返回值: true 表示 argVerifyPrice 合法地处在计算出的上边界之上;false 表示不满足要求(价格等于或低于上边界)。

使用示例: 检查一个计算出的卖单止损价 sellStopLossPrice 是否有效(卖单止损需要高于 Ask + StopLevel):

// 假设 sellStopLossPrice 已计算
if (!VerifyUpperStopLevel(Symbol(), sellStopLossPrice)) // 调用函数验证
{
    Alert("计算出的卖单止损价无效 (距离 Ask 过近)!");
    // ... 后续可能需要停止操作或调整价格 ...
}
  • 下边界验证: 验证价格是否低于下边界 (Bid - StopLevel*Point) 的函数 (VerifyLowerStopLevel) 逻辑相似,主要区别在于使用 Bid 价(或传入的 argOpenPrice)作为基准计算下边界,并且比较时要求目标价格严格小于下边界。

自动调整价格至上边界之上 (AdjustAboveStopLevel)

此函数不仅验证价格,而且如果价格无效(即小于或等于上边界),会自动将其调整到上边界之外,并可选择性地增加 argAddPips 指定的缓冲点数。

/**
 * @brief 验证价格是否在上边界之上,如果无效则自动调整到边界之上(加缓冲)。
 * 适用于需要设置在 Ask 价上方的价格。
 * @param argSymbol       交易品种。
 * @param argAdjustPrice  需要验证和可能调整的价格。
 * @param argAddPips      调整时在边界基础上额外增加的缓冲点数 (pips, 可选, 默认 0)。
 * @param argOpenPrice    计算边界的基准价格 (可选, 默认 0 使用 Ask)。
 * @return double         返回调整后的有效价格;如果原始价格已有效则直接返回。获取基准价失败则返回原始价。
 */
double AdjustAboveStopLevel(string argSymbol, double argAdjustPrice, int argAddPips = 0,
                            double argOpenPrice = 0)
{
    // 1. 计算停止级别价格距离
    double stopLevelDist = MarketInfo(argSymbol, MODE_STOPLEVEL) * Point;
    if (stopLevelDist < 0) {
        Print("AdjustAboveStopLevel 错误: 无法获取 MODE_STOPLEVEL for ", argSymbol);
        return(argAdjustPrice); // 获取失败则不调整,返回原值
    }

    // 2. 确定基准价格
    double basePrice;
    if (argOpenPrice == 0) {
        RefreshRates();
        basePrice = MarketInfo(argSymbol, MODE_ASK);
        if (basePrice <= 0) {
             Print("AdjustAboveStopLevel 错误: 无法获取 Ask price for ", argSymbol);
             return(argAdjustPrice); // 获取失败不调整
        }
    } else {
        basePrice = argOpenPrice;
    }

    // 3. 计算上停止级别边界
    double upperStopLevelBoundary = NormalizeDouble(basePrice + stopLevelDist, Digits);

    // 4. 检查价格是否无效 (小于或等于边界)
    double finalPrice; // (已修正: 在 if 外声明)
    if (argAdjustPrice <= upperStopLevelBoundary)
    {
        // 价格无效,需要调整
        // 计算缓冲距离对应的价格值 (需要 PipPoint 函数,假设已定义)
        double buffer = argAddPips * PipPoint(argSymbol);
        // 调整后的价格 = 上边界 + 缓冲
        finalPrice = upperStopLevelBoundary + buffer;
        // 规范化调整后的价格
        finalPrice = NormalizeDouble(finalPrice, Digits);
        Print("价格 ", argAdjustPrice, " 无效 (未高于上边界 ", upperStopLevelBoundary, "), 自动调整为: ", finalPrice); // 日志记录调整
    }
    else // 价格本身已有效 (严格大于边界)
    {
        finalPrice = argAdjustPrice; // 无需调整,使用原始价格
    }

    // 5. 返回最终有效价格
    return(finalPrice);
}
  • 参数解释:
    • argAdjustPrice: 需要被处理的目标价格。
    • argAddPips (可选): 整数,指定在自动调整时,在刚好满足要求的边界价格基础上,再额外增加多少个 pips 作为缓冲。默认为 0,即调整到刚好在边界之外(理论上刚好等于边界可能仍有问题,建议设置少量缓冲)。
    • argOpenPrice (可选): 计算边界的基准价,用法同 VerifyUpperStopLevel
  • 逻辑: 函数计算出上边界 upperStopLevelBoundary。检查 argAdjustPrice 是否小于或等于该边界。如果是(即无效),则计算调整后的价格为 upperStopLevelBoundary + 缓冲价格距离;否则(即有效),保持 argAdjustPrice 不变。最终返回这个保证有效的价格。
  • 返回值: 该函数总是返回一个保证有效(位于上边界之上)的价格,可以直接用于设置相应的止盈、止损或挂单价。
  • 下边界调整: 自动调整价格至下边界之下的函数 (AdjustBelowStopLevel) 逻辑类似,只是比较方向和调整方向相反(调整为 lowerStopLevelBoundary - 缓冲)。
赞(0)
未经允许不得转载:图道交易 » ​MQL4(27):处理停止级别 - 封装验证与调整函数
分享到