删除对象
MQL5 API 提供了两个用于删除对象的函数。要批量删除符合名称前缀、类型或子窗口编号条件的对象,可使用ObjectsDeleteAll函数。如果需要通过其他条件(如过时的日期时间坐标)选择要删除的对象,或仅删除单个对象,则使用 ObjectDelete函数。
ObjectsDeleteAll函数有两种形式:带名称前缀参数的形式和不带名称前缀参数的形式
int ObjectsDeleteAll(long chartId, int window = -1, int type = -1)
int ObjectsDeleteAll(long chartId, const string prefix, int window = -1, int type = -1)
该函数将删除指定 chartId图表上的所有对象,并考虑子窗口、类型和名称中的起始子字符串。
chartId参数值为 0 时,照例表示当前图表。
window和 type 参数的默认值 (-1) 分别定义所有子窗口和所有对象类型。
如果前缀为空,则将删除任意名称的对象。
该函数为同步执行,即将阻塞调用的 MQL 程序直至完成,并返回已删除对象的数量。由于该函数会等待调用前图表队列中所有命令执行完毕,因此操作可能需要一些时间。
bool ObjectDelete(long chartId, const string name)
该函数删除指定 chartId图表上具有指定名称的对象。
与 ObjectsDeleteAll不同,ObjectDelete 以异步方式执行,即它向图形发送删除对象命令,随后立即将控制权返回给 MQL 程序。返回值为true表示命令已成功加入队列。要检查执行结果,可使用 ObjectFind 函数或任何 ObjectGet函数查询对象特性。
以ObjectCleanup1.mq5脚本为例。它的任务是移除带有 "our" 前缀的对象,这些对象由上一节的 ObjectSimpleShowcase.mq5脚本生成。
在最简单的情况下,我们可以这样写:
#include "ObjectPrefix.mqh"
|
但为了增加多样性,我们还可以提供通过多次调用ObjectDelete函数来删除对象的选项。当然,当ObjectsDeleteAll满足所有要求时,采用此方法并无实际意义。但情况并非总是如此:当需要根据特殊条件(即不仅限于前缀和类型)选择对象时,ObjectsDeleteAll将不再适用。
后续当我们掌握读取对象特性的函数后,将完善此示例。当前,我们仅引入一个用于切换到“高级”删除模式的输入变量(UseCustomDeleteAll)。
#property script_show_inputs
|
在 OnStart函数中,根据所选模式,我们将调用标准的 ObjectsDeleteAll,或我们自己实现的 CustomDeleteAllObjects。
void OnStart()
|
我们将先构建该函数的框架,再逐步完善其实现。
int CustomDeleteAllObjects(const long chart, const string prefix,
|
此处涉及多项新功能,将在 下一节 中介绍(ObjectsTotal、ObjectName)总体而言,这些函数的功能应当明确:第一个函数返回图表上对象的索引,第二个函数返回指定索引下的对象名称。
同样需要注意的是,对象遍历采用降序索引循环方式:如果按常规顺序处理,删除列表起始位置的对象会导致索引编号错乱。严格来说,当前的循环也不能保证完全删除,假设有另一个 MQL 程序在我们删除的同时并行添加对象。确实,新的“外部”对象可能被添加到列表开头(列表按对象名称字母顺序生成),这会导致剩余索引值增加,从而将原本待删除的 "our" 对象推到当前索引i之后。新对象添加到开头的数量越多,就越有可能漏删自己的对象。
因此,为提高可靠性,可以在循环结束后检查剩余对象数量是否等于初始数量减去已删除对象数量。不过这也无法提供 100% 的保证,因为其他程序同样可能并行删除对象。我们将这些具体细节留待自行研究。
在当前实现中,无论是否切换UseCustomDeleteAll模式,我们的脚本都应删除所有带 "our" 前缀的对象。日志应显示如下内容:
ObjectSimpleShowcase (XAUUSD,H1) 14 objects of various types created
|
让我们先了解刚刚使用的 ObjectsTotal和 ObjectName 函数,然后再回到 ObjectCleanup2.mq5 版本的脚本。