English 中文 Español Deutsch 日本語 Português
preview
Трейдинг с экономическим календарем MQL5 (Часть 1): Освоение функций экономического календаря MQL5

Трейдинг с экономическим календарем MQL5 (Часть 1): Освоение функций экономического календаря MQL5

MetaTrader 5Трейдинг |
632 0
Allan Munene Mutiiria
Allan Munene Mutiiria

Введение

В этой статье мы рассмотрим мощные возможности экономического календаря MetaQuotes Language 5 (MQL5) и способы его интеграции в алготрейдинг. Экономический календарь, встроенный в торговый терминал MetaTrader 5, является важнейшим инструментом для трейдеров, предоставляющим важные новости и данные, которые могут существенно повлиять на движение рынка. Правильная интерпретация этой информации дает преимущество в прогнозировании реакции рынка на экономические события и позволяет корректировать торговые стратегии.

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

  1. Обзор экономического календаря MQL5
  2. Реализация средствами MQL5
  3. Заключение

К концу этой статьи вы будете вооружены знаниями, необходимыми для разработки MQL5-советника, который эффективно использует экономический календарь MQL5 в торговых стратегиях. Итак, начнем.


Обзор экономического календаря MQL5

Экономический календарь MQL5 — превосходный инструмент, предоставляющий трейдерам актуальную и последовательную информацию о ключевых экономических событиях, способных оказать существенное влияние на финансовые рынки. Это полезный инструмент, который стал еще более доступным, поскольку он встроен в платформу MetaTrader 5.

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

Чтобы открыть календарь, на панели задач выберите "Вид" > "Инструменты".

Панель "Инструменты"

В панели "Инструменты" перейдите на вкладку "Календарь" и щелкните по ней. Откроется окно календаря.

Календарь

Экономический календарь MQL5 перечисляет предстоящие события, имеющие значение для рынков, в упорядоченном порядке, отсортированные по их ожидаемому влиянию. Таким образом, календарь позволяет очень легко и быстро узнать значимость предстоящих событий. Календарь также удобно сортирует события по валютам. Хотя события организованы и обозначены цветами для большей релевантности, их не так много, чтобы трейдеру было сложно их все учесть. Таким образом, механизм сортировки гарантирует, что трейдеры не будут перегружены неактуальными данными, что позволит им сосредоточиться на новостях, которые могут напрямую повлиять на их открытые позиции или торговые стратегии.

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

Календарь

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

Конечно, не все данные имеют большое значение для трейдера, и поэтому ненужные данные можно отсортировать четырьмя способами. Один из них — по времени, например, когда нас не интересуют уже опубликованные данные. Второй способ — сортировка по валюте, третий — по стране. Например, при торговле на паре AUDUSD, важны новости, которые окажут наибольшее влияние на Австралию и США. Новости из Китая не окажут существенного влияния на пару.

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

Применение фильтра

Таким образом, используя экономический календарь MQL5, трейдеры могут лучше формулировать свои торговые планы в преддверии важных рыночных событий. Это можно сделать, проверив календарь вручную в MetaTrader 5 или используя автоматизированные торговые стратегии, которые действуют на основе данных календаря. Такая настройка открывает путь к четкому пониманию Экономического календаря MQL5 и к выяснению того, как использовать его в своей торговой системе MetaTrader 5 для получения более четких критериев для совершения сделок и более четкой торговой стратегии.


Реализация средствами MQL5

В терминале MetaTrader 5 выберите "Сервис" > "Редактор MetaQuotes Language" или просто нажмите F4. Также вы можете щелкнуть по иконке IDE (интегрированная среда разработки) на панели инструментов. Откроется среда разработки на MQL5, которая позволяет писать торговых роботов, технические индикаторы, скрипты и библиотеки функций.

Открыть MetaEditor

На панели инструментов выберите "Файл" - "Новый файл" или нажмите CTRL + N, чтобы создать новый документ. Также вы можете нажать на иконку "Создать" в панели инструментов. Откроется окно Мастера MQL.

Создание нового советника

В открывшемся Мастере выберите Советник (шаблон) и нажмите Далее.

Мастер MQL

В общих свойствах укажите имя файла вашего советника. Чтобы указать или создать папку, если она не существует, используйте обратную косую черту перед именем советника. По умолчанию указана папка Experts\. Это значит, что наш советник будет создан в папке Experts. Остальные разделы довольно просты, но вы можете перейти по ссылке в нижней части Мастера, чтобы узнать детали.

Имя нового советника

После указания имени файла советника нажмите "Далее" > "Далее" > "Готово". Мы готовы к воплощению стратегии в коде.

Начнем с определения некоторых метаданных о советнике (EA). Сюда входит название советника, информация об авторских правах и ссылка на сайт MetaQuotes. Мы также указываем версию советника. Сейчас это 1.00.

//+------------------------------------------------------------------+
//|                                    MQL5 NEWS CALENDAR PART 1.mq5 |
//|      Copyright 2024, ALLAN MUNENE MUTIIRIA. #@Forex Algo-Trader. |
//|                                     https://forexalgo-trader.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, ALLAN MUNENE MUTIIRIA. #@Forex Algo-Trader"
#property link      "https://forexalgo-trader.com"
#property description "MQL5 NEWS CALENDAR PART 1"
#property version   "1.00"

На этом этапе первое, что нам необходимо сделать, — это понять структуры работы с экономическим календарем. Их три - MqlCalendarCountry устанавливает описания стран, MqlCalendarEvent - описания событий, а MqlCalendarValue устанавливает значения событий. Структурные методы приведены ниже.

Структура стран:

struct MqlCalendarCountry 
  { 
   ulong                               id;                    // country ID (ISO 3166-1) 
   string                              name;                  // country text name (in the current terminal encoding) 
   string                              code;                  // country code name (ISO 3166-1 alpha-2) 
   string                              currency;              // country currency code 
   string                              currency_symbol;       // country currency symbol 
   string                              url_name;              // country name used in the mql5.com website URL 
  };

Структура событий:

struct MqlCalendarEvent 
  { 
   ulong                               id;                    // event ID 
   ENUM_CALENDAR_EVENT_TYPE            type;                  // event type from the ENUM_CALENDAR_EVENT_TYPE enumeration 
   ENUM_CALENDAR_EVENT_SECTOR          sector;                // sector an event is related to 
   ENUM_CALENDAR_EVENT_FREQUENCY       frequency;             // event frequency 
   ENUM_CALENDAR_EVENT_TIMEMODE        time_mode;             // event time mode 
   ulong                               country_id;            // country ID 
   ENUM_CALENDAR_EVENT_UNIT            unit;                  // economic indicator value's unit of measure 
   ENUM_CALENDAR_EVENT_IMPORTANCE      importance;            // event importance 
   ENUM_CALENDAR_EVENT_MULTIPLIER      multiplier;            // economic indicator value multiplier 
   uint                                digits;                // number of decimal places 
   string                              source_url;            // URL of a source where an event is published 
   string                              event_code;            // event code 
   string                              name;                  // event text name in the terminal language (in the current terminal encoding) 
  };

Структура значений:

struct MqlCalendarValue 
  { 
   ulong                               id;                    // value ID 
   ulong                               event_id;              // event ID 
   datetime                            time;                  // event date and time 
   datetime                            period;                // event reporting period 
   int                                 revision;              // revision of the published indicator relative to the reporting period 
   long                                actual_value;          // actual value multiplied by 10^6 or LONG_MIN if the value is not set 
   long                                prev_value;            // previous value multiplied by 10^6 or LONG_MIN if the value is not set 
   long                                revised_prev_value;    // revised previous value multiplied by 10^6 or LONG_MIN if the value is not set 
   long                                forecast_value;        // forecast value multiplied by 10^6 or LONG_MIN if the value is not set 
   ENUM_CALENDAR_EVENT_IMPACT          impact_type;           // potential impact on the currency rate 
  //--- functions checking the values 
   bool                         HasActualValue(void) const;   // returns true if actual_value is set 
   bool                         HasPreviousValue(void) const; // returns true if prev_value is set 
   bool                         HasRevisedValue(void) const;  // returns true if revised_prev_value is set 
   bool                         HasForecastValue(void) const; // returns true if forecast_value is set 
  //--- functions receiving the values 
   double                       GetActualValue(void) const;   // returns actual_value or nan if the value is no set 
   double                       GetPreviousValue(void) const; // returns prev_value or nan if the value is no set 
   double                       GetRevisedValue(void) const;  // returns revised_prev_value or nan if the value is no set 
   double                       GetForecastValue(void) const; // returns forecast_value or nan if the value is no set 
  };

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

