Possible bug in TimeTradeServer - page 2

 

Martin Bittencourt
:

Hi,

I'm developing an alert/alarm system which is supposed to trigger when a certain datetime set by the user is reached. For debugging, I'm using my scenario here in Brazil where the stock exchange's and broker's timezone is GMT-3h, the live market opens at 10AM, the futures opens at 9AM and I'm opening by Terminal around 8:55AM. So what I'm doing is trying to calculate the difference in seconds between the moment when the indicator is loaded at the opening of the Terminal's and the desired time (10AM, in my test) and call EventSetTimer on that difference.

Simply put, the code is as follows:

I've been testing this code for a while now and most of the time it runs fine, but in some days like today, it doesn't. For instance, yesterday I opened the Terminal at 08:04:30 and got a diffInSecs of 6930, so 115,5 min or 1,925h which is precisely the time difference from 08:04 until 10:00. But today I opened my Terminal at 08:54:22 and got diffInSecs of 14738, thus 245,63 min or 4,09 hours, which basically means the aprox. 1h of difference until my goal of 10AM plus 3h like if the GMT part wasn't working properly. 

So, what could be happening here? This isn't the first time this problem happened, the reason why I had a debug Print placed in the first place, but usually things go fine and the alert is triggered when it's suppose to.

I am sorry for my previous responses. I re-checked and it seems to be a bug that affects TimeTraderServer() only inside indicators. Specifically, the bug occurs when the terminal is launched with an indicator ( that calls TimeTradeServer() ) is attached to the chart.

The returned value of TimeTradeServer() is wrong. It becomes equal to TimeGMT() inside OnInit() and also during the first 2 or 3 ticks until the terminal connects to the trade server (connected sound).

This is an obvoius bug in TimeTradeServer() in indicators.  I file this bug report for MT5 developers team.

NOTICE: I checked experts advisors, luckily the bug DOES NOT happen there.

//+------------------------------------------------------------------+
//|                                         TimeTradeServer_indi.mq5 |
//|                                        Copyright © 2018, Amr Ali |
//|                             https://www.mql5.com/en/users/amrali |
//+------------------------------------------------------------------+
#property indicator_chart_window
#property indicator_buffers 0
#property indicator_plots   0

int msg=0;

int OnInit()
  {
   Print(__FUNCTION__+": is called.");
   ShowTimes();
   return (INIT_SUCCEEDED);
  }

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(++msg < 4)
     {
      Print(__FUNCTION__+": is called.");
      ShowTimes();
     }
   return(0);
  }

void ShowTimes()
  {
   datetime tts = TimeTradeServer();
   datetime gmt = TimeGMT();
   int BrokerOffset = (int)(tts - gmt);
   PrintFormat("  Server            = %s", AccountInfoString(ACCOUNT_SERVER));
   PrintFormat("  TimeTradeServer() = %s", string(tts));
   PrintFormat("  TimeGMT()         = %s", string(gmt));
   PrintFormat("  BrokerOffset      = %d (GMT%+g)", BrokerOffset, BrokerOffset/3600.0);
  }

output:

// 2024.04.05 02:04:58.685      TimeTradeServer_indi (EURUSD,M1)        OnInit: is called.
// 2024.04.05 02:04:58.685      TimeTradeServer_indi (EURUSD,M1)          Server            = ICMarketsSC-Demo
// 2024.04.05 02:04:58.685      TimeTradeServer_indi (EURUSD,M1)          TimeTradeServer() = 2024.04.05 00:04:58
// 2024.04.05 02:04:58.685      TimeTradeServer_indi (EURUSD,M1)          TimeGMT()         = 2024.04.05 00:04:58
// 2024.04.05 02:04:58.685      TimeTradeServer_indi (EURUSD,M1)          BrokerOffset      = 0 (GMT+0)
// 2024.04.05 02:04:58.685      TimeTradeServer_indi (EURUSD,M1)        OnCalculate: is called.
// 2024.04.05 02:04:58.685      TimeTradeServer_indi (EURUSD,M1)          Server            = ICMarketsSC-Demo
// 2024.04.05 02:04:58.685      TimeTradeServer_indi (EURUSD,M1)          TimeTradeServer() = 2024.04.05 00:04:58
// 2024.04.05 02:04:58.685      TimeTradeServer_indi (EURUSD,M1)          TimeGMT()         = 2024.04.05 00:04:58
// 2024.04.05 02:04:58.685      TimeTradeServer_indi (EURUSD,M1)          BrokerOffset      = 0 (GMT+0)
// 2024.04.05 02:05:00.282      TimeTradeServer_indi (EURUSD,M1)        OnCalculate: is called.
// 2024.04.05 02:05:00.282      TimeTradeServer_indi (EURUSD,M1)          Server            = ICMarketsSC-Demo
// 2024.04.05 02:05:00.282      TimeTradeServer_indi (EURUSD,M1)          TimeTradeServer() = 2024.04.05 03:05:00
// 2024.04.05 02:05:00.282      TimeTradeServer_indi (EURUSD,M1)          TimeGMT()         = 2024.04.05 00:05:00
// 2024.04.05 02:05:00.282      TimeTradeServer_indi (EURUSD,M1)          BrokerOffset      = 10800 (GMT+3)
// 2024.04.05 02:05:00.931      TimeTradeServer_indi (EURUSD,M1)        OnCalculate: is called.
// 2024.04.05 02:05:00.931      TimeTradeServer_indi (EURUSD,M1)          Server            = ICMarketsSC-Demo
// 2024.04.05 02:05:00.931      TimeTradeServer_indi (EURUSD,M1)          TimeTradeServer() = 2024.04.05 03:05:00
// 2024.04.05 02:05:00.931      TimeTradeServer_indi (EURUSD,M1)          TimeGMT()         = 2024.04.05 00:05:00
// 2024.04.05 02:05:00.931      TimeTradeServer_indi (EURUSD,M1)          BrokerOffset      = 10800 (GMT+3)
 

