Borrar objetos

La API de MQL5 ofrece dos funciones para eliminar objetos. Para la eliminación masiva de objetos que cumplan las condiciones de un prefijo en el nombre, tipo o número de subventana, utilice ObjectsDeleteAll. Si necesita seleccionar los objetos que desea eliminar por algún otro criterio (por ejemplo, por una coordenada de fecha y hora obsoleta), o si se trata de un único objeto, utilice la función ObjectDelete.

La función ObjectsDeleteAll tiene dos formas: con un parámetro para el prefijo del nombre y sin él.

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

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

La función borra todos los objetos del gráfico con la dirección chartId especificada, teniendo en cuenta la subventana, el tipo y la subcadena inicial del nombre.

El valor 0 del parámetro chartId representa el gráfico actual, como de costumbre.

Los valores por defecto (-1) en los parámetros window y type definen todas las subventanas y todos los tipos de objetos, respectivamente.

Si el prefijo está vacío, se eliminarán los objetos con cualquier nombre.

La función se ejecuta de forma sincrónica, es decir, bloquea hasta su finalización el programa MQL que está llamando y devuelve el número de objetos eliminados. Dado que la función espera a que se ejecuten todos los comandos que estaban en la cola del gráfico antes de llamarla, la acción puede tardar algún tiempo.

bool ObjectDelete(long chartId, const string name)

La función borra un objeto con el nombre especificado en el gráfico con chartId.

A diferencia de ObjectsDeleteAll, ObjectDelete se ejecuta de forma asíncrona, es decir, envía una orden a los gráficos para eliminar el objeto e inmediatamente devuelve el control al programa MQL. El resultado de true indica que el comando se ha colocado correctamente en la cola. Para comprobar el resultado de la ejecución, puede utilizar la función ObjectFind o cualquiera de las funciones ObjectGet***, que consultan las propiedades de un objeto.

Como ejemplo, vea el script ObjectCleanup1.mq5. Su tarea consiste en eliminar los objetos con el prefijo «nuestro», generados por el script ObjectSimpleShowcase.mq5 de la sección anterior.

En el caso más sencillo, podríamos escribir lo siguiente:

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

Sin embargo, para añadir variedad, también podemos proporcionar la opción de eliminar objetos utilizando la función ObjectDelete a través de múltiples llamadas. Por supuesto, este enfoque no tiene sentido cuando ObjectsDeleteAll cumple todos los requisitos. No obstante, no siempre es así: cuando los objetos deben seleccionarse según condiciones especiales, es decir, no sólo por prefijo y tipo, ObjectsDeleteAll ya no servirá de ayuda.

Más adelante, cuando nos familiaricemos con las funciones de lectura de las propiedades de los objetos, completaremos el ejemplo. Mientras tanto, introduciremos sólo una variable de entrada para cambiar al modo de borrado «avanzado» (UseCustomDeleteAll).

#property script_show_inputs
input bool UseCustomDeleteAll = false;

En la función OnStart, dependiendo del modo seleccionado, llamaremos al estándar ObjectsDeleteAll, o a nuestra propia implementación CustomDeleteAllObjects.

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

Primero vamos a esbozar esta función y luego a perfeccionarla.

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;
}

Aquí vemos varias novedades que se describirán en la sección siguiente (ObjectsTotal, ObjectName). La cuestión debería quedar clara en general: la primera función devuelve el índice de los objetos en el gráfico, y la segunda devuelve el nombre del objeto bajo el índice especificado.

También cabe señalar que el bucle a través de los objetos va en orden descendente de índice. Si lo hiciéramos de la forma habitual, la eliminación de objetos al principio de la lista supondría una violación de la numeración. En términos estrictos, ni siquiera el bucle actual garantiza el borrado completo, suponiendo que otro programa MQL comience a añadir objetos en paralelo a nuestro borrado. De hecho, se puede añadir un nuevo objeto «extraño» al principio de la lista (se forma por orden alfabético de los nombres de los objetos) y aumentar los índices restantes, empujando «nuestro» próximo objeto a eliminar más allá del índice actual i. Cuantos más objetos nuevos se añadan al principio, más probable será que no se borren los propios.

Por lo tanto, para mejorar la fiabilidad, sería posible comprobar después del bucle que el número de objetos restantes es igual a la diferencia entre el número inicial y el número de objetos retirados. Aunque esto no da una garantía del 100 %, ya que otros programas podrían borrar objetos en paralelo. Dejaremos estos detalles para su estudio de forma independiente.

En la implementación actual, nuestro script debería borrar todos los objetos con el prefijo «nuestro», independientemente de cambiar el modo UseCustomDeleteAll. El registro debería mostrar algo como lo siguiente:

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

Vamos a descubrir las funciones ObjectsTotal y ObjectName, que acabamos de utilizar, y luego volveremos a la versión ObjectCleanup2.mq5 del script.