MqlCalendarValue values[];
datetime startTime = TimeTradeServer() - PeriodSeconds(PERIOD_D1);
datetime endTime = TimeTradeServer() + PeriodSeconds(PERIOD_D1);

int valuesTotal = CalendarValueHistory(values, startTime, endTime, NULL, NULL);

Print("TOTAL VALUES = ", valuesTotal, " || Array size = ", ArraySize(values));

Здесь мы объявляем массив values типа структуры MqlCalendarValue, который будет содержать извлеченные данные экономического календаря. Затем мы устанавливаем переменные datetime, startTime и endTime, которые определяют временной диапазон для извлечения данных. Мы рассчитываем время начала значений как один день до текущего времени сервера, полученного с помощью функции TimeTradeServer. Функция PeriodSeconds используется для создания 24-часового смещения в секундах. Логика однодневного времени достигается с помощью константы PERIOD_D1. Аналогично, endTime устанавливается на один день позже текущего времени сервера, что позволяет фиксировать экономические события, происходящие в течение двух дней, сосредоточенных вокруг текущего момента.

Затем используем функцию CalendarValueHistory для заполнения массива значений экономическими событиями в указанном диапазоне времени. Эта функция возвращает общее количество событий, которое мы сохраняем в переменной valuesTotal. Параметры CalendarValueHistory включают массив values, startTime и endTime, as well as two NULL filters for country and currency type (we leave them NULL here to retrieve all events). Наконец, мы используем функцию Print для вывода общего количества значений и функцию ArraySize для вывода размера массива, чтобы подтвердить общее количество полученных событий и удостовериться, что массив содержит ожидаемые данные для дальнейшего использования в нашей торговой логике. При компиляции мы получаем следующий результат.

Подтверждение значений

Далее мы можем вывести эти значения в журнал, чтобы иметь возможность подтвердить то, что у нас есть.

if (valuesTotal >=0 ){
   Print("Calendar values as they are: ");
   ArrayPrint(values);
}

Здесь мы сначала проверяем, больше ли или равны ли общие значения нулю, что указывает на то, что функция CalendarValueHistory успешно извлекла некоторые события экономического календаря или вернула ноль без ошибок. Если это условие выполняется, мы используем функцию Print для вывода сообщения "Calendar values as they are:" (значения календаря как есть) в качестве заголовка, информирующего нас о том, что значения теперь будут отображаться. После этого мы называем функцию ArrayPrint, которая выводит все содержимое массива values в логи. После запуска мы имеем следующие данные.

Логи событий

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

for (int i = 0; i < valuesTotal; i++){

//---

}

Здесь мы создаем цикл for, который выполняет итерацию по каждому элементу в массиве values, содержащем данные экономического календаря. Цикл инициализирует целочисленную переменную i значением ноль, представляющим начальный индекс, и выполняется до тех пор, пока i меньше общих значений, которые представляют собой общее количество событий, извлеченных функцией CalendarValueHistory. С каждой итерацией мы увеличиваем i на единицу, что позволяет нам последовательно получать доступ к каждому экономическому событию в массиве values. Теперь внутри цикла мы можем обрабатывать или анализировать данные каждого события, что обеспечивает гибкость для таких задач, как сортировка событий, применение определенной торговой логики на основе сведений о событиях или вывод информации об отдельных событиях. Ниже приведена необходимая логика.

MqlCalendarEvent event;
CalendarEventById(values[i].event_id,event);

Мы объявляем переменную event типа MqlCalendarEvent, в которой будет храниться подробная информация о конкретном экономическом событии. Затем мы вызываем CalendarEventById, передавая два параметра. Первый параметр извлекает уникальный идентификатор текущего экономического события из массива values (на основе текущего индекса цикла i), а второй (event) действует как контейнер для хранения полной информации о событии. Используя функцию CalendarEventById, мы получаем доступ к полным данным о каждом конкретном событии, таким как его название, страна, прогноз и фактические значения, которые затем можно использовать для дополнительного анализа или принятия торговых решений. Чтобы подтвердить это, мы можем вывести идентификатор события следующим образом.

Print("Event ID ",values[i].event_id);

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

datetime startTime = TimeTradeServer() - PeriodSeconds(PERIOD_H1);
datetime endTime = TimeTradeServer() + PeriodSeconds(PERIOD_H1);

При запуске программы мы видим следующее.

Идентификаторы событий

Теперь мы можем перейти к получению фактических значений конкретного выбранного события, отличных от числовых значений событий. Чтобы добиться этого, нам просто нужно ввести ключевое слово event и использовать "оператор-точку", чтобы получить доступ ко всем методам и объектам этого класса или структуры. Вот что у вас должно получиться.

Оператор-точка

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

Print("Event ID ",values[i].event_id);
Print("Event Name = ",event.name);
Print("Event Code = ",event.event_code);
Print("Event Type = ",event.type);
Print("Event Sector = ",event.sector);
Print("Event Frequency = ",event.frequency);
Print("Event Release Mode = ",event.time_mode);
Print("Event Importance = ",EnumToString(event.importance));
Print("Event Time = ",values[i].time);
Print("Event URL = ",event.source_url);

Comment("Event ID ",values[i].event_id,
        "\nEvent Name = ",event.name,
        "\nEvent Code = ",event.event_code,
        "\nEvent Type = ",event.type,
        "\nEvent Sector = ",event.sector,
        "\nEvent Frequency = ",event.frequency,
        "\nEvent Release Mode = ",event.time_mode,
        "\nEvent Importance = ",EnumToString(event.importance),
        "\nEvent Time = ",values[i].time,
        "\nEvent URL = ",event.source_url);
}

Здесь мы используем функции Print для вывода сведений о каждом экономическом событии в массиве значений и отображения этой информации на вкладке Experts для удобства просмотра. Начнем с вывода идентификатора события из values[i], который однозначно идентифицирует событие. Далее мы извлекаем и выводим конкретные сведения о событии из переменной event, включая его имя, код события, тип, сектор, частоту, временной режим (указывающий режим времени выхода), важность (преобразованную в читаемую строку с помощью функции EnumToString) и фактическое запланированное время. Наконец, мы отображаем исходный Uniform Resource Locator (URL), который предоставляет ссылку на дополнительную информацию.

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

Данные события по идентификатору

Всё работает как надо. Чтобы получить доступ к данным о стране и валюте, мы внедряем еще одну структуру, которая обрабатывает значения стран. Ниже представлена необходимая логика. Она идентична тем, которые мы использовали.

MqlCalendarCountry country;
CalendarCountryById(event.country_id,country);

Здесь мы объявляем переменную country типа MqlCalendarCountry, в котором мы намеревались хранить специфичную для страны информацию, связанную с экономическим событием. Затем мы используем функцию CalendarCountryById для получения сведений о стране путем передачи двух параметров.

Первый параметр предоставляет уникальный идентификатор страны, связанной с текущим экономическим событием, в то время как параметр country служит контейнером для данных по этой стране. Вызывая функцию CalendarCountryById, мы заполняем нашу переменную country соответствующей информацией, такой как название страны, код и другие характеристики, что позволяет нам использовать эти данные для более контекстно-зависимого анализа и отображать сведения, специфичные для страны, вместе с каждым экономическим событием.

Для отображения мы снова печатаем информацию о стране.

Print("Country ID ",country.id);
Print("Country Name ",country.name);
Print("Country Code ",country.code);
Print("Country Currency ",country.currency);
Print("Country Currency Symbol ",country.currency_symbol);
Print("Country URL ",country.url_name);

Вот что мы получаем при запуске программы.

Данные по стране

Всё работает как надо. Мы рассмотрели необходимые MQL5-функции, которые предоставляют нам доступ к данным календаря. Теперь мы можем приступить к применению фильтров к нашему блоку кода, чтобы использовать в торговле данные по конкретной стране, степень важности новостей, валюты, а также новости, привязанные к определенному времени. Чтобы добиться динамики, мы можем перенести нашу логику в функцию, которую можно использовать для указанной выше цели.

