Features of the mql5 language, subtleties and tricks - page 258

 
Artyom Trishkin #:

That's what this thread is for. Why do you need another one?

In this one - search and discussion, and the new one - for recorded finds. It would be even with a table of contents in 1 post.

 
Artyom Trishkin #:

That's what this thread is for. Why do you need another one?

I kind of do, but, um. no.


 

A faster TimeToStruct() function for decoding of datetime variables, to get all the components of date and time.

Some parts of the code can be re-used to extract the components of interest, separately.

Benchmark:

#define SIZE 10000000
//+------------------------------------------------------------------+
void OnStart() {
   ulong sum = 0;
   datetime t[];
   ArrayResize(t, SIZE);
   for(int i = 0;i<SIZE;i++) {
      t[i] = datetime(randUlong(ulong(365)*128*3600*24));
   }
   ulong tt = GetMicrosecondCount();
   for(int i=0; i<SIZE; i++) {
      MqlDateTime dt;
      TimeToStruct(t[i], dt);   // <----------------------------- (1)
      //int mm =dt.year+ dt.mon+ dt.day+ dt.hour+ dt.min+ dt.sec+ dt.day_of_week+ dt.day_of_year;
      int mm =dt.mon;
      sum+=mm;
   }
   tt = GetMicrosecondCount()-tt;
   Print("1 - " + DoubleToString(tt*1000.0/SIZE,2) + " ns, контрольная сумма = " + string(sum)+"  // TimeToStruct");
   ///////////
   sum = 0;
   tt = GetMicrosecondCount();
   for(int i=0; i<SIZE; i++) {
      MqlDateTime dt;
      TimeToStructFast(t[i], dt);   // <----------------------------- (2)
      //int mm =dt.year+ dt.mon+ dt.day+ dt.hour+ dt.min+ dt.sec+ dt.day_of_week+ dt.day_of_year;
      int mm =dt.mon;
      sum+=mm;
   }
   tt = GetMicrosecondCount()-tt;
   Print("2 - " + DoubleToString(tt*1000.0/SIZE,2) + " ns, контрольная сумма = " + string(sum)+"  // amrali");
   }
//+------------------------------------------------------------------+
ulong randUlong(ulong max=ULONG_MAX) {
   return(((ulong)rand()<<60)|((ulong)rand()<<45)|((ulong)rand()<<30)|((ulong)rand()<<15)|(ulong)rand())%max;
}
//+------------------------------------------------------------------+
bool TimeToStructFast(datetime time, MqlDateTime& dt_struct)
  {
   int y = 4716   ;
   int j = 1401   ;
   int m = 2      ;
   int n = 12     ;
   int r = 4      ;
   int p = 1461   ;
   int v = 3      ;
   int u = 5      ;
   int s = 153    ;
   int w = 2      ;
   int B = 274277 ;
   int C = -38    ;
   int x = (int)(time / 86400)                           ;  // Unix day
   int J = x + 2440588                                   ;  // Julian day
   int f = J + j + (((4 * J + B) / 146097) * 3) / 4 + C  ;
   int e = r * f + v                                     ;
   int g = (e % p) / r                                   ;
   int h = u * g + w                                     ;
   int D = (h % s) / u + 1                               ;
   int M = (h / s + m) % n + 1                           ;
   int Y = (e / p) - y + (n + m - M) / n                 ;
   int HH  = (int)((time / 3600) % 24)                   ;
   int MM  = (int)((time / 60) % 60)                     ;
   int SS  = (int)(time % 60)                            ;
   int dow = (x + 4) % 7                                 ;
   int doy = x - ((Y * 5844 - 11512676) >> 4)            ;

   // string TimeToStringFast(datetime time)
   //return StringFormat("%.2d/%.2d/%.2d %.2d:%.2d:%.2d",Y,M,D,HH,MM,SS);

   dt_struct.year           = Y;
   dt_struct.mon            = M;
   dt_struct.day            = D;
   dt_struct.hour           = HH;
   dt_struct.min            = MM;
   dt_struct.sec            = SS;
   dt_struct.day_of_week    = dow;
   dt_struct.day_of_year    = doy;

   return (true);
  }

// Algorithm: https://en.wikipedia.org/wiki/Julian_day#Julian_or_Gregorian_calendar_from_Julian_day_number

// Branchless code: check it here https://godbolt.org/z/hYbr6h45P

Results:

2024.04.21 03:31:26.019 TimeToStructFast (EURUSD,H1)    1 - 18.16 ns, контрольная сумма = 65174992  // TimeToStruct
2024.04.21 03:31:26.060 TimeToStructFast (EURUSD,H1)    2 - 4.10  ns, контрольная сумма = 65174992  // amrali
2024.04.21 03:31:26.995 TimeToStructFast (EURUSD,H1)    1 - 18.26 ns, контрольная сумма = 65184753  // TimeToStruct
2024.04.21 03:31:27.037 TimeToStructFast (EURUSD,H1)    2 - 4.10  ns, контрольная сумма = 65184753  // amrali
2024.04.21 03:31:29.114 TimeToStructFast (EURUSD,H1)    1 - 18.08 ns, контрольная сумма = 65197160  // TimeToStruct
2024.04.21 03:31:29.157 TimeToStructFast (EURUSD,H1)    2 - 4.31  ns, контрольная сумма = 65197160  // amrali
Files:
 
amrali #:

A faster TimeToStruct() function to decode time-of-day variables to get all date and time components.

Some parts of the code can be reused to retrieve components of interest individually.

Benchmark:

Results:

Very cool! Especially the fact that static arrays are not used. We can take this function as a basis.
Thanks @amrali for the research and work done.

Only it is important to understand that after the compiler optimisation, the function code will be simplified and those values of the MqlDateTime structure that do not take part in the checksum calculation will not be calculated.
Therefore, the objective result will still be with this calculation:

uint mm =dt.year+ dt.mon+ dt.day+ dt.hour+ dt.min+ dt.sec+ dt.day_of_week+ dt.day_of_year;
sum+=mm;

result:

2024.04.20 22:47:04.405 TestDate3 (EURUSD,M1)   1 - 23.31 ns, контрольная сумма = 23112112280  // TimeToStruct
2024.04.20 22:47:04.530 TestDate3 (EURUSD,M1)   2 - 12.49 ns, контрольная сумма = 23112112280  // amrali
2024.04.20 22:47:05.622 TestDate3 (EURUSD,M1)   1 - 22.53 ns, контрольная сумма = 23112276291  // TimeToStruct
2024.04.20 22:47:05.740 TestDate3 (EURUSD,M1)   2 - 11.79 ns, контрольная сумма = 23112276291  // amrali
2024.04.20 22:47:06.724 TestDate3 (EURUSD,M1)   1 - 22.54 ns, контрольная сумма = 23111452828  // TimeToStruct
2024.04.20 22:47:06.850 TestDate3 (EURUSD,M1)   2 - 12.56 ns, контрольная сумма = 23111452828  // amrali
 
Nikolai Semko #:

Only it is important to understand that after the compiler optimisation, the function code will be simplified and those values of the MqlDateTime structure that do not take part in the checksum calculation will not be calculated.
Therefore, the objective result will still be with this calculation:

result:

You bare genius! 
I did not understand why that delay when calculating the checksum from all members.
 
amrali #:
I didn't understand why there is such a delay in calculating the checksum from all members.

Forum on trading, automated trading systems and testing trading strategies

Peculiarities of mql5 language, subtleties and techniques of work

fxsaber, 2024.04.16 17:56

Unfortunately, the source code of StructToTime is not analysed by the compiler, but is attached as an imformed function. Therefore, StructToTime counts all fields of the structure at each call.

TheMQL5 compiler is able not to count unused fields, but this requires the source code to be analysed.


MQ has repeatedly said that they will include the source code of standard functions at compilation. Unfortunately, this did not happen with StructToTime.

 
fxsaber #:

Good to know that!

Thanks.

 
Nikolai Semko #:

We can summarise
A set of fast structure-less functions to get date and time parameters up to 2100 by a single input parameter datetime:

For completeness, does anyone want to add GetWeekOfYear?

 
Andrei Iakovlev #:

For completeness, does anyone want to add GetWeekOfYear?

Why?
There's no need to. Especially how to count if 1 January is Wednesday or Sunday. If just by the number of days, then just divide the days in a year by 7
 
amrali #:

A faster TimeToStruct() function to decode time-of-day variables to get all date and time components.

That's a strange code. Have you compared performance with this solution?

Forum on trading, automated trading systems and testing trading strategies

Features of mql5 language, subtleties and techniques of work

fxsaber, 2024.04.16 14:08

I wrote a custom TimeToSruct, it is not faster than the original.
void TimeToStruct2100( const datetime dt, MqlDateTime &dt_struct )
{
  const uint time = (uint)dt;
  
  dt_struct.sec = (int)(time % 60);
  dt_struct.min = (int)(time / 60) % 60;
  dt_struct.hour = (int)(time / 3600) % 24;
  
  dt_struct.day_of_year = (int)(time / (24 * 3600));
  dt_struct.day_of_week = (dt_struct.day_of_year + THURSDAY) % 7;

  const int Year = ((dt_struct.day_of_year << 2) + 2) / (365 * 4 + 1); // to 2100
  const bool Flag = ((Year & 3) == 2);

  dt_struct.day_of_year -= Year * 365 + ((Year + 2) >> 2);          
  dt_struct.year = Year + 1970;
  dt_struct.mon = (dt_struct.day_of_year < 59) ? (dt_struct.day_of_year + Flag) / 31 + 1
                                               : ((dt_struct.day_of_year >= 90) ? (dt_struct.day_of_year * 500 + 1532 * 11) /
                                                                                  (1532 * 10)
                                                                                : 3);

  static const int Months[] = {0, 0-1, 31-1, 59-1, 90-1, 120-1, 151-1, 181-1, 212-1 ,243-1, 273-1, 304-1, 334-1};  
  
  dt_struct.day = dt_struct.day_of_year - Months[dt_struct.mon] + (Flag && (dt_struct.mon < 3));
  dt_struct.day_of_year += Flag;
  
  return;  
}
Overminded somewhere.