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

 
Nikolai Semko #:

I once said that it is a good idea to start the year on 1 March instead of 1 January. Then the curve February becomes the last month.
Then you can apply the formula to find the month:

Check out this implementation.

Forum on trading, automated trading systems and testing trading strategies

Peculiarities of mql5 language, subtleties and techniques of work

fxsaber, 2024.04.16 18:31

Easy to understand the source code.

// https://github.com/NewYaroslav/xtime_cpp/blob/master/src/xtime.hpp
struct MqlDateTime 
  { 
   int year;           // uint32_t get_year(const timestamp_t timestamp = get_timestamp())
   int mon;            // uint32_t get_month(const timestamp_t timestamp = get_timestamp())
   int day;            // uint32_t get_day_month(const timestamp_t timestamp = get_timestamp())
   int hour;           // uint32_t get_hour_day(const timestamp_t timestamp = get_timestamp())
   int min;            // uint32_t get_minute_hour(const timestamp_t timestamp = get_timestamp())
   int sec;            // uint32_t get_second_minute(const timestamp_t timestamp = get_timestamp())
   int day_of_week;    // uint32_t get_weekday(const timestamp_t timestamp = get_timestamp())
   int day_of_year;    // uint32_t get_day_year(const timestamp_t timestamp = get_timestamp())
  };
 
fxsaber #:

Check out this implementation.

Ha-ha, they didn't bother much there, they just threw in an array of 365 (or 366) elements.

maybe it's justified

 
Nikolai Semko #:

Haha, they didn't bother much there, they just stuck a 365 (or 366) element array in there

maybe it's justified

If the speed is higher than the alternatives, it is 100% justified.

 
fxsaber #:

If the speed is higher than the alternatives, it is 100% justified.

Solutions using lookup tables are often the fastest, especially in time critical areas of code.

Sometime, it is better not to be so smart :)

Edit:
It reminds me of the fastest algorithms for calculating int logs and clz.
 
Nikolai Semko #:
I once said that it was a good idea to start the year on 1 March rather than 1 January.

Perhaps that's how it used to be. It's not for nothing that they say the Slavs had their new year in March.

See Latin/Sanskrit: 7 - septem/sapta, 8 - octo/ashta, 9 - novem/nava, 10 - decem/dasha. Accordingly, the 11th month was January and the 12th month was February.

 
Nikolai Semko #:

Yeah, I checked, too.

the result:

function calculation time 1-3 ns. Light during this time passes 30 cm - 1 metre :)))

I changed GetMonthTime4 name to a more descriptive one:

//+------------------------------------------------------------------+
//| Create a datetime value from the given year, month and day.      |
//| https://www.mql5.com/en/forum/393227/page251#comment_53067868    |
//+------------------------------------------------------------------+
datetime CreateDateTime(const int iYear, const int iMonth, const int iDay)
  {
// MqlDateTime dt = {iYear, iMonth, iDay}
// return StructToTime(dt);

   static const int dm[] = {0, 0, 31, 59, 90, 120, 151, 181, 212,243, 273, 304, 334};
   int leap_days = (iYear - 1968) / 4 - (iYear % 4 == 0 && iMonth < 3);
   return datetime((iYear - 1970) * 365 + leap_days + dm[iMonth] + iDay - 1) * 86400;
  }

benchmark:

void OnStart()
  {
   int k = 5000;
   ulong sum1 = 0;
   ulong sum2 = 0;
   uint start = GetTickCount();
   for(int i = 0; i < k; i++)
      for(int y = 1970; y <= 2099; y++)
         for(int m = 1; m <= 12; m++)
            for(int d = 1; d <= 28; d++)
              {
               MqlDateTime st = {y, m, d};
               sum1 += StructToTime(st);  // <-------------------
              }
   PrintFormat("StructToTime() -> %u msec", GetTickCount()-start);
   start = GetTickCount();
   for(int i = 0; i < k; i++)
      for(int y = 1970; y <= 2099; y++)
         for(int m = 1; m <= 12; m++)
            for(int d = 1; d <= 28; d++)
              {
               sum2 += CreateDateTime(y, m, d);  // <-------------------
              }
   PrintFormat("CreateDateTime() -> %u msec", GetTickCount()-start);
//--- Display results.
   Print("sum1: ", sum1);
   Print("sum2: ", sum2);
  }

Results:

2024.04.18 02:50:07.953 benchmark_CreateDateTime (EURUSD,H1)    StructToTime() -> 6688 msec
2024.04.18 02:50:08.010 benchmark_CreateDateTime (EURUSD,H1)    CreateDateTime() -> 62 msec
2024.04.18 02:50:08.010 benchmark_CreateDateTime (EURUSD,H1)    sum1: 447943668480000000
2024.04.18 02:50:08.010 benchmark_CreateDateTime (EURUSD,H1)    sum2: 447943668480000000

Wow! faster 100x times than native way.

Forget about StringToTime(). It is extremely slowwwww!
 
amrali #:

I changed GetMonthTime4 name to a more descriptive one:

benchmark:

Results:

Wow! faster 100x times than native way.

Forget about StringToTime(). It is extremely slowwwww!

Your code is well suited for compiler optimization.

Maximum Optimization:

StructToTime() -> 13421 msec
CreateDateTime() -> 125 msec
sum1: 447943668480000000
sum2: 447943668480000000

No Optimization:

StructToTime() -> 12937 msec
CreateDateTime() -> 1860 msec
sum1: 447943668480000000
sum2: 447943668480000000

I'm just sharing the results of my runs

 
amrali #:

By the way, I tried to force your function to use a structure (to make the experiment more fair😄) and this did not affect performance - the result is the same (the difference is within the measurement error limits).

Files:
 

Forum on trading, automated trading systems and testing trading strategies

Libraries: Local Timezones and Local Session Hours

amrali, 2024.04.18 04:31

Update 18 April 2024 - version 1.88

Added the CreateDateTime internal method to construct datetime values from date components (year, month and day).

This is 100-120x times faster than assigning values to MqlDateTime struct then calling the StructToTime function.


 
amrali #:

I've changed the name GetMonthTime4 to be more descriptive:

Alternative.

    constexpr inline timestamp_t get_timestamp(
            const uint32_t day,
            const uint32_t month,
            const uint32_t year,
            const uint32_t hour = 0,
            const uint32_t minute = 0,
            const uint32_t second = 0) noexcept {
        long _mon = month - 1;
        const long _TBIAS_YEAR = 1900;
        const long      lmos[] = {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335};
        const long      mos[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
        long _year = year - _TBIAS_YEAR;
        // для предотвращения проблемы 2038 года переменная должна быть больше 32 бит
        long long _days = (((_year - 1) / 4) + ((((_year) & 03) || ((_year) == 0)) ? mos[_mon] : lmos[_mon])) - 1;
        _days += DAYS_IN_YEAR * _year;
        _days += day;
        const long _TBIAS_DAYS = 25567;
        _days -= _TBIAS_DAYS;
        timestamp_t _secs = SECONDS_IN_HOUR * hour;
        _secs += SECONDS_IN_MINUTE * minute;
        _secs += second;
        _secs += _days * SECONDS_IN_DAY;
        return _secs;
    }