Функции для работы со временем

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

Как мы знаем, основная система координат в торговле построена на двух измерениях: цене и времени. На графиках они отображаются, как правильно, по вертикальной и горизонтальной оси, соответственно. Позднее мы затронем еще одну важную ось, которую можно представить перпендикулярной двум первым и уходящей как бы вглубь графика, — на ней отмечаются торговые объемы. Но пока сконцентрируемся на времени.

Это измерение является общим для всех графиков, использует одни и те же единицы измерения и, как бы это странно ни звучало, характеризуется постоянством (ход времени предсказуем).

Общее число встроенных средств, связанных с расчетом и анализом времени, в терминале очень велико. Поэтому знакомиться с ними мы будем постепенно, по мере продвижения по главам книги, от простого — к сложному.

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

В разделе Дата и время в главе про преобразование данных мы уже видели пару функций, связанных со временем: TimeToStruct и StructToTime. Они позволяют разделить значение типа datetime на составляющие или наоборот, сконструировать datetime из отдельных полей: напомним, что они сведены в структуру MqlDateTime.

struct MqlDateTime

   int year;        // год (1970 — 3000)
   int mon;         // месяц (1 — 12) 
   int day;         // день (1 — 31) 
   int hour;        // часы (0 — 23) 
   int min;         // минуты (0 — 59) 
   int sec;         // секунды (0 — 59) 
   int day_of_week// день недели, нумерация с 0 (воскресенье) по 6 (субботу)
                    //    согласно перечислению ENUM_DAY_OF_WEEK
   int day_of_year// порядковый номер дня в году, начиная с 0 (1 января)
};

Но откуда MQL-программа может получить само значение datetime?

Например, исторические цены и время отражены в котировках, а текущие "живые" данные поступают с тиками. И то, и другое обладает метками времени, которые мы научимся получать в соответствующих разделах: про таймсерии и события терминала. Однако MQL-программа имеет возможность запросить текущее время само по себе (без цен или другой торговой информации) с помощью нескольких функций.

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

Любой часовой пояс характеризуется временным смещением относительно общемировой точки отсчета времени — нулевого гринвичского меридиана (Greenwich Mean Time, GMT). Как правило, смещение часового пояса составляет целое число часов N (хотя есть и экзотические зоны с получасовым шагом) и потому обозначается как GMT+N или GMT-N, в зависимости от того, восточнее или западнее от меридиана находится пояс. Например, расположенная восточнее от Лондона континентальная Европа использует центральноевропейское время (Central European Time, CET), равное GMT+1, или восточноевропейское время (Eastern European Time, EET), равное GMT+2, а в Америке расположены "отрицательные" зоны, такие как Eastern Standard Time (EST) или GMT-5.

Следует отметить, что GMT соответствует астрономическому (солнечному) времени, которое обладает едва заметной нелинейностью, поскольку вращение Земли постепенно замедляется. В связи с этим в последние десятилетия фактически произошел переход к более точной системе учета времени (на основе атомных часов), в которой общемировое время называется всемирным координированным временем (Coordinated Universal Time, UTC). Во многих прикладных областях, включая и трейдинг, различие между GMT и UTC несущественно, поэтому обозначения часовых поясов в новом формате UTC±N и старом GMT±N следует считать аналогами. Например, многие брокеры уже указывают в спецификациях времена сессий через UTC, в то время как в MQL5 API исторически используется обозначение GMT.

MQL5 API позволяет узнать текущее время терминала (фактически, локальное время компьютера) и время сервера: их возвращают, соответственно, функции TimeLocal и TimeCurrent. Кроме того, MQL-программа может получить текущее время GMT (функция TimeGMT), основываясь на настройках часового пояса Windows. Таким образом, у трейдера и программиста появляется привязка локального времени к общемировому, а по разнице между локальным и серверным временем можно определить "таймзону" сервера и котировок. Но здесь есть пара нюансов.

Во-первых, во многих странах мира существует практика перехода на "летнее" время из соображений более эффективного использования дневного света (Daylight Savings Time , DST). Обычно это означает добавление 1 часа к стандартному (зимнему) времени примерно с марта/апреля по октябрь/ноябрь (в северном полушарии, в южном — наоборот). При этом время GMT/UTC всегда остается постоянным, то есть не подвергается поправке DST, и потому потенциально возможны различные варианты схождения/расхождения клиентского и серверного времени:

  • в разных странах даты перехода могут отличаться;
  • некоторые страны не осуществляют переход на летнее время;

В связи с этим, некоторым MQL-программам требуется отслеживать подобные моменты перестройки часовых поясов, если алгоритмы основаны на привязке к внутридневному времени (например, к выходу новостей), а не к движениям цен или концентрации объемов.

И если перевод времени на компьютере пользователя определить довольно легко, благодаря функции TimeDaylightSavings, то для серверного времени готового аналога нет.

Во-вторых, штатный тестер MetaTrader 5, в котором мы можем отлаживать или оценивать MQL-программы таких типов как эксперты и индикаторы, к сожалению, не эмулирует время торгового сервера. Вместо этого все три вышеуказанные функции TimeLocal, TimeGMT, TimeCurrent вернут одно и то же время, то есть часовой пояс всегда виртуально равен GMT.

Абсолютное и относительное время
 
Учет времени в алгоритмах, как и в жизни, может вестись в абсолютных или относительных координатах. Каждый момент в прошлом, в настоящем и в будущем описывается абсолютным значением, на которое мы можем сослаться, чтобы указать начало отчетного периода или время выхода экономических новостей. Именно это время мы храним в MQL5 с помощью типа datetime. Вместе с тем, зачастую требуется заглянуть в будущее или отступить в прошлое на заданное количество единиц времени от текущего момента. При этом нас интересует не абсолютное значение, а временной интервал.
 
В частности, в алгоритмах существует понятие таймаута — периода времени, за который должно выполниться определенное действие, и если оно не выполнилось по любым причинам, мы его отменяем, перестаем ждать результата (потому что, видимо, что-то пошло не так). Измерять интервал можно в разных единицах: часах, секундах, миллисекундах или даже микросекундах (ведь, компьютеры нынче быстры).
 
В MQL5 часть функций, связанных со временем, работает с абсолютными значениями (например, TimeLocal, TimeCurrent), а часть с интервалами (например, GetTickCount, GetMicrosecondCount).
 
Однако измерение интервалов или активация программы через заданные промежутки времени могут осуществляться не только с помощью функций из данного раздела, но и встроенных таймеров, работающих по известному принципу будильника. Будучи взведенными, они используют для уведомления MQL-программ специальные события и реализуемые нами функции обработки этих событий — OnTimer (они похожи на OnStart). Этим аспектом управления временем мы займемся в отдельном разделе, после изучения общей концепции событий в MQL5 (см. раздел Обзор функций обработки событий).