//+------------------------------------------------------------------+
//|       FUNCTION TO GET NEWS EVENTS                                |
//+------------------------------------------------------------------+
bool isNewsEvent(){
   int totalNews = 0;
   bool isNews = false;
   
   //---
   
   return (isNews);
}

Мы определяем булеву функцию isNewsEvent, которая определит, доступны ли какие-либо экономические новостные события. Функция возвращает логическое значение, указывающее, присутствует ли новостное событие (true) или нет (false). Внутри функции мы объявляем целочисленную переменную totalNews и инициализируем ее нулем. Мы намерены использовать переменную для хранения общего количества соответствующих новостных событий, которые мы извлечем позже в функции. Мы также объявляем булеву переменную isNews и устанавливаем ее в значение false. Эта переменная будет действовать как флаг, переключаясь на значение true, если мы обнаружим какие-либо соответствующие новостные события во время выполнения функции.

В настоящее время функция просто возвращает значение isNews, которое по умолчанию равно false, поскольку в функции пока не обрабатываются новостные события. Эта структура функции обеспечивает основу для реализации логики, которая впоследствии может извлекать и проверять наличие новостей, устанавливая isNews в значение true, если события обнаружены. Именно к этой функции мы добавляем нашу ранее определенную логику из обработчика событий OnInit. Однако мы вызываем функцию обработчика событий, чтобы повлиять на логику нашей функции.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){
//---   
   if (isNewsEvent()){
      Print("______ ALERT: WE HAVE NEWS EVENT ___");
   }
   else if (isNewsEvent()==false){
      Print("______ ALERT: WE DON'T ANY HAVE NEWS EVENT ___");
   }
//---
   return(INIT_SUCCEEDED);
}

Здесь, внутри обработчика событий OnInit, мы начинаем с вызова функции isNewsEvent. Если функция возвращает true, что указывает на доступность новостного события, срабатывает блок if, и мы выводим сообщение "______ ALERT: WE HAVE NEWS EVENT ___" (внимание: новостное событие). Это сообщение оповещает нас об обнаружении экономического новостного события, которое мы при необходимости можем использовать для корректировки торговых стратегий.

При false (новостных событий нет) срабатывает блок else if и выводится "______ ALERT: WE DON'T HAVE ANY NEWS EVENT ___" (внимание: нет новостного события). Это сообщение предупреждает нас о том, что никаких текущих новостных событий не выявлено, что может указывать на то, что торговля может продолжаться без изменений. Наконец функция возвращает INIT_SUCCEEDED. Это константа, указывающая на то, что инициализация советника прошла успешно. Теперь, после вызова этого обработчика событий, мы можем продолжить применять фильтры к тем новостям, которые имеют для нас значение. В настоящее время у нас программа привязана к символу AUDUSD. Давайте разработаем логику, которая гарантирует, что будут рассматриваться только новости США.

string currency_filter = "USD";
string currency_base = SymbolInfoString(_Symbol,SYMBOL_CURRENCY_BASE);
string currency_quote = StringSubstr(_Symbol,3,3);
if (currency_base != currency_filter && currency_quote != currency_filter){
   Print("Currency (",currency_base," | ",currency_quote,
         ") is not equal equal to ",currency_filter);
   return false;
}

Начнем с определения двух строковых переменных, currency_filter и currency_base, для упрощения проверки того, соответствует ли текущий символ указанному фильтру валюты "USD". Переменная currency_filter инициализируется значением "USD", представляющим целевую валюту, которую мы хотим отслеживать. Затем мы извлекаем базовую валюту текущего символа (например, AUD в паре AUDUSD) с помощью функции SymbolInfoString и сохраняем ее в currency_base.

Далее определяем currency_quote, извлекая валюту котировки из текущего символа, беря последние три символа с использованием функции StringSubstr, поскольку прямого доступа к котируемой валюте не существует. Например, в паре AUDUSD функция StringSubstr извлечет "USD", валюту котировки.

Затем мы проверяем, отличаются ли базовая и котируемая валюты от валюты фильтра. Если они не соответствуют фильтру целевой валюты (в данном случае USD), мы выводим сообщение о том, что валюты символа не соответствуют фильтру валюты. Затем функция возвращает false, фактически завершая дальнейшую обработку, если символ не имеет отношения к указанной валюте. При запуске с другими символами получаем следующий результат.

Фильтр валют

Из визуализации видно, что при загрузке программы на графики AUDUSD и USDJPY мы не получаем никаких ошибок, но при загрузке на график EURJPY мы получаем ошибку, указывающую на то, что ни одна из цифр валюты не соответствует нашей предопределенной валюте фильтра. Теперь мы можем продолжить применять несколько фильтров динамически по важности и времени события.

if (StringFind(_Symbol,country.currency) >= 0){
   if (event.importance == CALENDAR_IMPORTANCE_MODERATE){
      if (values[i].time <= TimeTradeServer() && values[i].time >= timeBefore){
         Print(event.name," > ", country.currency," > ", EnumToString(event.importance)," Time= ",values[i].time," (ALREADY RELEASED)");
         totalNews++;
      }
            
      if (values[i].time >= TimeTradeServer() && values[i].time <= timeAfter){
         Print(event.name," > ", country.currency," > ", EnumToString(event.importance)," Time= ",values[i].time," (NOT YET RELEASED)");
         totalNews++;
      }
   }
}

Мы реализуем ряд вложенных условий для определения релевантных новостных событий для определенной валюты, уделяя особое внимание событиям, отнесенным к категории "умеренной важности" (moderate importance) и попадающим в определенный временной диапазон. Сначала мы проверяем, содержит ли название текущего торгового символа (_Symbol) валюту, связанную с событием. Мы делаем это с помощью функции StringFind, которая гарантирует, что мы рассматриваем только события, привязанные к валюте торгового символа.

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

После того, как мы определили событие средней важности, мы оцениваем его время относительно текущего времени сервера (TimeTradeServer), используя две отдельные проверки. В первой проверке мы определяем, является ли время события более ранним или равным текущему времени, но более поздним, чем timeBefore. Если это так, это означает, что событие уже было опубликовано в указанные нами сроки. Далее используем функцию Print для регистрации сведений о событии, включая его название, связанную валюту, важность и время, с пометкой ALREADY RELEASED (выпущено). Мы также увеличиваем переменную totalNews, чтобы отслеживать события, соответствующие нашим критериям. Во второй проверке мы определяем, является ли время события более поздним или равным текущему времени, но более ранним или равным timeAfter, что указывает на то, что событие приближается, но все еще находится в пределах указанного нами будущего периода времени.

пять же, мы регистрируем схожие детали событий, используя функцию Print с пометкой NOT YET RELEASED (еще не выпущено) и увеличив переменную totalNews для этого дополнительного соответствующего события. Вы могли заметить, что мы использовали в логике несколько разных временных переменных. Они нужны лишь для того, чтобы убедиться, что событие находится в пределах временного диапазона для принятия мер. Вот их логика.

datetime timeRange = PeriodSeconds(PERIOD_D1);
datetime timeBefore = TimeTradeServer() - timeRange;
datetime timeAfter = TimeTradeServer() + timeRange;
   
Print("FURTHEST TIME LOOK BACK = ",timeBefore," >>> CURRENT = ",TimeTradeServer());

Мы объявляем эту логику непосредственно перед циклом for, чтобы установить временной диапазон вокруг текущего времени сервера для того, чтобы определить, насколько далеко в прошлое и будущее мы хотим рассматривать новостные события. Сначала мы объявляем переменную timeRange и присваиваем ей продолжительность одного дня с помощью функции PeriodSeconds. Это позволяет нам работать со стандартизированным временным интервалом в 24 часа, однако вы можете просто настроить его на желаемый вами диапазон, например, на 15 минут до и после выпуска новостей. Далее мы определяем две дополнительные переменные даты и времени - timeBefore и timeAfter.

