Deleting objects

The MQL5 API offers two functions for deleting objects. For bulk deletion of objects that meet the conditions for a prefix in the name, type, or subwindow number, use ObjectsDeleteAll. If you need to select the objects to be deleted by some other criteria (for example, by an outdated date and time coordinate), or if this is a single object, use the ObjectDelete function.

The ObjectsDeleteAll function has two forms: with a parameter for the name prefix and without it.

int ObjectsDeleteAll(long chartId, int window = -1, int type = -1)

int ObjectsDeleteAll(long chartId, const string prefix, int window = -1, int type = -1)

The function deletes all objects on the chart with the specified chartId, taking into account the subwindow, type, and initial substring in the name.

Value 0 in the chartId parameter represents the current chart, as usual.

Default values (-1) in the window and type parameters define all subwindows and all types of objects, respectively.

If the prefix is empty, objects with any name will be deleted.

The function is executed synchronously, that is, it blocks the calling MQL program until its completion and returns the number of deleted objects. Since the function waits for the execution of all commands that were in the chart queue before calling it, the action may take some time.

bool ObjectDelete(long chartId, const string name)

The function deletes an object with the specified name on the chart with chartId.

Unlike ObjectsDeleteAll, ObjectDelete is executed asynchronously, that is, it sends a command to the graphics to delete the object and immediately returns control to the MQL program. The result of true indicates the successful placement of the command in the queue. To check the result of execution, you can use the ObjectFind function or any ObjectGet functions, which query the properties of an object.

As an example, consider the ObjectCleanup1.mq5 script. Its task is to remove objects with "our" prefix, which are generated by the ObjectSimpleShowcase.mq5 script from the previous section.

In the simplest case, we could write this:

#include "ObjectPrefix.mqh"
   
void OnStart()
{
   const int n = ObjectsDeleteAll(0ObjNamePrefix);
   PrintFormat("%d objects deleted"n);
}

But to add variety, we can also provide the option to delete objects using the ObjectDelete function through multiple calls. Of course, this approach does not make sense when ObjectsDeleteAll meets all requirements. However, this is not always the case: when objects need to be selected according to special conditions, that is, not only by prefix and type, ObjectsDeleteAll won't help anymore.

Later, when we get acquainted with the functions of reading the properties of objects, we will complete the example. In the meantime, we will introduce only an input variable for switching to the "advanced" delete mode (UseCustomDeleteAll).

#property script_show_inputs
input bool UseCustomDeleteAll = false;

In the OnStart function depending on the selected mode, we will call the standard ObjectsDeleteAll, or our own implementation CustomDeleteAllObjects.

void OnStart()
{
   const int n = UseCustomDeleteAll ?
      CustomDeleteAllObjects(0ObjNamePrefix) :
      ObjectsDeleteAll(0ObjNamePrefix);
      
   PrintFormat("%d objects deleted"n);
}

Let's sketch this function first, and then refine it.

int CustomDeleteAllObjects(const long chartconst string prefix,
   const int window = -1const int type = -1)
{
   int count = 0;
   const int n = ObjectsTotal(chartwindowtype);
   
   // NB: cycle through objects in reverse order of the internal chart list
   // to keep numbering as we move away from the tail
   for(int i = n - 1i >= 0; --i)
   {
      const string name = ObjectName(chartiwindowtype);
      if(StringLen(prefix) == 0 || StringFind(nameprefix) == 0)
      // additional checks that ObjectsDeleteAll does not provide,
      // for example, by coordinates, color or anchor point
      ...
      {
         // send a command to delete a specific object
         count += ObjectDelete(chartname);
      }
   }
   return count;
}

Here we see several new features that will be described in the next section (ObjectsTotal, ObjectName). Their point should be clear in general: the first function returns the index of objects on the chart, and the second one returns the name of the object under the specified index.

It is also worth noting that the loop through objects goes in index descending order. If we did it in the usual way, then deleting objects at the beginning of the list would lead to a violation of the numbering. Strictly speaking, even the current loop does not guarantee complete deletion, assuming that another MQL program starts adding objects in parallel with our deletion. Indeed, a new "foreign" object can be added to the beginning of the list (it is formed in alphabetical order of object names) and increase the remaining indexes, pushing "our" next object to be deleted beyond the current index i. The more new objects are added to the beginning, the more likely it is to miss deleting your own.

Therefore, to improve reliability, it would be possible after the loop to check that the number of remaining objects is equal to the difference between the initial number and the number of objects removed. Although this does not give a 100% guarantee, since other programs could delete objects in parallel. We will leave these specifics for independent study.

In the current implementation, our script should delete all objects with "our" prefix, regardless of switching the UseCustomDeleteAll mode. The log should show something like this:

ObjectSimpleShowcase (XAUUSD,H1) 14 objects of various types created 
ObjectCleanup1 (XAUUSD,H1) 14 objects deleted

Let's get to know the ObjectsTotal and ObjectName functions, which we just used, and then return to the ObjectCleanup2.mq5 version of the script.