Unpredictable OrderCreate behaviour, events never fire

 

OnInit I have


ChartSetInteger(0, CHART_EVENT_OBJECT_CREATE, true);

Creating an object on millisecond timer

uint Span=1000; 
uint Next=GetTickCount()-Span;  
int counter;
void OnTimer()
  {   
   if(Next<=(GetTickCount()+Span))
     {        
      counter++;
      string name="TestObj_"+(string)counter;
      Print(__FUNCTION__+": Creating "+name+" ...");
      if(!ObjectCreate(0, name,OBJ_HLINE,0,TimeCurrent(),1.0))
         Print(__FUNCTION__+": Error "+(string)_LastError); 
      Next+=Span;      
     }   
   if(_LastError!=0)
     {
      Print(__FUNCTION__+": Error="+(string)_LastError);   
      ResetLastError();  
     }
  }

Observations:

1. Object create events usually do not fire when created On Timer. I've seen this happen earlier though, but the code wasn't the same (failing to repropduce).

2. No errors. I guess this is within whats documented ("In this case, true only means that the command has been successfully enqueued"). However this is true also if the line already exists, which is something to keep in mind.

3. I have observed this behavior also when creating an object manully, thats what got me to investigate it, but this is another thing I'm failing to reproduce.

4. Works as expected on MT4.


Snippet from logs, as you can see it happens sometimes:

2018.03.04 09:21:29.397 ObjectCreateTest (GBPUSD,M5) OnTimer: Creating TestObj_29 ...

2018.03.04 09:21:29.930 ObjectCreateTest (GBPUSD,M5) OnDeinit

2018.03.04 09:21:29.933 ObjectCreateTest (GBPUSD,M1) OnInit

2018.03.04 09:21:30.941 ObjectCreateTest (GBPUSD,M1) OnTimer: Creating TestObj_30 ...

2018.03.04 09:21:30.941 ObjectCreateTest (GBPUSD,M1) OnDeinit

2018.03.04 09:21:30.944 ObjectCreateTest (GBPUSD,H4) OnInit

2018.03.04 09:21:31.952 ObjectCreateTest (GBPUSD,H4) OnChartEvent: TestObj_30 created

2018.03.04 09:21:31.952 ObjectCreateTest (GBPUSD,H4) OnTimer: Creating TestObj_31 ...

2018.03.04 09:21:31.952 ObjectCreateTest (GBPUSD,H4) OnDeinit

2018.03.04 09:21:31.953 ObjectCreateTest (GBPUSD,W1) OnInit

Complete code attached.

EDIT: Added screenshot

 
bwa:
 

1. Object create events usually do not fire when created On Timer. I've seen this happen earlier though, but the code wasn't the same (failing to repropduce).

2. No errors. I guess this is within whats documented ("In this case, true only means that the command has been successfully enqueued"). However this is true also if the line already exists, which is something to keep in mind.

3. I have observed this behavior also when creating an object manully, thats what got me to investigate it, but this is another thing I'm failing to reproduce.

4. Works as expected on MT4.

You should add the function ChartRedraw() after every calling ObjectCreate(). See bellow.

void OnTimer()
  {   
   if(Next<=(GetTickCount()+Span))
     {        
      counter++;
      string name="TestObj_"+(string)counter;
      Print(__FUNCTION__+": Creating "+name+" ...");
      if(!ObjectCreate(0, name,OBJ_HLINE,0,TimeCurrent(),1.0))
         Print(__FUNCTION__+": Error "+(string)_LastError); 
      ChartRedraw();
      Next+=Span;      
     }   
   if(_LastError!=0)
     {
      Print(__FUNCTION__+": Error="+(string)_LastError);   
      ResetLastError();  
     }
  }
 
Petr Nosek:

You should add the function ChartRedraw() after every calling ObjectCreate(). See bellow.

I see. I Didn't realize that the create events are fired only once chart is redrawn. And a weekend too, so no new ticks to trigger it.

But that still doesn't explain why the TestObj_29 didn't print on create event.

 
bwa:

But that still doesn't explain why the TestObj_29 didn't print on create event.

What are you talking about? The script works well. See the attached log.

Files:
LOG.txt  6 kb
 
Petr Nosek:

What are you talking about? The script works well. See the attached log.

I'm talking about the line in my original post:

2018.03.04 09:21:29.397 ObjectCreateTest (GBPUSD,M5) OnTimer: Creating TestObj_29 ...

which never triggered OnChartEvent like

2018.03.04 09:21:31.952 ObjectCreateTest (GBPUSD,H4) OnChartEvent: TestObj_30 created

OnChartEvent: TestObj_29 created is missing.


I think it has something to do with the OnDeinit/OnDeinit (i was switching timeframes there). I no longer have the exact same code that produced the logs in my original post, So it's hard to say if there is anything to worry about here. ObjectCreate is asynchronous, so (I can now see) it can actually happen:

//--- created 3 times without errors, 1 create event
int OnInit()
  {
   ChartSetInteger(0, CHART_EVENT_OBJECT_CREATE, true);
   ChartSetInteger(0, CHART_EVENT_OBJECT_DELETE, true); 
   string name="TestObj_OnInit";
   Create(name);  
   Create(name);
   Create(name);      
   Delete(name);
   ChartRedraw();           
   return(INIT_SUCCEEDED);
  }
void Check(string name){
   if(ObjectFind(0,name)>=0)Print(name+" found"); 
   else Print(name+" not found");      
  }   
void Create(string name){
   if(!ObjectCreate(0,name,OBJ_HLINE,0,TimeCurrent(),1.0))
      Print("ObjectCreate Error "+(string)_LastError);  
  }   
void Delete(string name){
   if(!ObjectDelete(0,name))      
      Print("ObjectDelete Error "+(string)_LastError); 
  }   

Create and delete events do fire even if the ChartRedraw is after Delete, so all is in line with whats documented. Although i think the documentation could make it clearer by explicitly pointing out that the chart events are only fired after chart redraw.

I don't have the time to play with this any further now, but when I originally discovered such behavior (i might have just missed a log entry) I was manually creating objects, while 1 millisecond timer was causing the interface lag so bad that I coudnt event move the lines smoothly. It involved detecting manually created objects and renaming them. If you want to understand my confusion, use

if(counter%5==0)
  {
   Print("redraw");
   ChartRedraw(); 
  }  

in the ea from my original post, change timeframes and delete objects manually by Ctrl+B -> List All -> Delete. Note that this way programmatically created objects can be deleted before they are actually drawn on the chart (havent tested if it changs event behaviour). 

I attached ChartObjects.mqh where you can find something to use for detecting a manually created object. Tested on MT5, if someone tests that with MT4, please repost with correct object names.

EDIT: Fixed the errors in the included file.

Files:
ChartObject.mqh  14 kb
 
bwa:

I'm talking about the line in my original post:

2018.03.04 09:21:29.397 ObjectCreateTest (GBPUSD,M5) OnTimer: Creating TestObj_29 ...

which never triggered OnChartEvent like

2018.03.04 09:21:31.952 ObjectCreateTest (GBPUSD,H4) OnChartEvent: TestObj_30 created

OnChartEvent: TestObj_29 created is missing.


I think it has something to do with the OnDeinit/OnDeinit (i was switching timeframes there). I no longer have the exact same code that produced the logs in my original post, So it's hard to say if there is anything to worry about here. ObjectCreate is asynchronous, so (I can now see) it can actually happen:

Create and delete events do fire even if the ChartRedraw is after Delete, so all is in line with whats documented. Although i think the documentation could make it clearer by explicitly pointing out that the chart events are only fired after chart redraw.

I don't have the time to play with this any further now, but when I originally discovered such behavior (i might have just missed a log entry) I was manually creating objects, while 1 millisecond timer was causing the interface lag so bad that I coudnt event move the lines smoothly. It involved detecting manually created objects and renaming them. If you want to understand my confusion, use

in the ea from my original post, change timeframes and delete objects manually by Ctrl+B -> List All -> Delete. Note that this way programmatically created objects can be deleted before they are actually drawn on the chart (havent tested if it changs event behaviour). 

I attached ChartObjects.mqh where you can find something to use for detecting a manually created object. Tested on MT5, if someone tests that with MT4, please repost with correct object names.

  1. The missing log doesn't have anything to do with the OnDeinit()/OnInit() but only with missing ChartRedraw() after every ObjectCreate(), ObjectDelete()... (see the new attached log with switching timeframes)
  2. 1 millisecond timer is total nonsense.
  3. If you create an object programmatically without using ChartRedraw() you can delete it before it appears on the chart.
  4. I think there is an easier way to detect manually created objects. E.G. comparing ObjectsTotal() to previous one.
Files:
LOG.txt  7 kb
 
Petr Nosek:
  1. The missing log doesn't have anything to do with the OnDeinit()/OnInit() but only with missing ChartRedraw() after every ObjectCreate(), ObjectDelete()... (see the new attached log with switching timeframes)
  2. 1 millisecond timer is total nonsense.
  3. If you create an object programmatically without using ChartRedraw() you can delete it before it appears on the chart.
  4. I think there is an easier way to detect manually created objects. E.G. comparing ObjectsTotal() to previous one.

1. And how can you tell that? The only reason I can see for the missing entry is that there was an existing object of the same name on the chart. If I understood you right, you aren't right in claiming that missing ChartRedraw() leaves create/delete events untriggered. Like I said, create events do trigger even if the object is deleted before chart redraw. And how would that be proper behaviour if it create events did'nt fire at all, for other objects but the one thats created last? All of the pending create and delete events are triggered at redraw, see logs.

2. Well firstly nothing prevents me from testing perfomance, and secondly I need it to check for callback request from dll (as far as i know setting a callback to dll is not possible?). Sure there is other ways, but this is the easy one.

3. Yea, got it.

4. And how would you distinguish an object created by another program from manually created one, using ObjectsTotal()? Even my method is not fail-proof in that sense.

Files:
log.txt  4 kb
 
bwa:

1. And how can you tell that? The only reason I can see for the missing entry is that there was an existing object of the same name on the chart. If I understood you right, you aren't right in claiming that missing ChartRedraw() leaves create/delete events untriggered. Like I said, create events do trigger even if the object is deleted before chart redraw. And how would that be proper behaviour if it create events did'nt fire at all, for other objects but the one thats created last? All of the pending create and delete events are triggered at redraw, see logs.

2. Well firstly nothing prevents me from testing perfomance, and secondly I need it to check for callback request from dll (as far as i know setting a callback to dll is not possible?). Sure there is other ways, but this is the easy one.

3. Yea, got it.

4. And how would you distinguish an object created by another program from manually created one, using ObjectsTotal()? Even my method is not fail-proof in that sense.

Maybe we only don't understand to each other.
  1. If you meant How can I tell that OnDeinit()/OnInit() has nothing to do with not catching in OnChartEvent() I'm convinced of that. If you want to catch object creating in OnChartEvent() safely you should call ChartRedraw() immediately after ObjectCreate(). If you don't do that you can't know when the object will be posted on the chart because the ObjectCreate() only inserts an object to queue and MT handles with it by its way. But ChartRedraw() causes processing this queue. I've never said that missing ChartRedraw() leaves create/delete events untriggered. I'm sorry but I don't understand your sentence: "And how would that be proper behaviour if it create events did'nt fire at all, for other objects but the one thats created last?". Of course all the pending events are triggered at ChartRedraw().
  2. OK if you want it you can set timer to one millisecond. I think 50ms or more is enough. But it depends.
  3. ???
  4. You are right. But don't forget another program can also create an object with same name like be created manually.

Have a nice day ;-)

Reason: