You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MQL4指标开发求助:如何删除已突破的无效价格区间对象

解决MQL4指标无法删除已突破价格区间的问题

问题核心分析

现有代码存在几个关键问题导致无效区间无法删除:

  • 数组存储对象名的索引逻辑混乱:创建区间时用循环变量i直接赋值数组索引,删除时用ObjectsTotal()的循环变量j遍历,两者无对应关系,导致无法正确获取目标对象名。
  • 价格突破判断逻辑错误:用循环变量j作为K线索引取Close[j],这和数组存储的对象名没有关联,应该检查最新K线的价格走势是否突破区间。
  • 循环遍历方式不合理:正序遍历ObjectsTotal()删除对象时,对象总数减少会导致漏删;且未区分多空区间对象,统一遍历会出现空对象名调用ObjectGet的错误。
  • 对象名可能重复:用整数格式的高低价作为后缀,若存在相同价格的区间,会导致对象创建失败或数组存储重复名称。

修正方案

1. 改用动态数组存储对象名

避免固定索引赋值的问题,用动态数组统一管理多空区间的对象名:

// 全局变量定义
string rectangleLongNames[]; // 存储多头区间对象名
string rectangleShortNames[]; // 存储空头区间对象名

创建区间的代码修改为:

if (isCandleSequenceLong)
{
    // 用Digits保证价格精度,避免对象名重复
    string LongName = "Bullish_" + DoubleToString(Low[i + 2], Digits);
    if(ObjectCreate(LongName, OBJ_RECTANGLE, 0, Time[i + 3], High[i + 2], EMPTY_VALUE, Low[i + 2]))
    {
        ObjectSet(LongName, OBJPROP_COLOR, Lime);
        if (!FillZone) ObjectSet(LongName, OBJPROP_BACK, false);
        // 动态添加到数组
        ArrayResize(rectangleLongNames, ArraySize(rectangleLongNames)+1);
        rectangleLongNames[ArraySize(rectangleLongNames)-1] = LongName;
    }
    isCandleSequenceLong = false;
}

if (isCandleSequenceShort)
{
    string ShortName = "Bearish_" + DoubleToString(High[i + 2], Digits);
    if(ObjectCreate(ShortName, OBJ_RECTANGLE, 0, Time[i + 3], High[i + 2], EMPTY_VALUE, Low[i + 2]))
    {
        ObjectSet(ShortName, OBJPROP_COLOR, Red);
        if (!FillZone) ObjectSet(ShortName, OBJPROP_BACK, false);
        ArrayResize(rectangleShortNames, ArraySize(rectangleShortNames)+1);
        rectangleShortNames[ArraySize(rectangleShortNames)-1] = ShortName;
    }
    isCandleSequenceShort = false;
}

2. 重写删除无效区间的函数

  • 倒序遍历数组避免删除元素后索引错乱
  • 检查最新K线的突破情况,确认有效突破后删除
  • 区分多空区间处理,删除后从数组移除对应名称
void DeleteBrokeZone()
{
    // 处理多头区间:价格突破区间上沿(OBJPROP_PRICE1)则删除
    for(int j = ArraySize(rectangleLongNames)-1; j >= 0; j--)
    {
        string objName = rectangleLongNames[j];
        if(!ObjectFind(0, objName)) continue; // 对象已不存在,跳过
        
        double zoneTop = ObjectGetDouble(0, objName, OBJPROP_PRICE1);
        // 确认有效突破:当前K线收盘高于区间上沿,前一根低于
        if(Close[0] > zoneTop && Close[1] <= zoneTop)
        {
            if(ObjectDelete(0, objName))
            {
                ArrayRemove(rectangleLongNames, j);
                Print("Deleted bullish zone: ", objName);
            }
            else
            {
                Print("Failed to delete bullish zone: ", objName, " Error code: ", GetLastError());
            }
        }
    }

    // 处理空头区间:价格突破区间下沿(OBJPROP_PRICE2)则删除
    for(int j = ArraySize(rectangleShortNames)-1; j >= 0; j--)
    {
        string objName = rectangleShortNames[j];
        if(!ObjectFind(0, objName)) continue;
        
        double zoneBottom = ObjectGetDouble(0, objName, OBJPROP_PRICE2);
        if(Close[0] < zoneBottom && Close[1] >= zoneBottom)
        {
            if(ObjectDelete(0, objName))
            {
                ArrayRemove(rectangleShortNames, j);
                Print("Deleted bearish zone: ", objName);
            }
            else
            {
                Print("Failed to delete bearish zone: ", objName, " Error code: ", GetLastError());
            }
        }
    }
}

3. 关键补充说明

  • 使用ObjectGetDouble替代ObjectGet:MQL4中推荐用类型安全的获取函数,避免类型转换错误。
  • 添加ObjectFind检查:防止对象已被手动删除或创建失败时,调用ObjectGet出现异常。
  • 用Digits格式化价格:保证价格后缀的唯一性,避免相同价格区间的对象名重复。
  • 在OnCalculate中调用DeleteBrokeZone():确保每根K线更新时自动检查并删除无效区间。

内容的提问来源于stack exchange,提问作者Andrea Ramengo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 05:10:18