4

How can I get current milliseconds from MQL4 using an Expert Advisor.

i.e.: in Java we can get current milliseconds using system.currenttimemillis()

Stanislav Kralin
  • 11,070
  • 4
  • 35
  • 58
Nitin
  • 2,701
  • 2
  • 30
  • 60
  • A constant absolute error precise timing solution is provided below. No blocking, no unpredictable randomness, no jitter, no wander, nothing as from using `OnTimer()`-hung event-driven lottery-machine. **Simply exact down to the microsecond [ even when you ask for millis :o) ].** – user3666197 Jun 12 '17 at 23:58

6 Answers6

3

This MT4 "Get millisecond" problem has been around for ages. This is a hack I created to solve this problem.

//+------------------------------------------------------------------+
//|                                                     timeInMs.mq4 |
//|                                       Copyright 2017, Joseph Lee |
//+------------------------------------------------------------------+
#property copyright "Copyright 2017, Joseph Lee"
#property link      "https://www.facebook.com/joseph.fhlee"
#property version   "1.00"
#property strict

int     prevSecondTime      = 0;
uint    prevSecondTick      = 0;


int OnInit()    {
    // Create an Event that triggers every 1 millisecond.
    // **NOTE: GetTickCount() is accurate to 16ms only, so
    // in practice, no need to trigger every 1ms.
    EventSetMillisecondTimer(1);
    return(INIT_SUCCEEDED);
}

void OnTick() {
    Comment( "Now: " + TimeLocal() + " :: " + getCurrentMs() + " ms. +- 16ms accuracy.");
}

int getCurrentMs() {
    return(GetTickCount() - prevSecondTick);
}

// This is an EVENT function that will be called every
// x milliseconds [see EventSetMillisecondTimer() in OnInit()]
void OnTimer() {
    // If a new "second" occurs, record GetTickCount()
    if(TimeLocal() > prevSecondTime) {
        prevSecondTick  = GetTickCount();
        prevSecondTime  = TimeLocal();
    }
}
Lutz Prechelt
  • 36,608
  • 11
  • 63
  • 88
jlee88my
  • 2,935
  • 21
  • 28
  • This solution works for me. I user `TimeGMT()` and convert this time string to the current millisecond in my node application. – Nitin Jun 10 '17 at 03:59
  • 1
    **If it were true**, what your *(cit.:)* **"`// **NOTE: GetTickCount() is accurate to +-16ms only,`"** says, there would be absolutely no sense for sub-millisecond TimeDOMAIN resolution, as is available from **`GetMicrosecondCount()`**, which is obviously a contradiction, due to which reason the initial hypothesis was just proven to be wrong ( and the problem is in the `OnTimer()` in-accuracy, not in the `GetTickCount()` nor the `GetMicrosecondCount()` ). **Q.E.D.** – user3666197 Jun 12 '17 at 20:49
  • 1
    Did I mention **this will never work in Strategy Tester** mode? – user3666197 Jun 12 '17 at 21:03
  • You are over-conplocating stuffs :) It works for 98% of scenarios. If we want to be 'precise', we need to also sync the PC's time to the atomic clock (Windows time has accuracy to 30s). But this works for most usage. Of course, I am open to better alternative solutions. – jlee88my Jun 12 '17 at 23:08
  • Don't tell me, man, you do not synchronise your FOREX platforms to at least a pair of STRATUM-1 reference clocks + use a continuous CLOCK_MONOTONIC correction service in 24/7/365 mode? – user3666197 Jun 12 '17 at 23:54
  • I do, and I know you do too :) BUT 99% of most out there don't (nor do they have a clue what you're talking about :D ) – jlee88my Jun 12 '17 at 23:56
  • Well, in case one wants to run event analyses, then you need precise, absolute time, which only enables any **microsecond-aligned** event-log merging into a robust, well time-aligned, **Sequence-of-Events**. Not doing this job right enough will generate just a wreck-havoc, not a serious journal, where a cause-effect ordering is assured. **Anybody can imagine a value of such nonsensical Havoc-instead-of-The-Journal** :o) Anyway, stay tuned! – user3666197 Jun 13 '17 at 00:11
  • The scary thing is that I'm not sure whether or not you guys are joking about the computer STRATUM-1 sync, but in case you are not, how would you do that? – not2qubit Jan 06 '20 at 17:36
  • 2
    @not2qubit , it is not a joke. You need to sync your PC time. Otherwise, you're out by multiple seconds which won't work for high-precision operations like news event trading. You can try http://www.timesynctool.com/ and set it to resync frequently. – jlee88my Jan 08 '20 at 06:46
2

Can have relative [ms] or even [us]:

Be careful as both are relative, but one with respect to the system start, the other with respect to the MQL4 code-execution unit start.

The GetTickCount() function returns the number of milliseconds that elapsed since the system start.

uint GetTickCount();

