timing problem with ChartIndicatorDelete()

 
Hi,

if have an EA that loads, handles and unloads several indicators. Therefore I created a wrapper class to hold indicator objects in a

CHashMap<string ident, cObject obj>

Things working fine for indicators like iATR, iMA and others.
Now I have a custom indicator that draws a bunch of lines (~800) of type OBJ_TREND. This indicator works fine in standalone and within my EA, too. The problem occurs when I unload the EA from the chart since it leads to "abnormal termination".


I found out, that it's coming from the amount of lines which the custom indicator draws. Seems to be some kind of timing problem. The custom indicator itself destroys the trendlines in OnDeinit() with

ObjectsDeleteAll(0, "UPPER_");
ObjectsDeleteAll(0, "LOWER_");

Since I have a wrapper object for all this indicators, I tried to pre-delete the trendlines in destructor right before ChartIndicatorDelete() to speed up the OnDeinit() function from the indicator.

But this seems to be too much, also. If I limit the lines, let's say to 50 within the indicator, the EA unloads correctly and removes everything from the chart, like it should. For this indicator I have the source code, so I could limit the amount of trendlines, but what if I don't have access to the source code?

// called in destructor of indicator wrapper
void cleanup() {

   _Log.info("Cleanup indicator " + getId() + " with handle " + IntegerToString(_handle), "", getId());

   if(_handle == INVALID_HANDLE) return;

   if(!_keepOnChart) { // decide if indicator should stay on chart or should be removed
      
      string name = getIndicatorNameByHandle(_subwindow, _handle);
      if(name != "") {
         if(ArraySize(_preDeleteGraphicalObjects) > 0) {
            preDeleteGraphicalObjects(_preDeleteGraphicalObjects);
         } 
         ArrayFree(_preDeleteGraphicalObjects);
         ChartIndicatorDelete(_window, _subwindow, name);
      }
   }

   // always free instances for this EA
   IndicatorRelease(_handle);
   _handle = INVALID_HANDLE;

   ArrayFree(_params);

}

// pre-delete graphical objects with certain prefixes
void preDeleteGraphicalObjects(string &prefixes[]) {

   // alternativ delete all with certain prefixes
   // for(int p = 0; p < ArraySize(prefixes); ++p) {
   //    ObjectsDeleteAll(_window, prefixes[p], _subwindow);
   //    _Log.info("Cleanup indicator, pre-delete with object prefix " + prefixes[p], "", getId());
   // }

   int total = ObjectsTotal(_window, _subwindow, -1);

   for(int i = total - 1; i >= 0; i--) {
      string name = ObjectName(_window, i, _subwindow, -1);

      // check for every prefix
      for(int p = 0; p < ArraySize(prefixes); p++) {
         string prefix = prefixes[p];
         if(StringFind(name, prefix) == 0) { // graphical object begins with prefix
            ObjectDelete(_window, name);
            _Log.info("Cleanup indicator, pre-delete with object prefix " + name, "", getId());
            break; // no more refix necessary
         }
      }
   }
}


What else can I do to get a bulletproof unloading w/o timing problems?

Thank you, Lex

 

All chart operations, such as adding or removing Graphics Objects, are queued for operation, and carried out asynchronously. So, even when you remove an Indicator from the chart, and it needs to clean up after itself, it will happen asynchronously.

Also, the OnDeinit event has a time limit and should not be delayed too long or else the Indicator/EA will be forced to terminate abnormally — Documentation on MQL5: MQL5 programs / Client Terminal Events

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.

If possible, make your Indicator use buffer graphics as much as possible, and restrict the amount of Graphics Objects it manipulates.

 
Fernando Carreiro #:
If possible, make your Indicator use buffer graphics as much as possible, and restrict the amount of Graphics Objects it manipulates.

Yes, you are right, I know. But it is not mine and in the future I maybe want to use closed-source ones, so I could not change anything. And to be honest, there are 800 trendlines only. That should not be a problem, shouldn't it?


I made some time measurements now. Unloading EA with:

3 Indicators (iATR, 2x iMA): ~70ms
3 Indicators (iATR, 2x iMA) + problematic one, with 1 OBJ_TREND: ~95ms
3 Indicators (iATR, 2x iMA) + problematic one, with 100 OBJ_TREND: ~1800ms
3 Indicators (iATR, 2x iMA) + problematic one, with 200 OBJ_TREND: ~3500ms, still gives me Print() output but at the end abnormal termination
3 Indicators (iATR, 2x iMA) + problematic one, with 300 OBJ_TREND: no more output, abnormal termination 

3 Indicators (iATR, 2x iMA) + Camarilla Channel (bundeled with MT5), with ~10 graph. objects: +250ms 


I know this measurements are not 100% correct, but there is an assessment. And as you said, chart operations are asynchronously, there shouldn't be such a big impact at all, because of a ridiculous amount of OBJ_TREND lines.
But the last test with Camarilla Channels makes me uncertain, took a lot of unload time, too, so I'm not sure at all.

Loading and unloading this problematic indicator in "standalone mode" is a blip of an eye, loading and unloading within a quick test EA, too. I have to dig into further. ATM I have no idea how to do this, need to think about. 

The funny thing is, all 3 + 1 indicators share the same structure in project: all 4 are handled by the same IndicatorManager object, all 4 reside in the same CHashMap<string, cObject> and all share the same base class. They are only different with their derived class that implement two functions (20 copied LOC), which are only calling two functions in the base class.

 
Alex #That should not be a problem, shouldn't it? ... chart operations are asynchronously, there shouldn't be such a big impact at all ...

Because of the asynchronous nature, MT5 is actually slower than MT4 when handling a large number of graphics objects, especially considering that a single thread is used for ALL indicators on the same symbol. So yes, it can be a problem.

Given that the indicator code is closed-source and you can not make improvements to it, there is not much you can do, except maybe to stay away from such indicators and making your own.

Remember that EAs do not have "eyes" and don't need all those graphic objects to work. It can do all the math internally without need of graphic objects.

 
Fernando Carreiro #:
Remember that EAs do not have "eyes" and don't need all those graphic objects to work. It can do all the math internally without need of graphic objects.
Yes sure, but while developing it is much more convenient to add, see, check, unload, test , compile, add, test, ... all day...

I changed now some global manager objects from automatic objects to dynamic objects (with new operator) to have a better control in which order which object gets deleted in OnDeinit() and tada :-): its working now. The necessary time for the OnDeinit function went down to 200ms for ALL cleanup work including all lines from that indicator! No more "abnormal termination" and the backtester is much faster, too!

Thank you very much for your tips and and thoughts and listening :-)
 
Fernando Carreiro #:

Because of the asynchronous nature, MT5 is actually slower than MT4 when handling a large number of graphics objects, especially considering that a single thread is used for ALL indicators on the same symbol. So yes, it can be a problem.

Given that the indicator code is closed-source and you can not make improvements to it, there is not much you can do, except maybe to stay away from such indicators and making your own.

Remember that EAs do not have "eyes" and don't need all those graphic objects to work. It can do all the math internally without need of graphic objects.

Can you prove that please ? (If you like). I don't think it's right.

 
Alain Verleyen #Can you prove that please ? (If you like). I don't think it's right.

It is based on visual experience (back in the day when I still used MT4/MQL4 extensively), where I observed that response time for many graphical object updates on MT4 was faster than on the MT5.

So, in technical concrete terms, I am currently unable to prove it.