Problem removing objects (mql5)

 

Hi,

if I draw more than 59 lines in the chart, and I want to eliminate those objects specifically when the OnDeinit () function is activated (when the profile is changed or when the terminal is closed) it only deletes 59 objects.

As I use a random variable to define the name of the object, in the next time that the chart or profile is loaded, the old lines remain which is not desirable because they interfere with the new profile layout. (for example, drawing lines for a market profile)

This does not happen with MT4 since no matter how many lines I draw it always eliminates them when the OnDeinit() function is invoked.

Any reason for this to happen specifically in MT5 ??


P.S. I attach a test code to observe the situation that I am talking about.

//+------------------------------------------------------------------+
//|                                                         test.mq5 |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_plots 0

double c[]; //arrays close, high low
datetime t[];
int x=0,rd;
string  rnd;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   rnd=  IntegerToString( rand()); 
   rd=StringLen(rnd);
   
   ArraySetAsSeries(c,true);
   ArraySetAsSeries(t,true);
      
//---
   return(INIT_SUCCEEDED);
  }
  //+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason){
  
  for(int cnt=ObjectsTotal(0,0)-1;cnt>=0;cnt--)
      {
         string name=ObjectName(0,cnt);
       
         string ss =StringSubstr(name,1,rd);
       
       if (StringGetCharacter(name,0) ==35&& ss==rnd) //delete objects firt char = #      
            ObjectDelete(0,name); 
       
         //ChartRedraw(0); 
      }   
    Print("End desconexion");
     
}    
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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[])
  {
//---
       CopyTime(Symbol(),0,0,100,t); 
       CopyClose(Symbol(),0,0,100,c);   
      if (x==0)
      {
         for (int i=0; i<70;i++) // until line 59 they are eliminated correctly, 
                                // increase the number of lines only 59 are eliminated and in the next load the old lines appear.
          {
            
            int num = 1 + 60*MathRand()/32768; // 
             ObjectCreate(0,"#"+rnd+IntegerToString(i), OBJ_TREND,0, t[0], c[i], t[num], c[i]);  
            Print(num);
            x=1;
          }
      
      
      }
    
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

Any insight is in advance appreciated!!

slds

 
Ok I got to thinking, if the issue has to do with that the time of deinitialized was very long but I see that even with less than a second fails to eliminate all objects.


So I can not think that anything else can be the reason why objects remain, even though apparently the elimination cycle runs completely and the disconnection time seems to be within the threshold.


any ideas?
 

Already discussed, search on the forum.

Your OnDeinit is taking too long. Try ObjectsDeleteAll(0,"#"+rnd)

 
Alain Verleyen:

Already discussed, search on the forum.

Your OnDeinit is taking too long. Try ObjectsDeleteAll(0,"#"+rnd)

Alain thanks for the insight, it's certainly the most appropriate and straight solution.Really there is no reason to use a loop to reach the goal (hehe).

again, thank you very much and I apologize for not having been very clever looking for the topic in the forum.

(topic) https://www.mql5.com/en/forum/160715

Best regards
OnDeinit() race condition and recalculation issues
OnDeinit() race condition and recalculation issues
  • 2016.11.10
  • www.mql5.com
Hello, I am writing an indicator which draws certain objects in the chart...
 
Alain Verleyen:

Already discussed, search on the forum.

Your OnDeinit is taking too long. Try ObjectsDeleteAll(0,"#"+rnd)

That's not the case here. Perhaps MQ has built in IsStopped() protections into the string functions he's relying on or his global variables are being destroyed before OnDeinit finishes, (it's neither) but the ObjectDelete function will continue to work for as long as you want when called from OnDeinit.

UPDATE: I cannot replicate OPs bug using MT5 build 1755 

This example proves the ability to easily delete upwards of 50,000 unique chart objects from OnDeinit without using "ObjectDeleteAll" and without any issues. You can even un-comment the while loop to delay OnDeinit by a full 10 seconds and it still works.

#property indicator_chart_window

#include <Arrays\ArrayObj.mqh>
#include <ChartObjects\ChartObjectsLines.mqh>
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CChartLine : public CChartObjectHLine
{
   static int        s_instances;
public:
   CChartLine(const double price)
   {
      string name=StringFormat("%s - %s: line_pointer #%d",
                               _Symbol,
                               EnumToString(_Period),
                               ++s_instances);
      this.Create(0,name,0,price);
      this.Selectable(true);
      ObjectSetInteger(m_chart_id,m_name,OBJPROP_HIDDEN,false);
   }
  ~CChartLine()
   {
      ulong ms = GetMicrosecondCount();
      if((--s_instances % 1000) == 0)
         printf("There are %d remaining line object instances",s_instances);
      //while(GetMicrosecondCount()-ms < 1000)
      //   continue;
   }
};
int CChartLine::s_instances=0;

CArrayObj *global_array;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   global_array=new CArrayObj;
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnDeinit(const int r)
  {
   uint tc = GetTickCount();
   printf("Deinit begin");
   if(CheckPointer(global_array))
      delete global_array;
   printf("Deinit end, completed in %d ms.",GetTickCount()-tc);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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[])
  {
//---
   static bool once=false;
   if(!once)
     {
      MqlTick tick;
      SymbolInfoTick(_Symbol,tick);
      for(int i=0;i<25000;i++)
        {
         CChartLine *line_pointer=new CChartLine(tick.bid+i*_Point);
         global_array.Add(line_pointer);
         line_pointer=new CChartLine(tick.bid-i*_Point);
         global_array.Add(line_pointer);
        }
      once=true;
     }
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
 
aslkdjf:

That's not the case here. Perhaps MQ has built in IsStopped() protections into the string functions he's relying on or his global variables are being destroyed before OnDeinit finishes, (it's neither) but the ObjectDelete function will continue to work for as long as you want when called from OnDeinit.

Yes it's the case, you missed the point.

Due to specific code of the OP, as he is using a global variable to check the object's name, but what was discovered in the topic above, is that the events are not processed in sequence (synchronously). So the rnd value can be changed before all objects are deleted, and it doesn't find (and delete) the remaining objects. ObjectDeleteAll() hopefully is "monolithic" and should not lead to this issue. The problem is solved as reported by the OP.

UPDATE: I cannot replicate OPs bug using MT5 build 1755 

I suppose it depends of the computer, maybe try to increase the number of objects ?

This example proves the ability to easily delete upwards of 50,000 unique chart objects from OnDeinit without using "ObjectDeleteAll" and without any issues. You can even un-comment the while loop to delay OnDeinit by a full 10 seconds and it still works.

I didn't try your code, but that would mean that once again the documentation is obsolete.

The deinitialization reason can be obtained from the parameter, passed to the OnDeinit() function. The OnDeinit() function run is restricted to 2.5 seconds. If during this time the function hasn't been completed, then it is forcibly terminated. The Deinit event is not generated for scripts.

 
Alain Verleyen:

Yes it's the case, you missed the point.

Due to specific code of the OP, as he is using a global variable to check the object's name, but what was discovered in the topic above, is that the events are not processed in sequence (synchronously). So the rnd value can be changed before all objects are deleted, and it doesn't find (and delete) the remaining objects. ObjectDeleteAll() hopefully is "monolithic" and should not lead to this issue. The problem is solved as reported by the OP. I suppose it depends of the computer, maybe try to increase the number of objects ?

I didn't try your code, but that would mean that once again the documentation is obsolete.

This is obviously a case of obsolete documentation because you can push OnDeinit well beyond 2.5 seconds without any issues. 

 

To delete all objects, this code is enough:

int deinit()
{
    ObjectsDeleteAll(0);
    return (0);
}
 
Kenan Ozkarakas #:  To delete all objects,

You should never to that. Only delete the objects your code creates.

 
Add ChartRedraw(); at the end of deinit solved the problem for me.
 
this is a thread from 2018, and there's another recent trade on this subject
Reason: