Summary: 每次在MetaEditor里编译代码后,MT4图表上的所有手动画线、箭头、文本标签全部消失?这是因为代码中的对象缓冲区逻辑触发了全图表刷新。本文详细分析原因并提供三个层面的修复方案。




聊一个不太常见但遇到了就特别上火的毛病。你在MetaEditor里改个指标参数,或者给脚本加个注释,随手点了下“编译”,代码没报错,一切正常。等你切回MT4的图表界面——傻眼了,整个图表光秃秃的。你自己画的支撑阻力线没了,之前标注的箭头和文字也全没了,就跟刚打开一个新图表似的。

第一次遇到这事儿的时候,我还以为是MT4抽风了,重启了好几次都没用。后来翻了一堆外文帖子才发现,问题不在平台,在你的代码里。准确地说,是你的代码在编译的时候,给终端发送了一个“刷新一切”的信号,而终端执行力极强,二话不说就把你画的东西全清了。

根源在哪儿?

核心问题就出在对象(Object)的创建和删除逻辑上。如果你的代码里用 ObjectCreate()ObjectDelete() 的时候,对象名字是固定的,比如 "MyLine",而且每次执行时没有做存在性判断,那编译的时候终端就会认为这个对象需要重新创建。如果旧对象和新对象冲突了,终端就会来一次全量刷新来解决冲突——然后你所有的画线就跟着陪葬了。

第一步:改掉死板的对象命名

我之前写过一个多周期的阻力位指标,里面画线用的名字是写死的 "Resistance"。每次编译后图表必然重置。后来改成用时间戳来命名,问题直接消失了一半。

不要这样写:
``c
ObjectCreate("MyLine", OBJ_HLINE, 0, 0, price);
`

改成这样:
`c
string lineName = "HLINE_" + DoubleToStr(Time[0], 0);
ObjectCreate(lineName, OBJ_HLINE, 0, 0, price);
`

这样每根线都有唯一的标识,终端就不会搞混了。

第二步:检查
ObjectsDeleteAll() 的使用场景

这个问题代码里很常见——有些人习惯在
start() 函数开头就放一个 ObjectsDeleteAll(),然后重新画所有东西。单次执行没问题,但如果你在编译时触发了代码重跑,那这个函数就会把之前的所有东西删光光。

解决思路是加一道判断:如果对象已经存在,就只更新数值,不要重复创建。可以用
ObjectFind() 来检查对象是否已经存在。

第三步:
prev_calculated 的局限性(官方文档没写明白的地方)

MQL4官方文档(docs.mql4.com)里提到,
OnCalculate() 函数中的 prev_calculated 参数可以帮助判断当前是第一次加载还是收到新报价。如果值为0,表示从头开始计算;否则只计算新来的K线。

文档的逻辑没错,但有个隐藏问题:你在MetaEditor里手动点击编译的时候,
prev_calculated 会被强制重置为0,即使你的对象已经存在,它也会走一遍全量初始化的流程。这就意味着,你不可能单纯靠 prev_calculated 来保住图表上的对象。

我自己的解决方式是双重保障:在代码里用全局变量记录对象是否已经创建,同时在对象命名上加上时间戳做唯一区分。不把希望寄托在
prev_calculated 上。

第四步:一个几乎没人提过的编译器设置

这个是最容易被忽略的,也是我今天最想分享的。打开MetaEditor,点 工具 > 选项 > MQL4编译器,里面有一个选项叫“编译后重置图表”。这个选项默认是开启的,而且藏得比较深,很多人压根不知道它的存在。

如果这个选项被打勾了,你每次编译代码,不管代码有没有问题,图表都会强制刷新,所有非持久化的对象(就是你手工画上去的那些线)都会被清掉。把这个勾取消掉,至少能排除掉平台层面的干扰。

最后多说一句,养成在代码里使用
ChartRedraw()` 的习惯,手动控制图表更新的时机,而不是把刷新权完全交给终端。这样你的控制力会强很多。

参考来源: MQL4官方文档. "对象函数"和"OnCalculate()"章节. docs.mql4.com。
参考来源: MetaQuotes帮助中心. "MetaEditor选项设置." help.metaquotes.net。

本文首发于FXEAR.com,原创内容,未经授权禁止转载。