Мы вычисляем переменную timeBefore путем вычитания временного диапазона из текущего времени сервера, что дает нам самую дальнюю точку времени, на которую мы хотим вернуться. Аналогично, timeAfter определяется путем добавления timeRange к текущему времени сервера, предоставляя самую позднюю точку времени, которую мы хотим учитывать в будущем. Вместе timeBefore и timeAfter создают 24-часовое окно, центрированное вокруг текущего времени, что помогает нам фиксировать события, которые либо только что произошли, либо ожидаются в ближайшее время.

Временной охват

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

if (totalNews > 0){
   isNews = true;
   Print(">>>>>>> (FOUND NEWS) TOTAL NEWS = ",totalNews,"/",ArraySize(values));
}
else if (totalNews <= 0){
   isNews = false;
   Print(">>>>>>> (NOT FOUND NEWS) TOTAL NEWS = ",totalNews,"/",ArraySize(values));
}

Здесь мы оцениваем, были ли выявлены какие-либо значимые новостные события на основе общего количества зарегистрированных новостей. Если общее количество новостей больше нуля, это означает, что было найдено по крайней мере одно новостное событие, соответствующее нашим критериям. В этом случае мы устанавливаем переменную isNews в true и выводим сообщение, отображающее общее количество соответствующих новостных событий и размер массива values. Сообщение с меткой FOUND NEWS (найденные новости) также включает в себя общее количество идентифицированных новостей и все изначально рассмотренные новости, указывая количество релевантных новостных событий из общего числа найденных событий.

И наоборот, если общее количество новостей равно нулю или меньше, это означает, что не было найдено ни одного релевантного новостного события. В этом сценарии мы устанавливаем isNews в false и выводим сообщение с меткой NOT FOUND NEWS (новости не найдены), показывающее, что общее количество новостей равно нулю, как и размер массива values. Эта структура помогает нам отслеживать, были ли найдены какие-либо новостные события, соответствующие нашим критериям, и предоставляет логи результатов, полезные для подтверждения результатов проверки новостей. После компиляции получаем следующий результат.

0 новостей

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

datetime startTime = TimeTradeServer() - PeriodSeconds(PERIOD_D1);
datetime endTime = TimeTradeServer() + PeriodSeconds(PERIOD_D1);

Если вернуть диапазон новостей к одному дню, то получим следующий результат.

5 новостей

На изображении мы видим, что у нас есть 5 релевантных новостей из 81, и мы выводим наличие релевантных новостных событий, которые мы можем использовать для принятия торговых решений (вход или выход). Полный код функции, отвечающей за идентификацию и сортировку новостей из календаря MQL5, выглядит так:

//+------------------------------------------------------------------+
//|       FUNCTION TO GET NEWS EVENTS                                |
//+------------------------------------------------------------------+
bool isNewsEvent(){
   int totalNews = 0;
   bool isNews = false;
   
   MqlCalendarValue values[];
   
   datetime startTime = TimeTradeServer() - PeriodSeconds(PERIOD_D1);
   datetime endTime = TimeTradeServer() + PeriodSeconds(PERIOD_D1);
   
   //string currency_filter = "USD";
   //string currency_base = SymbolInfoString(_Symbol,SYMBOL_CURRENCY_BASE);
   //string currency_quote = StringSubstr(_Symbol,3,3);
   //if (currency_base != currency_filter && currency_quote != currency_filter){
   //   Print("Currency (",currency_base," | ",currency_quote,
   //         ") is not equal equal to ",currency_filter);
   //   return false;
   //}
   
   int valuesTotal = CalendarValueHistory(values,startTime,endTime,NULL,NULL);
   
   Print("TOTAL VALUES = ",valuesTotal," || Array size = ",ArraySize(values));
   
   //if (valuesTotal >=0 ){
   //   Print("Calendar values as they are: ");
   //   ArrayPrint(values);
   //}
   
   datetime timeRange = PeriodSeconds(PERIOD_D1);
   datetime timeBefore = TimeTradeServer() - timeRange;
   datetime timeAfter = TimeTradeServer() + timeRange;
   
   Print("Current time = ",TimeTradeServer());
   Print("FURTHEST TIME LOOK BACK = ",timeBefore," >>> LOOK FORE = ",timeAfter);
   
   for (int i = 0; i < valuesTotal; i++){
      MqlCalendarEvent event;
      CalendarEventById(values[i].event_id,event);
      
      
      MqlCalendarCountry country;
      CalendarCountryById(event.country_id,country);
      
      if (StringFind(_Symbol,country.currency) >= 0){
         if (event.importance == CALENDAR_IMPORTANCE_MODERATE){
            if (values[i].time <= TimeTradeServer() && values[i].time >= timeBefore){
               Print(event.name," > ", country.currency," > ", EnumToString(event.importance)," Time= ",values[i].time," (ALREADY RELEASED)");
               totalNews++;
            }
            
            if (values[i].time >= TimeTradeServer() && values[i].time <= timeAfter){
               Print(event.name," > ", country.currency," > ", EnumToString(event.importance)," Time= ",values[i].time," (NOT YET RELEASED)");
               totalNews++;
            }
         }
      }
      
   }
   
   if (totalNews > 0){
      isNews = true;
      Print(">>>>>>> (FOUND NEWS) TOTAL NEWS = ",totalNews,"/",ArraySize(values));
   }
   else if (totalNews <= 0){
      isNews = false;
      Print(">>>>>>> (NOT FOUND NEWS) TOTAL NEWS = ",totalNews,"/",ArraySize(values));
   }
   
   return (isNews);
}


Заключение

Мы начали изучать экономический календарь MQL5. Мы научились извлекать информацию и оценивать ее в соответствии с важностью валют и значимостью событий. Мы разработали структурированный процесс, который позволяет нам извлекать данные из экономического календаря, сортировать их по важным критериям, таким как валюта и значимость события, и определять, произошли ли они или еще нет. Такой подход имеет решающее значение для автоматизации торговых систем, способных реагировать на важные экономические события, предоставляя нам преимущество в управлении рыночными колебаниями.

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

Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/16223

Прикрепленные файлы |
Майнинг данных балансов центробанков и получение картины мировой ликвидности Майнинг данных балансов центробанков и получение картины мировой ликвидности
Майнинг данных балансов центробанков позволяет получить картину мировой ликвидности рынка Форекс и ключевых валют. Мы объединяем данные ФРС, ЕЦБ, BOJ и PBoC в композитный индекс и применяем машинное обучение для выявления скрытых закономерностей. Такой подход превращает сырой поток данных в реальные торговые сигналы, соединяя фундаментальный и технический анализ.
Изучаем конформное прогнозирование финансовых временных рядов Изучаем конформное прогнозирование финансовых временных рядов
В этой статье вы познакомитесь с конформными предсказаниями и библиотекой MAPIE, которая их реализует. Данный подход является одним из самых современных в машинном обучении и позволяет сосредоточиться на контроле рисков для уже существующих разнообразных моделей машинного обучения. Конформные предсказания, сами по себе, не являются способом поиска закономерностей в данных. Они лишь определяют степень уверенности существующих моделей в предсказании конкретных примеров и позволяют фильтровать надежные предсказания.
От начального до среднего уровня: Рекурсия От начального до среднего уровня: Рекурсия
В этой статье мы рассмотрим очень интересную и довольно интересную концепцию программирования, хотя к ней следует относиться с большой осторожностью, поскольку неправильное её использование или непонимание превращает относительно простые программы в нечто неоправданно сложное. Но правильное использование и идеальная адаптация в одинаково подходящих ситуациях делают рекурсию отличным союзником в решении вопросов, которые в другом случае были бы гораздо более трудоемкими и длительными. Представленные здесь материалы предназначены только для изучения. Ни в коем случае нельзя рассматривать это приложение как окончательное, цели которого будут иные, кроме изучения представленных концепций.
Разрабатываем мультивалютный советник (Часть 27): Компонент для вывода многострочного текста Разрабатываем мультивалютный советник (Часть 27): Компонент для вывода многострочного текста
При возникновении необходимости вывести текстовую информацию на график мы можем воспользоваться функцией Comment(). Но её возможности достаточно сильно ограничены. Поэтому, в рамках этой статьи, мы создадим собственный компонент — диалоговое окно на весь экран, способное выводить многострочный текст с гибкими настройками шрифта и поддержкой прокрутки.