MT4 and MT5: OnTimer sometimes stops updating?

 

Hi all. 

I am seeing an intermittent problem on MT4 and MT5 (although it happens more on MT4 so far) where Initializing the Timer works fine, no errors, and the OnTimer function begins to work ok.  But then at some later point, OnTimer appears to stop updating/being triggered.  I am unsure of the dynamic, and have begun troubleshooting.  This is on VPS, 2 cores, 2 GB RAM, and usually has a very light load and the following image is a fair example. 


I have three instances of MT running on it:

  • MT4 (IG) 4.00 build 1402 2 Jan 2024
  • MT4 (OANDA) 4.00 build 1400 10 Nov 2023
  • MT5 (OANDA) 5.00 build 4127 12 Jan 2024

As of this writing, they are all recent and are fresh installs on the VPS within the last 2 weeks.

I have done a bit of searching for OnTimer issues, and I didn't find anything that seemed relevant except one theory mentioned below.

The EA that I have running has some maintenance functions that I am using the OnTimer function for, and most importantly a position closing function that I moved to OnTimer because I wanted daily positions to close by a certain time, whether or not there were incoming ticks.  The event timer is set to trigger every 10 seconds which is more than enough for the functions I want to trigger.  I thought this would be a better option when ticks might be sparse.  Among the visual functions are a time panel that I use to check to times, my "alarms" which trigger events, and which session is currently active.  See the example image below. (I am glad to be spotting this while testing in DEMO - all my test accounts are down on profit, in part because the closing is not occurring on the expected schedule.)

Yes, restarting the EA - as well as restarting the VPS and restarting the MT instances will all reset the OnTimer behavior.  But then at some point (hours or days later) it will break on any or all of the instances.  Sometimes one of the EAs on one instance will break, but the others will keep time with no issues.  It appears intermittent in all of these factors.

The time at which I took this screenshot (localtime on the VPS) was 9 am Eastern Time US.  None of those "Loc" times are consistent with it, the ones with the blue X.  You will also notice that the session ("TOK" or "LON" for Tokyo and London) are incorrect and inconsistent.  Again, note that when I initiate the EA, the time keeping works flawlessly at first: the various times keep up to date within the 10 second trigger.


My questions for those who know more than me:  Is this a bug?  Or are there techniques I should use to keep the OnTimer heartbeat going?  Or are there specific recommendations for troubleshooting? 

From another post I have seen on the forum, I got the idea that cpu utilization might become saturated at times on a VPS.  The theory in that case: it may have caused an error in OnTimer functionality.  Can anyone confirm that behavior?  (Sorry, but I did not save the link to that thread... I found it after some time of browsing through the forum. If I find it again in the future I will share it here  :(  )  I would be surprised if this were still a problem on up to date versions of MT, but maybe it is?

Many thanks in advance for all suggestions.

BTW: I am running the following EA to try to see if the issue occurs with very simple functionality. 

//+------------------------------------------------------------------+
//|                                                  Timertester.mq4 |
//|                        Copyright 2024, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict

datetime gmt = 0;
string comment = "";
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit() {
   gmt = TimeGMT();
   comment = TimeToString(gmt, TIME_DATE|TIME_SECONDS);
//--- create timer
   ResetLastError();
   if(!EventSetTimer(10)) Print("Timer not inited: ", _LastError);
//---
   return(INIT_SUCCEEDED);
   }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
//--- destroy timer
   EventKillTimer();
   }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick() {
//---
   if(gmt < TimeGMT() - 60) {
      comment = "OnTimer out of sync: gmt field " + TimeToString(gmt) + ", TimeGMT " + TimeToString(TimeGMT());
      Print(comment);
      }
   Comment(comment);
   ChartRedraw();
   }
//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer() {
//---
   gmt = TimeGMT();
   comment = TimeToString(gmt, TIME_DATE|TIME_SECONDS);
   }
//+------------------------------------------------------------------+
 

Perhaps this thread will be useful to someone else one day, so I will note my troubleshooting here.

I checked the state of the instances last night, just after some of my EA functions would have run at GMT 00:00.  Interestingly, all instances of MT4 and MT5 had not updated after midnight GMT, each instance runs 3 of these EAs that all have the same functionality.  The little piece of test code (in first post) was running without any issue.

This morning, the MT5 instance EAs had obviously started updating their timer processes at different points, and then each stopped at different times, nothing consistent.  The MT4 instance EAs were still stuck near GMT midnight.  The timer test code was still updating with no problems.


Troubleshooting:

  1. I reviewed the code, specifically double-checking for anything that might have reset the EventSetTimer() parameter.  There wasn't anything obvious of the sort, so this is ruled out.  Of course, maybe another function might be interfering with it...?  But like I said, nothing obvious.
  2. I tried putting EventSetTimer(10) in the OnTick() function to ensure the heartbeat stays alive like so:
    void OnTick() {
       EventSetTimer(10);
    }
    This does not work (the timed processes never update) and just yields an error (10) on MT4, which I could not find in the docs, the error codes go from 9 to 64.  MT5 does not report the error, but does not update.  So this will not work in either case.  I removed this code change.
  3. I changed OnTick() to always run the main loop.  This main loop runs all code related to checking whether it is time to execute my functions based on time of day, as well as checking to see it it is time to modify trades-in-flight or check for closes. 
    void OnTick() {
       Main();
      }
    And I updated the OnTimer() function to NOT run Main() but to execute panel updates and to check for closes:
    void OnTimer() {
    
       Update_Time_Info();
       Update_Session_Info();
       
       CheckForClose();
    }
    Making these changes this morning, all instances of MT4 started up and report no errors.
  4. As for the Timertester code I am using to see if a simplified EA can generate similar issues, I moved everything out of OnTick() and into OnTimer(), similar to how my strategy EA was set up initially.  The change looks like this:
    //+------------------------------------------------------------------+
    //|                                                  Timertester.mq4 |
    //|                        Copyright 2024, MetaQuotes Software Corp. |
    //|                                             https://www.mql5.com |
    //+------------------------------------------------------------------+
    #property copyright "Copyright 2024, MetaQuotes Software Corp."
    #property link      "https://www.mql5.com"
    #property version   "1.00"
    #property strict
    
    datetime gmt = 0;
    string comment = "";
    //+------------------------------------------------------------------+
    //| Expert initialization function                                   |
    //+------------------------------------------------------------------+
    int OnInit() {
       gmt = TimeGMT();
       comment = TimeToString(gmt, TIME_DATE | TIME_SECONDS);
    //--- create timer
       ResetLastError();
       if(!EventSetTimer(10)) Print("Timer not inited: ", _LastError);
    //---
       return(INIT_SUCCEEDED);
      }
    //+------------------------------------------------------------------+
    //| Expert deinitialization function                                 |
    //+------------------------------------------------------------------+
    void OnDeinit(const int reason) {
    //--- destroy timer
       EventKillTimer();
      }
    //+------------------------------------------------------------------+
    //| Expert tick function                                             |
    //+------------------------------------------------------------------+
    void OnTick() {
    //---
    
      }
    //+------------------------------------------------------------------+
    //| Timer function                                                   |
    //+------------------------------------------------------------------+
    void OnTimer() {
    //---
       gmt = TimeGMT();
       comment = TimeToString(gmt, TIME_DATE | TIME_SECONDS);
    //if(gmt < TimeGMT() - 60) {
    //comment = "OnTimer out of sync: gmt field " + TimeToString(gmt) + ", TimeGMT " + TimeToString(TimeGMT(), TIME_DATE|TIME_SECONDS);
    //Print(comment);
    //}
       Comment(comment);
       ChartRedraw();
      }
    //+------------------------------------------------------------------+
    


To start afresh, I restarted my VPS as well.  I will see what these changes bring. 

 

Troubleshooting has brought about partial success.

  1. The first thread of troubleshooting is to see what can keep my main EAs running, while still making use of the OnTimer function to help ensure that trade closes happen on schedule.  The changes made in step 3 (in post #2, above) seem to have prevented the EAs from "stalling out" and they continue to run without issue.  Driving from OnTick seems to have helped.  The panel times keep updating, and since the trade closures are called from OnTimer, I expect that this occurs on schedule as well.  Trade closes happened at their normal times, per the logs.  (After I am done with troubleshooting, I may call for trade closures from both OnTick and OnTimer to make sure that whether the ticks are sparse or not, closures happen.)
    • Triggering the main loop from OnTick seems to keep the EA alive, and is a good heartbeat. 
    • Since the rest of the code operates smoothly from OnTick, it seems that the rest of the code is sound - nothing is causing general failure that could be root cause.
    • If the EA runs stable over the next week, I will feel that the issue is resolved.  So this may be a successful resolution. 
  2. The second thread of troubleshooting is to find out why this is happening in the first place.  Here is my suspicion: The vps cpus are getting saturated for a duration that exceeds the EventSetTimer second count, which is 10 seconds for my EA.  I am guessing that if the CPUs are busy with processing for longer than the EventSetTimer period, OnTimer may have an unrecoverable error.  So, I re-wrote my tester to purposefully saturate the cpus for a set number of function iterations, and it is driven from the OnTimer function. I created array filling operations that would be guaranteed to suck all the cycles out of the vps to 100% for a long duration of time far exceeding the 10 second period.
    • An interesting note about performance during the test.  I happened to trigger these tests on MT4 first, then MT5.  It is clear that Windows 10 server gives precedence to the first MT instance that runs this overwhelming test.  The green OANDA MT4 just happened to be initiated first, then IG MT4, and then the MT5 instance.  OANDA finished first after almost half an hour of operation of 10k iterations of the performance test.  IG MT4 is exceeding an hour at only 8k iterations, and MT5 is not only a cycle AND memory hog, but it is going the slowest at only 117 iterations after an hour.  Prior to this I was under the impression that Win 10 gave similar precedence to all concurrently running user applications.
    • Another interesting thing to note is that MT5 was running much more slowly even after the other MT4 instances were complete.  The other instances could complete at least two iterations per second - and up to 5 iterations per second if they had precendence.  Even after shutting down MT5 and restarting it, MT 5 only ran one iteration in 1m 20s.  MT5 is much slower at this operation than I initially guessed it would be.
    • When the performance test is done , the normal OnTimer operations continue after the test finishes its iterations and continues to refresh the on screen comment.  So, I am not closer to understanding the root cause of the issue and this is a partial failure in that regard.
    • On the other hand, while running three performance stress tests simultaneously on the vps, I also noticed that it did not disrupt regular operations of the other EAs running on the same set of instances (now driven from OnTick, as mentioned above.)  This is a success for OnTick vs OnTimer.


My informal conclusion so far is that OnTick is generally more reliable.  Some operations (as yet unknown to me) will cause a glitch in OnTimer operations, and I will not rely on OnTimer alone to drive EA processes.

The latest performance/stress test EA I used is here.  It compiles on both MT4 and MT5 as-is, but apparently is even less efficient on MT5 than MT4.

//+------------------------------------------------------------------+
//|                                                  Timertester.mq4 |
//|                        Copyright 2024, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict

input int testcycles = 10000;
datetime gmt = 0;
string comment = "";
bool saturated = false;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit() {
   gmt = TimeGMT();
   comment = TimeToString(gmt, TIME_DATE | TIME_SECONDS);
//--- create timer
   ResetLastError();
   if(!EventSetTimer(10)) Print("Timer not inited: ", _LastError);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
//--- destroy timer
   Comment("timertester removed");
   EventKillTimer();
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick() {
//---

  }
//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer() {
//---


   gmt = TimeGMT();
   comment = TimeToString(gmt, TIME_DATE | TIME_SECONDS);
//if(gmt < TimeGMT() - 60) {
//comment = "OnTimer out of sync: gmt field " + TimeToString(gmt) + ", TimeGMT " + TimeToString(TimeGMT(), TIME_DATE|TIME_SECONDS);
//Print(comment);
//}
   Comment(comment);
   ChartRedraw();
   
   if(!saturated) {
      for(int i = 0; i < testcycles; i++) {
         double arr1[], arr2[], arr3[];
         for(int j = 0; j < iBars(_Symbol, PERIOD_CURRENT) - 1; j++) {
            ArrayResize(arr1, ArraySize(arr1) + 1);
            ArrayResize(arr2, ArraySize(arr2) + 1);
            ArrayResize(arr3, ArraySize(arr3) + 1);
            arr1[j] = iHigh(_Symbol, PERIOD_CURRENT, j) - iLow(_Symbol, PERIOD_CURRENT, j);
            arr2[j] = double(iVolume(_Symbol, PERIOD_CURRENT, j) - iVolume(_Symbol, PERIOD_CURRENT, j + 1));
            arr3[j] = iClose(_Symbol, PERIOD_CURRENT, j) - iClose(_Symbol, PERIOD_CURRENT, j + 1);
           }
         Print("Done: ", i);
        }
      saturated = true;
     }
  }
//+------------------------------------------------------------------+
 

It has been over a week since the last changes to the code. 

  • Driving the logic from OnTick() vs OnTimer() definitely brought stability.  Not a single issue over the last week, vs multiple EA "freezes" in a day before I made the change.
  • I reviewed the code for anything that could have caused an issue with Timer functionality, and could not find any obvious code that would be a culprit.
  • I still suspect that cpu cycles might have been the choke point, and it seems to affect OnTimer more than OnTick, or at least OnTick can recover easier.


I will definitely depend on OnTick() for future coding, and use OnTimer only as a redundancy.

 
OnTimer() has a very large delay. How to solve it? - My program doesn’t work, but I'm very surprised with the delay in my timer; How To Ask Questions The Smart Way
OnTimer() has a very large delay. How to solve it? - My program doesn’t work, but I'm very surprised with the delay in my timer; How To Ask Questions The Smart Way
  • 2023.07.27
  • www.mql5.com
Is there any way to get a reliable timer. Timer is reliable, but probably your code don't work correctly. See my countdown timer (mt4) indicators: zero lag timer - indices - articles, library comments - mql5 programming forum #8 (20 17 ) this way causes too many log. Your code is very good to get accurate timer only if ontimer() is called expectedly