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

 

Forum on trading, automated trading systems and testing trading strategies

Features of mql5 language, subtleties and techniques of work

Nikolai Semko, 2024.04.16 05:02

My realisation of such a task without numerical methods, but only logically, would be, for example, the following:

datetime GetMonthTime4(const int Year, const int Month ) {
   static const int dm[13] = {0, 0, 31, 59, 90, 120, 151, 181, 212 ,243, 273, 304, 334};
   return datetime(uint((Year-1970)*365+ (Year-1968)/4 - ((Year%4==0 && Month<3)?1:0) + dm[Month])*24*60*60);
}

I don't think the difference in performance would be significant, especially I don't have double types

Thanks, that's faster.
 
fxsaber #:
Thank you, that's quicker.

Yeah, I checked, too.

#define  DAY (24 * 3600)
#define  SIZE 100000
//+------------------------------------------------------------------+
void OnStart() {
   ulong sum = 0;
   int y[SIZE], m[SIZE];
   for(int i = 0;i<SIZE;i++) {
      y[i] = 1970 +rand()%128;
      m[i] = 1 + rand()%12;
   }
   ulong tt = GetMicrosecondCount();
   for(int i=0; i<SIZE; i++)
      sum += GetMonthTime3(y[i],m[i]);   
   tt = GetMicrosecondCount()-tt;
   Print("контрольная сумма: "+string(sum) +" for "+string(tt)+" µs (1)");
   sum = 0;
   tt = GetMicrosecondCount();
   for(int i=0; i<SIZE; i++)
      sum += GetMonthTime4(y[i],m[i]);   
   tt = GetMicrosecondCount()-tt;
   Print("контрольная сумма: "+string(sum) +" for "+string(tt)+" µs (2)");

}
//+------------------------------------------------------------------+
// Работает до конца XXI-века.
datetime GetMonthTime3( const int Year, const int Month ) {
   static const double Months[] = {0, 0.45, 31 * 1.01, 59 * 1.01, 90 * 1.007, 120 * 1.005, 151 * 1.004, 181 * 1.004,
                                   212 * 1.003, 243 * 1.003, 273 * 1.002, 304 * 1.002, 334 * 1.002
                                  };

   return((datetime)(((Year - 1970) * 365.25 + Months[Month]) * DAY) / DAY * DAY);
}
//+------------------------------------------------------------------+
// Работает до конца XXI-века.
datetime GetMonthTime4(const int Year, const int Month ) {
   static const int dm[13] = {0, 0, 31, 59, 90, 120, 151, 181, 212 ,243, 273, 304, 334};
   return datetime(uint((Year-1970)*365+ (Year-1968)/4 - ((Year%4==0 && Month<3)?1:0) + dm[Month])*24*60*60);
}

the result:

2024.04.15 23:41:13.549 TestDate (EURUSD,M15)   контрольная сумма: 201808073635200 for 125 µs (1)
2024.04.15 23:41:13.550 TestDate (EURUSD,M15)   контрольная сумма: 201808073635200 for 108 µs (2)
2024.04.15 23:41:14.420 TestDate (EURUSD,M15)   контрольная сумма: 201797123644800 for 353 µs (1)
2024.04.15 23:41:14.420 TestDate (EURUSD,M15)   контрольная сумма: 201797123644800 for 294 µs (2)
2024.04.15 23:41:15.152 TestDate (EURUSD,M15)   контрольная сумма: 202013637724800 for 344 µs (1)
2024.04.15 23:41:15.152 TestDate (EURUSD,M15)   контрольная сумма: 202013637724800 for 333 µs (2)
2024.04.15 23:41:15.922 TestDate (EURUSD,M15)   контрольная сумма: 202268604902400 for 293 µs (1)
2024.04.15 23:41:15.922 TestDate (EURUSD,M15)   контрольная сумма: 202268604902400 for 243 µs (2)
2024.04.15 23:41:16.700 TestDate (EURUSD,M15)   контрольная сумма: 202117366195200 for 386 µs (1)
2024.04.15 23:41:16.700 TestDate (EURUSD,M15)   контрольная сумма: 202117366195200 for 327 µs (2)
2024.04.15 23:41:17.748 TestDate (EURUSD,M15)   контрольная сумма: 201254289638400 for 380 µs (1)
2024.04.15 23:41:17.748 TestDate (EURUSD,M15)   контрольная сумма: 201254289638400 for 295 µs (2)
2024.04.15 23:41:18.553 TestDate (EURUSD,M15)   контрольная сумма: 202225825929600 for 306 µs (1)
2024.04.15 23:41:18.554 TestDate (EURUSD,M15)   контрольная сумма: 202225825929600 for 261 µs (2)
2024.04.15 23:41:19.364 TestDate (EURUSD,M15)   контрольная сумма: 202132174982400 for 362 µs (1)
2024.04.15 23:41:19.365 TestDate (EURUSD,M15)   контрольная сумма: 202132174982400 for 314 µs (2)
2024.04.15 23:41:20.154 TestDate (EURUSD,M15)   контрольная сумма: 201679615324800 for 236 µs (1)
2024.04.15 23:41:20.154 TestDate (EURUSD,M15)   контрольная сумма: 201679615324800 for 199 µs (2)
function calculation time 1-3 ns. Light during this time passes 30 cm - 1 metre :)))
 
Nikolai Semko #:

Yeah, I checked, too.

You can do it without uint.

datetime GetMonthTime4(const int Year, const int Month ) {
   static const int dm[13] = {0, 0, 31, 59, 90, 120, 151, 181, 212 ,243, 273, 304, 334};
   return datetime((Year-1970)*365+ (Year-1968)/4 - ((Year%4==0 && Month<3)?1:0) + dm[Month])*24*60*60;
}
 
fxsaber #:
return datetime((Year-1970)*365+(Year-1968)/4 - ((Year%4==0 && Month<3)?1:0) + dm[Month])*24*60*60;

Oh, right. I didn't realise that DAY could be put outside the brackets.

 
fxsaber #:
I don't understand why this is here.

ignore it.

 
Nikolai Semko #:

ignore it.

You shouldn't. Corrected.

 

Forum on trading, automated trading systems and testing trading strategies

Peculiarities of mql5 language, subtleties and techniques of work

Nikolai Semko, 2024.04.16 05:02

Try to solve the problem of getting the day of the month from the input time datetime usingthis numerical method . I doubt that you will be able to.

char GetDayOfMonth(datetime time) {?}

Perhaps, overminded, but to find the day of the month you need to know the year and month.


Let's start with the year.

input group "Оптимизируем"
input double inKoef1 = 365;
input double inKoef2 = 0;

input group "Не оптимизируем"
sinput int inYearFrom = 1970;
sinput int inYearTo = 2099; 

#define  DAY (24 * 3600)

int GetYear( const datetime time )
{
  return((int)((time / DAY + inKoef2) / inKoef1) + 1970);
}

double OnTester()
{
  int Sum = 0;

  MqlDateTime time1 = {0, 1, 1};
  MqlDateTime time2 = {0, 12, 31};

  for (int i = inYearFrom; i <= inYearTo; i++)
  {
    time1.year = i;
    time2.year = i;

    Sum -= MathAbs(i - GetYear(StructToTime(time1))) + MathAbs(i - GetYear(StructToTime(time2)));
  }

  return(Sum);
}


We've got the function we're looking for.

int GetYear2( const datetime time )
{
  return((int)((time / DAY+ 0.5) / 365.25) + 1970);
}


Or the same function in integer form.

int GetYear3( const datetime time )
{
  return((int)((time / DAY * 4 + 2) / (365 * 4 + 1)) + 1970);
}


Now the month.

