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
相关产品推荐
相关产品推荐