Counter is limited by the restrictions of the system timer. Time is stored as an unsigned integer, so it's overfilled every 49.7 days if a computer works uninterruptedly.


The GetMicrosecondCount() function returns the number of microseconds that have elapsed since the start of MQL program.

ulong GetMicrosecondCount();


Can have absolute [ms] or even [us], with const(!) ABSOLUTE ERROR,

that will exhibit neither any drift, nor jitter in exact measuring of time.

Isn't this great for FOREX domain, where milliseconds are "full of events" and microseconds ( nanoseconds in recent professional-grade designs ) matter ?!

// -----------------------------------------------------------------
ulong system_currenttimemillis(){
      return(   OnStart_GLOB_MILLISECONDS       // ABS [ms] SYNC-ed OnStart() WITH [s]-EDGE-ALIGNMENT
            + (           GetMicrosecondCount() // + DELTA ------------------
              - OnStart_BASE_MICROSECONDS       //   since SYNC-ing OnStart()
                ) / 1000 // =================== //   DELTA [ms] =============
              );
}
// -----------------------------------------------------------------
static ulong    OnStart_GLOB_MICROSECONDS;
static ulong    OnStart_GLOB_MILLISECONDS;
static ulong    OnStart_EoDY_MICROSECONDS;
static datetime OnStart_EoDY_DATETIME;
static datetime OnStart_BASE_DATETIME;
static uint     OnStart_BASE_MILLISECONDS;
static ulong    OnStart_BASE_MICROSECONDS;
// -----------------------------------------------------------------
void            OnStart(){ /* { SCRIPT | EXPERT ADVISOR | CUSTOM INDICATOR } CALL
                                                                             THIS */
                OnStart_BASE_DATETIME      = TimeLocal();           // .SET int == the number of seconds elapsed since January 01, 1970.
         while( OnStart_BASE_DATETIME     == TimeLocal() ){ // ---- // EDGE-ALIGNMENT -------------------------------------------------------
                OnStart_BASE_MICROSECONDS  = GetMicrosecondCount(); //      .SET ulong, since MQL4 program launch
                OnStart_BASE_MILLISECONDS  = GetTickCount();        //      .SET uint,  since system start
         } // ==[ MAX 1 SECOND ]=============================== NOW // EDGE-ALIGNED TO [s] ==================================================
                OnStart_BASE_DATETIME      = TimeLocal();           // .SET date and time as the number of seconds elapsed since January 01, 1970.
                OnStart_GLOB_MICROSECONDS  = (       (ulong) OnStart_BASE_DATETIME ) * 1000000;
                OnStart_GLOB_MILLISECONDS  = (       (ulong) OnStart_BASE_DATETIME ) * 1000;
                OnStart_EoDY_DATETIME      =                 OnStart_BASE_DATETIME
                                           - (               OnStart_BASE_DATETIME % 86400 );
                OnStart_EoDY_MICROSECONDS  = (   TimeSecond( OnStart_BASE_DATETIME )
                                             + ( TimeMinute( OnStart_BASE_DATETIME )
                                               + TimeHour(   OnStart_BASE_DATETIME ) * 60 ) * 60 ) * 1000000;
}
// -----------------------------------------------------------------
int OnInit()    {
    OnStart();             /*   HACK 4 { EXPERT ADVISOR | CUSTOM INDICATOR } CALL
    ...                                                                      THAT */
    ..
    return( INIT_SUCCEEDED );
}
// -----------------------------------------------------------------
ulong Get_a_Microsecond_of_a_Day(){           // THIS HAS A !!_CONSTANT_!! ONLY ABSOLUTE SYSTEMATIC TIMING ERROR
      return( (   OnStart_EoDY_MICROSECONDS   // EDGE-SYNC OnStart_EoDY + DELTA-SINCE-OnStart-SYNC-ed:
              + (           GetMicrosecondCount()                       // == NOW ( 8B ulong ) ROLL-OVER ~ 213M504 DAYS AFTER THE PROGRAM START, WAY LONGER, THAN WE WILL LIVE UNDER THE SUN
                - OnStart_BASE_MICROSECONDS   //                        //  - OnStart_BASE_MICROSECONDS
                  )
                ) // ================== // SECONDS-EDGE-SYNC-ed DISTANCE FROM EoDY-EDGE
              % 86400000000             // MODULO DAY-LENGTH ROLL-OVER
              );                        // ALL DST-MOVs TAKE PLACE OVER WEEKENDS, SO NOT DURING TRADING-HOURS, SHOULD BE JUST-ENOUGH GOOD SOLUTION :o)
}
// -----------------------------------------------------------------
uint Get_a_Millisecond_of_a_Day(){      // IMMUNE TO A uint ROLL-OVER ~ 49.7 DAYS
     return( Get_a_Microsecond_of_a_Day()
           / 1000
             );
}
  • This solution runs in all { Script | Expert Advisor | Custom Indicator }

Gerard Bosch
  • 648
  • 1
  • 7
  • 18
user3666197
  • 1
  • 6
  • 50
  • 92
  • 1
    I do not force you, Sir, to consider it *( cit.: )* "what you need". I help you find, what is available in MetaTrader4 Terminal Ecosystem. This is built in. The rest is to be designed & implemented ( from a private custom ntp client, to a self-adjusting local clock, using "just" relative [ms] or [us] timers ). – user3666197 May 23 '17 at 17:14
0

something like this:

ulong time = GetTickCount(); // function(); time = GetTickCount()-time;

Daniel Kniaz
  • 4,603
  • 2
  • 14
  • 20
  • Not working. `ulong time=GetTickCount(); time=GetTickCount()-time; Print("Time : ", time); `. It always print 0 – Nitin May 23 '17 at 16:28
  • maybe because 0 milliseconds between the operations? look: https://gyazo.com/717aae7eb5d9f0ccd7693a892243c916 it was sleeping ~160ms, and prints 156. I think GetTickCount() is more accurate then Sleep() – Daniel Kniaz May 23 '17 at 17:50
  • @DanielKniaz - the call to **`system.currenttimemillis()`** returns absolute TimeDOMAIN distance from epoch datum ( i.e. from **`1970-01-01T00:00:00ZULU`** ). The relative timing of a section of code is of no use in this. – user3666197 Jun 13 '17 at 00:03
0
dt1 = TimeLocal()+2;
do
{
  dt2 = TimeLocal();
}
while(TimeSecons(dt2) < TimeSecons(dt1));

after finish you may count time from 0.000

Sova
  • 1
0

Just cast values to ulong and make sure to multiply TimeGMT() with 1000

for print result cast to string :

ulong time = (ulong) TimeGMT()*1000 - (ulong) GetTickCount() ; 
Print("milliseconds: ",  (string)time);
josef
  • 872
  • 9
  • 8
0

Another way seems to be using the WinAPI (kernel32.dll). This seems to be more integrated with MQL5 by using #include <WinAPI/windef.mqh> but can be used with MQL4 too by defining the required structs.

The following snippet shows how to get it in MQL4 –in MQL5 you don't need to define the structs as they can be included:

// MQL5 seems to have Include/WinAPI/windef.mqh - constants, structures and enumerations
#ifdef __MQL4__
//+------------------------------------------------------------------+
//| MQL4 equivalent of Windows _FILETIME struct: GetSystemTimeAsFileTime().
//| @see: https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
//+------------------------------------------------------------------+
struct FILETIME {
  uint dwLowDateTime;
  uint dwHighDateTime;
};

//+------------------------------------------------------------------+
//| MQL4 equivalent of Windows GetSystemTime()/GetLocalTime()/... struct.
//| Credits: https://www.mql5.com/en/forum/146837/page3#comment_3702187
//+------------------------------------------------------------------+
struct SYSTEMTIME {
  ushort wYear;         // 2014 etc
  ushort wMonth;        // 1 - 12
  ushort wDayOfWeek;    // 0 - 6 with 0 = Sunday
  ushort wDay;          // 1 - 31
  ushort wHour;         // 0 - 23
  ushort wMinute;       // 0 - 59
  ushort wSecond;       // 0 - 59
  ushort wMilliseconds; // 0 - 999

  string toString() {
    return StringFormat("%hu-%02hu-%02hu %02hu:%02hu:%02hu.%03hu", wYear, wMonth, wDay, wHour, wMinute, wSecond, wMilliseconds);
  }
};
#endif

#import "kernel32.dll"
  // Millisecond (ms) precision, but limited by Windows timer configuration?? (15-16 ms by default)
  void GetSystemTime(SYSTEMTIME &time); // (struct version)
  void GetLocalTime(SYSTEMTIME &time); // (struct version)
  // Microsecond (us) precision, limited by Windows timer configuration?? (15-16 ms by default)
  void GetSystemTimeAsFileTime(FILETIME& t); // (ulong version) Returns the system time in 100-nsec units
#import

Then you can define user-friendly functions to get the time around the above ones, e.g.

//+------------------------------------------------------------------+
//| Get the system time (UTC) in milliseconds.
//| Credits: https://www.mql5.com/en/forum/146837/page4#comment_13522420
//+------------------------------------------------------------------+
ulong systemTimeMillis(){
  FILETIME t; // time measured in 100-nano second units
  GetSystemTimeAsFileTime(t);
  ulong time = (long)t.dwHighDateTime << 32 | t.dwLowDateTime;
  ulong diffTo1970 = 11644473600000; // FILETIME starts at January 1, 1601 (UTC)
  return (ulong)(time * 0.0001 - diffTo1970); // 100-ns to ms (divide 10_000)
}

ulong localTimeMillis() {
  return systemTimeMillis() - TimeGMTOffset() * 1000;
}

More references

Gerard Bosch
  • 648
  • 1
  • 7
  • 18