Is it really a bug or is it just that until connection to the trade server, the function doesn't have data from the server to tell what its hourly time would be?

Also, TimeCurrent is the only reliable way, in my experience, to get the actual server time. However, without ticks, it will not update. In a tickless environment, TimeTradeServer will give a reasonable estimate (if connection to the server can be established), unless the PC clock of the machine running the MQL5 program is way off.

I do not like the idea of snapshotting time once, at program start, and then using that as the basis for market/server time alerts. This is highly non-robust and could easily fail. I think it's better to run a loop on a timer, that checks TimeCurrent, and notes the offset between TimeCurrent and TimeTradeServer. Using this offset, TimeTradeServer can be used to keep tab on time, without needing ticks. But in order for this offset to be accurate, you must calculate it at the precise moment TimeCurrent changes, so that you can be sure you're getting an accuracy of TimeCurrent (server time) that is within ~1 second. Then, of course, you could also have almost a second of additional inaccuracy if the moment TimeCurrent changes, is toward the end of the current second of the local PC time ;) If a couple seconds doesn't matter, then this is fine.

It should also be noted, that if the local PC time setting is changed, perhaps automatically by the OS to calibrate it, or manually by the user, this will require recalculation, which is where the loop comes in. I've also personally witnessed the MetaQuotes demo server recalibrate its time after a daychange and it became very closely aligned (within 15-16ms) of my PC time which I had recently updated from online, after the server/PC time were different by a couple hundred milliseconds. This means that the trade server itself sometimes changes its time setting, I imagine, during day change switchover times when the markets are pretty much all closed. Once again, this is why a constant loop is more reliable.

With a constant timer loop, the program can keep tabs on both server time and local time, so on one hand, it doesn't have to be dependent on ticks to know what the server time should be, but at the same time, it can be as accurate as possible with what the server time should be, by getting new time data from the server regularly that verifies the offset between server/local is kept relatively accurate.

 
Max0r847 #:

Is it really a bug or is it just that until connection to the trade server, the function doesn't have data from the server to tell what its hourly time would be?

In the documentation of TimeTradeServer: Returns the calculated current time of the trade server. Unlike TimeCurrent()the calculation of the time value is performed in the client terminal and depends on the time settings on your computer.

I think it should be stated also that "TimeTradeServer is not reliable in OnInit() and OnCalculate() for indicators."

Or do I have to use my intuition to realize that ;)
I know how to fix it, but probably others did not know that there is even a bug here.

Edit: 
I prefer there is a compiled list on the documentations page for platform functions that should not be used (or used with caution!) inside indicators. 😀 

Edit2:
So do you suggest to re-invent the TimeTradeServer function from scratch?!
 
amrali #:

In the documentation of TimeTradeServer: Returns the calculated current time of the trade server. Unlike TimeCurrent()the calculation of the time value is performed in the client terminal and depends on the time settings on your computer.

I think it should be stated also that "TimeTradeServer is not reliable in OnInit() and OnCalculate() for indicators."

Or do I have to use my intuition to realize that ;)
I know how to fix it, but probably others did not know that there is even a bug here.

Edit: 
I prefer there is a compiled list on the documentations page for platform functions that should not be used (or used with caution!) inside indicators. 😀 

Edit2:
So do you suggest to re-invent the TimeTradeServer function from scratch?!

It is true that TimeTradeServer uses local time for minutes/seconds, but without being connected to a server, it has no data for the hour portion of the time. The hour part of the time comes from what the program knows about the trade server.

This video I just recorded demonstrates what happens if the terminal/program is started in a disconnected state (I unpluged my ethernet cable). It shows the hour time as GMT 0, and the only reason it managed to do that, I believe, is because my system had its time zone set, which it read from and determined GMT based on the offset. Then, while recording, I plugged the cable back in, and when the terminal connects, it changes the hourly portion of that time to reflect the server's time zone.


So it appears the documentation does not describe TimeTradeServer's behavior when the terminal has no data from the server. Of course it will not be reliable if this is the case. It will only be reliable once a connection has been established and it downloads that data from the server.

As far as what I suggest, I would say both MetaQuotes and programmers have something to do. MetaQuotes can set TimeTradeServer to return a specific result that indicates it has no data from the server, to make it easier to know that. As far as us programmers go, the best we can do is run it on an OnTimer function loop, say once per second, and keep it auto-updated that way. As long as the terminal was connected to the given server just once, long enough to receive that timezone data from it, that's all it needs to keep that hour time accurate afterward, until restarting the terminal, except when there's a DST event :D

 

I thought a little bit about the issue of flying around the world with a mobile device, switching from timezone to timezone in terms of physical location. We do not know if the mobile device will automatically update its system time or not. However, once TimeTradeServer() has received info from the trade server about its GMT offset, as long as the terminal is still running, it should remain accurate in terms of the hour, save for any system clock drift, which would likely be trivial. The only problem is, what if the user's system clock is severely off in terms of minutes, and there are no recent ticks from the trade server? In this case, I imagine the only programmable solution would be to use some kind of outside DLL or whatever, to pull accurate time from some other source than the trade server or the local system time.

This may be a niche concern, since likely most peoples' mobile devices will update time automatically, and won't ever drift far enough to matter. But you never know just when someone's device may have a really wonky time for some reason :P

 
Max0r847 #:

I thought a little bit about the issue of flying around the world with a mobile device, switching from timezone to timezone in terms of physical location. We do not know if the mobile device will automatically update its system time or not. However, once TimeTradeServer() has received info from the trade server about its GMT offset, as long as the terminal is still running, it should remain accurate in terms of the hour, save for any system clock drift, which would likely be trivial. The only problem is, what if the user's system clock is severely off in terms of minutes, and there are no recent ticks from the trade server? In this case, I imagine the only programmable solution would be to use some kind of outside DLL or whatever, to pull accurate time from some other source than the trade server or the local system time.

This may be a niche concern, since likely most peoples' mobile devices will update time automatically, and won't ever drift far enough to matter. But you never know just when someone's device may have a really wonky time for some reason :P

Please see this https://www.mql5.com/en/forum/464678#comment_52861161

Even if the terminal is connected to the server but system time is wrong, all times on the terminal are wrong (except TimeCurrent).  So the analogy of mobile phone updating its time from the internet is not right here

 
amrali #:
Please see this https://www.mql5.com/en/forum/464678#comment_52861161

Even if the terminal is connected to the server but system time is wrong, all times on the terminal are wrong (except TimeCurrent).  So the analogy of mobile phone updating its time from the internet is not right here

It's not an analogy. I'm saying if the computer's time is far off in terms of minutes, only a TimeCurrent update will fix that in terms of internal MT5 programming, while if TimeTradeServer received the GMT offset from the trade server, it will set the hour correctly, unless there was a disconnect/DST event after that without a reconnection. However, the minutes/seconds will still be off.

So for my own time operations for trading related things, standard practice (because I'm still a newbie goober that hasn't used DLLs and stuff yet) is to simply create a flashing object notice, or alert, plus auto-offset, if system time is shown to be off from TimeCurrent in terms of minutes/seconds and to run time calibration/verification operations on a regular basis in OnTimer. It doesn't matter if it's once per hour or 20 times per second, as long as it happens multiple times per day. This would be a reminder to fix the time on the PC, or to just let the time be really off in terms of minutes, and auto-correct for that. The MQL5 program would continually keep track of the minute/second offset (or even millisecond/microsecond offset, if being fancy) between server time and local time.

The only purpose of TimeTradeServer is to be able to time things in relation to the trade server when ticks stop, which will be accurate as long as the proper calibrations/offsets are maintained, and there is sufficient window of access to the server to witness a new market tick every once in a while to give the program a chance to maintain accurate calibration.

 
Max0r847 #:

It's not an analogy. I'm saying if the computer's time is far off in terms of minutes, only a TimeCurrent update will fix that in terms of internal MT5 programming, while if TimeTradeServer received the GMT offset from the trade server, it will set the hour correctly, unless there was a disconnect/DST event after that without a reconnection. However, the minutes/seconds will still be off.

So for my own time operations for trading related things, standard practice (because I'm still a newbie goober that hasn't used DLLs and stuff yet) is to simply create a flashing object notice, or alert, plus auto-offset, if system time is shown to be off from TimeCurrent in terms of minutes/seconds and to run time calibration/verification operations on a regular basis in OnTimer. It doesn't matter if it's once per hour or 20 times per second, as long as it happens multiple times per day. This would be a reminder to fix the time on the PC, or to just let the time be really off in terms of minutes, and auto-correct for that. The MQL5 program would continually keep track of the minute/second offset (or even millisecond/microsecond offset, if being fancy) between server time and local time.

The only purpose of TimeTradeServer is to be able to time things in relation to the trade server when ticks stop, which will be accurate as long as the proper calibrations/offsets are maintained, and there is sufficient window of access to the server to witness a new market tick every once in a while to give the program a chance to maintain accurate calibration.

The main point here is not how to fix TimeTradeServer or time calibrations, but about the unexpected behavior (not stated in the docs) when the indicator/expert advisor is not connected to the trade server.

 
Martin Bittencourt:

Hi,

I'm developing an alert/alarm system which is supposed to trigger when a certain datetime set by the user is reached. For debugging, I'm using my scenario here in Brazil where the stock exchange's and broker's timezone is GMT-3h, the live market opens at 10AM, the futures opens at 9AM and I'm opening by Terminal around 8:55AM. So what I'm doing is trying to calculate the difference in seconds between the moment when the indicator is loaded at the opening of the Terminal's and the desired time (10AM, in my test) and call EventSetTimer on that difference.

Simply put, the code is as follows:

I've been testing this code for a while now and most of the time it runs fine, but in some days like today, it doesn't. For instance, yesterday I opened the Terminal at 08:04:30 and got a diffInSecs of 6930, so 115,5 min or 1,925h which is precisely the time difference from 08:04 until 10:00. But today I opened my Terminal at 08:54:22 and got diffInSecs of 14738, thus 245,63 min or 4,09 hours, which basically means the aprox. 1h of difference until my goal of 10AM plus 3h like if the GMT part wasn't working properly. 

So, what could be happening here? This isn't the first time this problem happened, the reason why I had a debug Print placed in the first place, but usually things go fine and the alert is triggered when it's suppose to.

The approach you've described looks generally correct, but there are a few potential pitfalls here.

You need to ensure that you're correctly accounting for timezones in your calculations. If your broker's timezone is GMT-3, you need to adjust the current time accordingly to get the time in GMT. You seem to be doing this by subtracting 3 hours, which is correct. However, you should also ensure that the goal time is in GMT as well. Check if there are any changes in the time zone due to daylight saving time adjustments. This could affect the calculation if not accounted for properly.

Also make sure that the time reported by TimeTradeServer() corresponds to the time on your trading terminal and is accurate. Sometimes discrepancies in terminal time can occur due to synchronization issues or incorrect system settings. And, Ensure that you're testing your code under consistent conditions. Variations in network latency or server load could affect the accuracy of your timing calculations. Consider adding more logging and debugging statements to your code to better understand what might be causing the discrepancies on days when the calculations don't match your expectations. This could help pinpoint any specific issues that need to be addressed.

 
Martin Bittencourt:
I've been testing this code for a while now and most of the time it runs fine, but in some days like today, it doesn't. For instance, yesterday I opened the Terminal at 08:04:30 and got a diffInSecs of 6930, so 115,5 min or 1,925h which is precisely the time difference from 08:04 until 10:00. But today I opened my Terminal at 08:54:22 and got diffInSecs of 14738, thus 245,63 min or 4,09 hours, which basically means the aprox. 1h of difference until my goal of 10AM plus 3h like if the GMT part wasn't working properly. 

This is exactly the bug I described. TimeTradeServer() is unerliable for the first few tick after the terminal is launched wth an indicator that uses TimeTradeServer() is attached to the chart. What happened is the TimeTradeServer returned the TimeGMT instead. So that the obseved time difference included additional 3 hours.

For a better approach: check the terminal is connected to the trade server before using TimeTradeServer in indicators/experts

if(!TerminalInfoInteger(TERMINAL_CONNECTED))
  {
   Print("Caution: Terminal is not connected, TimeTradeServer will be unreliable.");  
  }
  
//--- now it is safe to use the function
datetime t = TimeTradeServer();

I suggest that TimeTradeServer() should be fixed to return 0 instead of TimeGMT, if the connection to the trade server is not yet established.

This will warn users that something wrong happened. Also setting the _LastError variable would be a good idea.

Reason: