ObjectDelete() function not working properly

 

I'm writing an indicator which displays (many) trendlines on the chart. When the indicator is removed from the chart I would like to delete the trendlines it has drawn, and do so without deleting other trendlines created by other indicators or drawn manually. For illustration one can just assume the following code, which draws many trendlines:


int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
   if (rates_total < 10)
      return(rates_total);
   for (int i = MathMax(0, rates_total - 500); i < rates_total; i++)
   {
      ObjectCreate(0, "My Trendline " + i, OBJ_TREND, 0, time[rates_total - 5], close[rates_total - 5], time[rates_total - 2], close[rates_total - 2]); 
      ObjectSetInteger(0,"My Trendline " + i,OBJPROP_SELECTABLE, true);
      ObjectSetString(0,"My Trendline " + i, OBJPROP_TOOLTIP, "Description");
   }
   
   return(rates_total);
  }


In order to delete the trendlines I implement the OnDeinit() procedure, search the list of chart objects for objects with the substring "My Trendline", and delete every one of those.


void OnDeinit(const int reason)
  {
   /*for (int i = 0; i < ObjectsTotal(0); i++)
   {
      string name = ObjectName(0, i);
      if (StringFind(name, "My Trendline") != -1)
      {
            ObjectDelete(0, name);
      }
   }*/
   ObjectsDeleteAll(0, -1, OBJ_TREND);
  }


The problem is that it doesn't work, and the chart still contains the trendlines. If I delete the trendlines using the  ObjectsDeleteAll() function, the trendlines are removed but so are also every other trendline. Also, if the chart does not contain too many trendlines it seems to work, but becomes a problem when several hundreds of trendlines are drawn by the indicator.


Does anyone know the problem, or a possible solution?

 
Andorofo:

I'm writing an indicator which displays (many) trendlines on the chart. When the indicator is removed from the chart I would like to delete the trendlines it has drawn, and do so without deleting other trendlines created by other indicators or drawn manually. For illustration one can just assume the following code, which draws many trendlines:



In order to delete the trendlines I implement the OnDeinit() procedure, search the list of chart objects for objects with the substring "My Trendline", and delete every one of those.



The problem is that it doesn't work, and the chart still contains the trendlines. If I delete the trendlines using the  ObjectsDeleteAll() function, the trendlines are removed but so are also every other trendline. Also, if the chart does not contain too many trendlines it seems to work, but becomes a problem when several hundreds of trendlines are drawn by the indicator.


Does anyone know the problem, or a possible solution?

Yes

StringFind()

Is the incorrect approach.

Can use

ObjectFind()

Function.

Also

ObjectCreate(0, "My Trendline " + IntegerToString(i)
 
Marco vd Heijden:

Yes

Is the incorrect approach.

Can use

Function.

I'm using the StringFind() in order to filter out the objects with the substring "My Trendline", as every actual trendline has a unique name such as "My Trendline 1", "My Trendline 2".

The ObjectFind() function only returns whether or not an object with the specified name actually exists in the chart, and so does not address the problem since the name is already given by ObjectName() function.

If I add print statements in the OnDeinit() procedure the output actually says that an object with the name has been found, and the ObjectDelete() function returns true, yet the trendlines remain in the chart.

Could you please post an example OnDeinit() procedure which deletes just the trendlines which begin their name with "My Trendline", if you know the problem?


PS: I tried changing the name using IntegerToString(i) but it still does not function.

 
Andorofo:

I'm using the StringFind() in order to filter out the objects with the substring "My Trendline", as every actual trendline has a unique name such as "My Trendline 1", "My Trendline 2".

The ObjectFind() function only returns whether or not an object with the specified name actually exists in the chart, and so does not address the problem since the name is already given by ObjectName() function.

If I add print statements in the OnDeinit() procedure the output actually says that an object with the name has been found, and the ObjectDelete() function returns true, yet the trendlines remain in the chart.

Could you please post an example OnDeinit() procedure which deletes just the trendlines which begin their name with "My Trendline", if you know the problem?


PS: I tried changing the name using IntegerToString(i) but it still does not function.

Well you call the ObjectsTotal() function at every cycle in the loop but if the loop removes an object then this will affect that exact number of iterations... and hence int i, so instead you can do like so:

void OnDeinit(const int reason)
  {
   int objects=ObjectsTotal(0);
   for (int i = 0; i < objects; i++)
   {
      string name = ObjectName(0, i);
      if (StringFind(name, "My Trendline") != -1)
      {
            ObjectDelete(0, name);
      }
   }
   ObjectsDeleteAll(0, -1, OBJ_TREND);
  }
 
Marco vd Heijden:

Well you call the ObjectsTotal() function at every cycle in the loop but if the loop removes an object then this will affect that exact number of iterations... and hence int i, so instead you can do like so:

Mhm, I too thought that was the problem, but after trying to put the ObjectsTotal() function outside the loop scope, somehow strangely the trendlines remain.
 
Perhaps it is because the trendlines get different psoitions in the object list when deleting?, i.e. after deleting one at position X, the successive trendlines are shifted backwards immediately.
 
Andorofo:
Mhm, I too thought that was the problem, but after trying to put the ObjectsTotal() function outside the loop scope, somehow strangely the trendlines remain.
At this point it is time to check the return value of
ObjectDelete()

Also watch the output log to see something like

4202

ERR_OBJECT_DOES_NOT_EXIST

Object does not exist

4203

ERR_UNKNOWN_OBJECT_TYPE

Unknown object type

4204

ERR_NO_OBJECT_NAME

No object name


Also

ObjectsTotal

The function returns the number of objects in the specified chart, specified subwindow, of the specified type.

int  ObjectsTotal(
   long  chart_id,           // chart identifier
   int   sub_window=-1,      // window index
   int   type=-1             // object type
   );

Parameters

chart_id

[in]  Chart identifier. 0 means the current chart.

sub_window=-1

[in]  Number of the chart subwindow. 0 means the main chart window, -1 means all the subwindows of the chart, including the main window.

type=-1

[in]  Type of the object. The value can be one of the values of the ENUM_OBJECT enumeration. -1 means all types.

Return Value

The number of objects.
 

So that seemed to be the problem, that after deleting an object the chart's object list changes. The following procedure removed all the trendlines:

void OnDeinit(const int reason)
  {
   bool allDeleted = false;
   while (!allDeleted)
   {
      allDeleted = true;
      int objects=ObjectsTotal(0);
      for (int i = 0; i < objects; i++)
      {
         string name = ObjectName(0, i);
         if (StringFind(name, "My Trendline") != -1)
         {
            allDeleted = false;
            ObjectDelete(0, name);
         }
      }
   }
   //ObjectsDeleteAll(0, -1, OBJ_TREND);
  }


Kindof nice to know since I have seen the previous version in other indicators.

 
Andorofo:

So that seemed to be the problem, that after deleting an object the chart's object list changes. The following procedure removed all the trendlines:


Kindof nice to know since I have seen the previous version in other indicators.

So

int objects=ObjectsTotal(-1,-1);


And the best approach would be to use i-- in stead of i++ in the loop.

This way it auto compensates so to speak.