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

 
amrali #:

Высокопроизводительные функции работы со временем, действующие для всего диапазона дат и времени MQL5 (с 1 января 1970 года по 31 декабря 3000 года):

(На основе алгоритма преобразования календарей Нери–Шнайдера: здесь)

Прилагаемый файл скрипта содержит исходные коды и полные проверки.

Что такое ULL и U ?
 
Vladimir Pastushak #:
Что такое ULL и U?

  • Суффикс U: unsigned int 32 (uint)
  • Суффикс ULL: unsigned long 64 (ulong)

Эти беззнаковые делители (3600ULL, 86400ULL и т. д.) принудительно запускают беззнаковое деление и вычисление остатка по модулю, особенно когда числитель имеет тип datetime ( внутренне обрабатываемый как signed long 64).

Перед выполнением деления или вычисления модуля значение datetime будет преобразовано в ulong. Это обеспечивает более быструю оптимизацию со стороны компилятора.

datetime / 86400 ULL is a bit faster than datetime / 86400.

Деление и вычисление остатка с знаком потребуют дополнительных инструкций для обработки знака.

Проверьте это на сайте https://godbolt.org/


Compiler Explorer
Compiler Explorer
  • Matt Godbolt
  • godbolt.org
Compiler Explorer is an interactive online compiler which shows the assembly output of compiled C++, Rust, Go (and many more) code.
 

Подписанные и неподписанные операции div/mod:

int DayOfWeek(const datetime t)
  {
   return (int)(t / 86400 + THURSDAY) % 7;
  }

int DayOfWeekU(const datetime t)
  {
   return (int)((t / 86400 ULL + THURSDAY) % 7 U);
  }

#define  BENCHSIZE 10000000

ulong randUlong() { return((ulong)rand()<<60)|((ulong)rand()<<45)|((ulong)rand()<<30)|((ulong)rand()<<15)|(ulong)rand(); }

void OnStart() {
   Print("\nCompiler Version: " + (string)__MQLBUILD__ + ", " + __CPU_ARCHITECTURE__);
   Print(TerminalInfoString(TERMINAL_CPU_NAME) + ", " + TerminalInfoString(TERMINAL_CPU_ARCHITECTURE));

   datetime t[];
   ArrayResize(t, BENCHSIZE);
   for(int i = 0; i < BENCHSIZE;i++) {
      t[i] = (datetime) (randUlong() % D'3000.01.01');
   }

   // Тесты
   ulong sum = 0;
   ulong tt = GetMicrosecondCount();
   for(int i=0; i<BENCHSIZE; i++) { sum += t[i] + DayOfWeek(t[i]); }
   PrintFormat("%5.2f ns, checksum = %llu   // DayOfWeek", (GetMicrosecondCount()-tt)*1000.0/BENCHSIZE, sum);

   sum = 0;
   tt = GetMicrosecondCount();
   for(int i=0; i<BENCHSIZE; i++) { sum += t[i] + DayOfWeekU(t[i]); }
   PrintFormat("%5.2f ns, checksum = %llu   // DayOfWeekU", (GetMicrosecondCount()-tt)*1000.0/BENCHSIZE, sum);
  }

Результаты:

 Compiler Version: 5836, AVX2 + FMA3
 13 th Gen Intel Core i7-13700 KF, AVX2 + FMA3
  1.24 ns, checksum = 162509975528847278   // День недели
  0.72 ns, checksum = 162509975528847278   // DayOfWeekU
 

Stefano Cerbioni Expert Advisor is strictly bound to the chart it is running on. There is no native, event-driven way to detect when a user switches focus (clicks) between different chart tabs within the terminal unless the EA is present on every single chart.

[...]


Это событие должно:

срабатывать всякий раз, когда пользователь нажимает на вкладку другого графика в терминале.

быть доступным для любого советника, запущенного в терминале, независимо от того, к какому графику он физически привязан (или, по крайней мере, предоставлять глобальное свойство графика, доступное через OnChartEvent).


Это не совсем то, о чём вы просили, но вы можете использовать этот недокументированный параметр lparam CHARTEVENT_CHART_CHANGE для обнаружения переключения вкладок; однако он работает только при переключении между вкладками в режиме максимального развертывания (изменение размера окна), а не когда они расположены рядом.

if(id == CHARTEVENT_CHART_CHANGE)
  {
   if(lparam != 16)
     {
      BroadcastEvent(ChartID(),0,"Broadcast Message");
     }
  }

Вы могли бы создать минималистичный индикатор на графике, который будет передавать пользовательское событие вашему советнику — это и станет вашим триггером «push».

Если вам нужны окна, расположенные рядом, то вы могли бы использовать CHARTEVENT_CLICK, но для этого либо понадобится дополнительный переключатель (bool) для включения/выключения события, либо оно будет срабатывать каждый раз, когда вы нажимаете на график.

Я согласен, что должен быть более удобный способ решения этой проблемы.

Documentation on MQL5: EventChartCustom / Working with Events
Documentation on MQL5: EventChartCustom / Working with Events
  • www.mql5.com
The function generates a custom event for the specified chart. Parameters chart_id [in] Chart identifier. 0 means the current chart...
 
amrali #:

Подписанные и неподписанные операции div/mod:

Спасибо, это очень интересный нюанс, причины которого хотелось бы понять. Чтобы в будущем писать более оптимально в общем случае.

ЗЫ Увидел объяснение. Еще раз спасибо.

 
amrali #:

Альтернатива функции StructToTime() на языке MQL:

Замена функции TimeToStruct() в MQL:

Великолепная работа! Наверное, MQ стоит рассмотреть это решение для замены своих штатных функций.

Здесь ускорение имеет большое практическое значение - Тестер.

 

Как быстро инвертировать стратегию?

Просто меняешь 

Trade.Buy(lot, _Symbol, 0, sl, tp);

на

Trade.Sell(lot, _Symbol, 0, ask+bid-sl, ask+bid-tp);

и по такой же логике меняешь Sell на Buy

математика элементарная, но не очевидная

 
rkdius #:

Это не совсем то, о чём вы просили, но вы можете использовать этот недокументированный параметр lparam CHARTEVENT_CHART_CHANGE для обнаружения переключения вкладок; однако он работает только при переключении между вкладками в режиме максимального развертывания (изменение размера окна), а не когда они расположены рядом.

Вы могли бы создать минималистичный индикатор на графике, который будет передавать пользовательское событие вашему советнику — это и станет вашим триггером «push».

Если вам нужны окна, расположенные рядом, то вы могли бы использовать CHARTEVENT_CLICK, но для этого либо понадобится дополнительный переключатель (bool) для включения/выключения события, либо оно будет срабатывать каждый раз, когда вы нажимаете на график.

Я согласен, что должен быть более удобный способ решения этой проблемы.

Можно отслеживать в OnChartEvent, при нажатиях мыши, id активного графика.

ChartGetInteger(0, CHART_BRING_TO_TOP)
 
Aleksandr Slavskii #:

Вы можете отслеживать идентификатор активного графика в методе `OnChartEvent` при нажатии кнопки мыши.

Это самая сложная часть, потому что всё зависит от того, как вы используете MT.
Если у вас один монитор и один график в максимальном размере, то всё просто — подойдут либо CHART_BRING_TO_TOP либо CHART_IS_MAXIMIZED.
Если у вас несколько мониторов, несколько окон графиков, расположенных рядом, или отдельные графики, то, вероятно, правильным решением будет отслеживание щелчков мышью и нажатий клавиш.

Было бы гораздо проще, если бы существовало свойство графика, указывающее, активно ли окно графика, или обработчик событий, как упоминал ранее Стефано.

Правка:

На самом деле, после краткого тестирования, CHART_BRING_TO_TOP похоже, выполняет функцию «активного окна», хотя название довольно неудачное и вводящее в заблуждение. Документация MQL5 явно нуждается в обновлении...

 
fxsaber #:

Отличная работа! Возможно, MQ стоит рассмотреть это решение в качестве замены своих стандартных функций.

Повышение производительности в данном случае имеет огромное практическое значение — Tester.

Я добавил эти функции в библиотеку TimeUtils (здесь: https://www.mql5.com/ru/code/53970).

Буду рад любым предложениям. Спасибо.

High-Performance Time Functions (TimeUtils)
High-Performance Time Functions (TimeUtils)
  • 2024.12.03
  • www.mql5.com
High-performmance functions for dealing with time.