For simplicity, I decided to search for the month in year zero - 1970.

input group "Оптимизируем"
input double inKoef1 = 30;
input double inKoef2 = 0;

#define  DAY (24 * 3600)

int GetMonth( const datetime time )
{
  return((int)((time / DAY) / inKoef1 + inKoef2));
}

double OnTester()
{
  int Sum = 0;

  const datetime Dates[] = {D'1970.01.01', D'1970.01.31',
                            D'1970.02.01', D'1970.02.28',
                            D'1970.03.01', D'1970.03.31',
                            D'1970.04.01', D'1970.04.30',
                            D'1970.05.01', D'1970.05.31',
                            D'1970.06.01', D'1970.06.30',
                            D'1970.07.01', D'1970.07.31',
                            D'1970.08.01', D'1970.08.31',
                            D'1970.09.01', D'1970.09.30',
                            D'1970.10.01', D'1970.10.31',
                            D'1970.11.01', D'1970.11.30',
                            D'1970.12.01', D'1970.12.31'};

  for (int i = 1; i <= 12; i++)
    Sum -= MathAbs(i - GetMonth(Dates[(i - 1) << 1])) + MathAbs(i - GetMonth(Dates[((i - 1) << 1) + 1]));

  return(Sum);
}


We could not achieve a coincidence (zero in OnTester).


So I divided it into two cases: 1-2 months and 4-12 months.


We got the desired function.

int GetMonth2( const datetime time )
{
  const int time2 = (int)time / DAY;
  
  return((time2 < D'1970.03.01' / DAY) ? time2 / 31 + 1
                                       : ((time2 >= D'1970.04.01' / DAY) ? (int)(time2 / 30.64 + 1.1) : 3));
}


Or the same in integer form.

int GetMonth3( const datetime time )
{
  const int time2 = (int)time / DAY;
  
  return((time2 < D'1970.03.01' / DAY) ? time2 / 31 + 1
                                 : ((time2 >= D'1970.04.01' / DAY) ? ((time2 * 500 + 1532 * 11) / (1532 * 10)) : 3));
}


Day of the month.

Finally, let's try to apply the obtained results. Not forgetting leap year features.

#define  DAY (24 * 3600)

// Работает до конца XXI-века.
int GetDayMonth2100( const datetime time )
{
  int time2 = (int)(time / DAY);
  const int Year = ((time2 << 2) + 2) / (365 * 4 + 1); // to 2100

  const bool Flag = ((Year & 3) == 2);
  time2 -= Year * 365 + ((Year + 2) >> 2);    
  
  const int Month = (time2 < 59) ? (time2 + Flag) / 31 + 1
                                 : ((time2 >= 90) ? (time2 * 500 + 1532 * 11) / (1532 * 10) : 3);
                                                  
  // Количество дней от начала года до начала месяца: январь - 0, февраль - 31, март - 59, ...
  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};
  
  return(time2 - Months[Month] + (Flag && (Month < 3)));
}


It seems to work.

 
fxsaber #:

Probably overthinking it

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;  
}
I may have overdone it somewhere.
 
Nikolai Semko #:

Yeah, I checked, too.

the result:

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

Thanks, it is really fast!

 
amrali #:

Thanks, it is really fast!

The function is a smart subset of the algorithm of StructToTime in mql5, or mktime in C  https://github.com/lattera/glibc/blob/master/time/mktime.c.   

Nicely formatted:

//+------------------------------------------------------------------+
//| Get the datetime of the first day of the iMonth for the iYear.   |
//| GetMonthTime(2016, 5) => D'2016.05.01 00:00:00'                  |
//| https://www.mql5.com/en/forum/393227/page251#comment_53067868    |
//+------------------------------------------------------------------+
datetime GetMonthTime(const int iYear, const int iMonth)
  {
// MqlDateTime dt = {iYear, iMonth, 01}
// 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]) * DAY;
  }