Особенности языка mql5, тонкости и приёмы работы - страница 251

 
Nikolai Semko #:

Я же все время выступаю противником оптимизации для ТС, которые всегда являются не статическими системами, а динамическими, ввиду того, что сам рынок динамический и переменчивый. Именно поэтому такую оптимизацию корректней называть подгонкой параметров под исторический период времени. Это самообман и пустая трата времени. Найденный с помощью такой "оптимизации" набор параметров будет в будущем вести себя совсем по-другому.

Не понял, зачем здесь это.
 

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Особенности языка mql5, тонкости и приёмы работы

Nikolai Semko, 2024.04.16 05:02

Моя реализация такой задачи без численных методов, а только логически, была бы, например, следующая:

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);
}

не думаю, что разница в производительности будет существенной, тем более у меня отсутствуют типы double

Спасибо, это быстрее.
 
fxsaber #:
Спасибо, это быстрее.

да, я тоже проверил

#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);
}

результат:

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)
время расчета функции 1-3 нс. Свет за это время проходит 30 см - 1 метр :))
 
Nikolai Semko #:

да, я тоже проверил

Можно без 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;

а, ну да. Не подумал, что DAY можно вынести за скобки

 
fxsaber #:
Не понял, зачем здесь это.

не обращайте внимания.

 
Nikolai Semko #:

не обращайте внимания.

Не стоит. Поправил.

 

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Особенности языка mql5, тонкости и приёмы работы

Nikolai Semko, 2024.04.16 05:02

Попробуйте таким численным методом решить задачу получения дня месяца из входного времени datetime   Сомневаюсь, что сможете.

char GetDayOfMonth(datetime time) {?}

Возможно, перемудрил, но для нахождения дня месяца нужно знать год и месяц.


Начнем с года.

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);
}


Получили искомую функцию.

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


Или она же в целочисленном виде.

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


Теперь месяц.

Для упрощения решил искать месяц в нулевом годе - 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);
}


Достичь совпадения (нуля в OnTester) не получилось.


Поэтому разделил на два случая: 1-2 месяцы и 4-12 месяцы.


Получили искомую функцию.

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));
}


Или она же в целочисленном виде.

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));
}


День месяца.

Наконец, пробуем применить полученные результаты. Не забывая про високосные особенности.

#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)));
}


Похоже, получилось.

 
fxsaber #:

Возможно, перемудрил

Написал кастомный TimeToSruct, по скорости не превосходит оригинал.
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;  
}
Перемудрил где-то.
 
Nikolai Semko #:

Да, я тоже проверил.

результат:

время расчета функции 1-3 нс. Свет за это время проходит 30 см - 1 метр :)))

Спасибо, это действительно быстро!

Причина обращения: