Использование Экономического календаря MQL5 для фильтрации новостей (Часть 1): Реализация временных окон до и после новостей в MQL5
Типичные и нетипичные проблемы
Большинство новостных фильтров для торговых роботов выполняют лишь одну функцию — блокируют открытие новых сделок во время публикации новостей. Этого недостаточно.
Во время публикации важных экономических данных на рынке часто наблюдаются:
- резкие скачки цен;
- расширение спреда;
- проскальзывание;
- выносы стопов шпильками.
Открытые позиции остаются подверженными риску, что может полностью свести на нет статистическое преимущество стратегии.
К числу дополнительных проблем относятся:
- Соблюдение правил проп-фирм — необходимо соблюдать строгие временные окна до и после определенных новостных событий.
- Валютная релевантность — не все новости влияют на все символы; фильтрация должна учитывать валюты символа.
- Нестабильность стратегии во время новостей — стоп-лоссы часто срабатывают из-за расширения спреда, а не реального движения цены.
- Потеря состояния после перезапуска советника или VPS — многие реализации не сохраняют состояние торговой логики при прерываниях.
- Отсутствие тестового режима — сложно проверить поведение без реальных новостных событий.
Решение
Решение состоит в создании структурированного новостного фильтра с использованием встроенного Экономического календаря MQL5.
Система:
- оценивает релевантность новостей по валютам символа;
- фильтрует по уровню важности;
- применяет настраиваемые интервалы до и после новостей;
- блокирует открытие новых сделок во время активных новостных окон;
- при необходимости закрывает позиции перед событиями высокой важности;
- корректно определяет начало и окончание новостного окна.
Вместо простого переключателя "вкл./выкл." используется механизм, учитывающий риски.
Рамки статьи
Это первая часть торговой системы для MQL5, учитывающей новости.
В этой статье рассматриваются:
- выявление новостей по уровню важности;
- сопоставление событий с символами на основе валютной логики;
- определение окон до и после новостей;
- блокировка открытия новых сделок;
- закрытие позиций перед событиями высокой важности.
Отдельно будут рассмотрены расширенные механизмы управления стоп-лоссами и восстановления состояния, чтобы реализация оставалась сфокусированной и практичной.
Ниже приведена схема рабочего процесса, кратко показывающая работу новостного фильтра в этой статье.

Экономический календарь MQL5 – подход, используемый в этой статье, и почему он необходим
Раньше трейдерам приходилось использовать веб-запросы к внешним сайтам для получения новостных данных. Такой подход медленный, ненадежный и затрудняет точный бэктест. Сегодня MQL5 предоставляет функции экономического календаря, позволяющие получать экономические данные непосредственно из терминала.
Этот метод быстрее, поскольку не использует HTTP-запросы, а получает данные из локального кэша. При тестировании на исторических данных новостные события можно вручную имитировать в нужные моменты. Кроме того, этот подход надежнее: не нужно учитывать неработающие ссылки, изменения API и другие внешние проблемы.
Ограничения и проектные соображения
Эта реализация спроектирована как легковесная, детерминированная и совместимая со встроенным Экономическим календарем MQL5. В связи с этим необходимо четко сформулировать несколько ограничений и допущений.- Новостной фильтр загружает события календаря в пределах скользящего окна продолжительностью 24 часа. Такой подход сводит к минимуму повторные запросы к календарю и повышает производительность во время выполнения. Однако события за пределами следующих 24 часов не загружаются заранее, поэтому для сохранения точности кэш календаря необходимо периодически обновлять.
- Эвристическое сопоставление символов с валютами. Релевантность символа определяется с помощью эвристических правил: для FX-символов извлекаются базовая и котируемая валюты, а для индексов, металлов и сырьевых товаров используется распознавание по ключевым словам. Хотя этот подход работает со стандартными правилами именования брокеров, он не гарантирует охват всех пользовательских символов. Поэтому предусмотрен входной параметр для ручного переопределения валюты, позволяющий обрабатывать нестандартные ситуации и проприетарные форматы символов.
- Все сравнения времени выполняются по текущему времени торгового сервера. События Экономического календаря MQL5 также снабжены временными метками относительно серверной среды. Однако расхождения могут возникать из-за различий часовых поясов серверов брокеров, перехода на летнее время и условий тестирования на исторических данных. Поэтому интервалы до и после новостей являются настраиваемыми, а не фиксированными.
- Эта реализация полностью опирается на Экономический календарь MQL5, предоставляемый брокером. Если брокер предоставляет некорректные данные по определенным событиям, странам или уровням важности, такие события не могут быть обнаружены фильтром. Поэтому полнота системы зависит от полноты базовых календарных данных, предоставляемых брокером.
Работа с временными окнами
Новостной фильтр реагирует не только в точный момент публикации события. Вместо этого он задает настраиваемый временной интервал вокруг события, чтобы учесть волатильность перед публикацией и нестабильность рынка после нее. Этот интервал состоит из периода до новости — минут до события, фактического времени публикации новости и периода после новости — минут после события. Любой момент времени, попадающий в этот общий интервал, рассматривается как активный новостной период.
Ниже приведено изображение, показывающее работу новостного окна.

Реализация
Шаг 1. Определение основных структур
Прежде чем выявлять экономические новости или реагировать на них, необходимо определить, как будут храниться новостные данные и как система будет отслеживать активность новостного окна.
Во многих реализациях начального уровня новостные события проверяются непосредственно на каждом тике без надлежащей организации данных. Это быстро приводит к избыточной нагрузке на процессор, повторным вычислениям и запутанной логике, которую сложно сопровождать и расширять. Чтобы избежать этих проблем, сначала определяются простые структуры данных с четкой областью ответственности, служащие двум основным целям:- хранение событий экономического календаря, полученных из MetaTrader;
- отслеживание того, находится ли торговая система в периоде ограничений, связанных с новостями.
Использование структуры Экономического календаря MQL5
MetaTrader 5 предоставляет встроенную структуру MqlCalendarValue.
Эта структура содержит всю необходимую информацию об экономическом событии, включая его запланированное время, соответствующую валюту, уровень важности — низкий, средний или высокий, — а также фактическое, прогнозное и предыдущее значения.
Вместо определения пользовательской структуры для экономических событий используется этот встроенный тип, обеспечивающий совместимость с Экономическим календарем MQL5 и снижающий риск ошибок реализации.
Данные календаря хранятся в массиве, который позднее будет содержать все релевантные события текущего торгового дня.

Сценарии и ожидаемое поведение
Ниже показано ожидаемое поведение новостного фильтра для различных символов и экономических событий. Предполагается, что Экономический календарь содержит соответствующее событие и настроенный временной интервал активен. Приведенные ниже иллюстрации являются примерами и не охватывают все возможные сценарии работы фильтра.
| Символ | Валюта события | Важность события | В новостном окне | Ожидаемый результат |
|---|---|---|---|---|
| EURUSD | EUR или USD | Высокая (красная) | Да | Открытие новых сделок заблокировано |
| EURUSD | EUR или USD | Высокая | Нет | Торговля разрешена |
| EURUSD | EUR или USD | Низкая (серая) | Да | Если фильтрация низкой важности отключена, торговля разрешена |
| EURUSD | GBP | Высокая, низкая или средняя | Да | Торговля разрешена |
| GOLD | USD | Высокая | Да | Открытие новых сделок заблокировано |
| US100 | USD | Средняя (желтая) | Да | Открытие новых сделок блокируется, если включен фильтр событий средней важности. |
| GBPJPY | GBP или JPY | Высокая | Нет | Торговля разрешена |
| AUDUSD | AUD или USD | Высокая | После новостного окна | Торговля разрешена |
В каждом случае решение принимается исключительно на основе валютной релевантности и попадания в настроенное временное окно. Если валюта события совпадает с одной из релевантных валют символа, а текущее время попадает в настроенное временное окно, новостной фильтр переходит в активное состояние.
Для ручной проверки в Тестере стратегий можно использовать тестовые входные параметры, имитирующие конкретное время событий. Это позволяет детерминированно активировать новостное окно, не полагаясь на актуальные данные календаря.
Понимание релевантности валют для символа
Экономические новостные события связаны с валютами, а не с торговыми символами. Чтобы определить релевантность события, система выделяет набор валют, связанных с текущим торговым символом, и сравнивает их с валютой, указанной для события.
Для стандартных FX-символов базовая и котируемая валюты извлекаются непосредственно из имени символа: например, EURUSD содержит EUR и USD.
Для индексов, металлов и сырьевых товаров используются заранее заданные эвристические правила на основе ключевых слов, связывающие символ с наиболее значимой валютой: например, GOLD — с USD, а GER40 — с EUR.
Если символ не соответствует ни одному известному шаблону, во входных параметрах можно задать ручное переопределение валюты и явно указать отслеживаемую валюту. Экономическое событие считается релевантным, если его валюта совпадает хотя бы с одной из валют, связанных с данным символом.
Практический шаг
Отслеживание состояния новостного фильтра
Новостной фильтр не должен повторно проверять одну и ту же информацию на каждом тике.
Чтобы избежать этого, вводится простой флаг состояния, позволяющий системе отслеживать, находится ли она в новостном окне с ограничениями.
Кроме того, используется временная метка для отслеживания момента последней загрузки данных календаря. Это позволяет обновлять данные календаря только при необходимости, а не запрашивать их постоянно.
Такой подход помогает снизить нагрузку на процессор, сделать выполнение эффективнее, сохранить логику предсказуемой и понятной, а также обеспечить ясное логирование и отладку.
К концу этого шага в советнике еще нет рабочей новостной логики, но уже создана ясная и масштабируемая структура для последующих этапов.
//+------------------------------------------------------------------+ //| News Filter Integration.mq5 | //| soloharbinger | //+------------------------------------------------------------------+ #property copyright "soloharbinger" #property link "" #property version "1.01" #include <Trade/Trade.mqh> //=================================================================== // GLOBAL VARIABLES | //=================================================================== MqlCalendarValue TodayEvents[]; // Stores calendar events for the trading day datetime lastCalendarLoad = 0; // TimeStamp of the last calendar update into our above value CTrade trade; // Ctrade instance for order management //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Print("News Filter Demo initialized"); //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- // News detection logics will be implemented in the next steps } //+------------------------------------------------------------------+
Шаг 2. Загрузка и кэширование событий Экономического календаря MQL5
После создания базовых структур данных необходимо эффективно получать данные экономических новостей.
Экономический календарь MQL5 содержит тысячи событий за несколько лет. Поиск по всему календарю на каждом тике был бы крайне неэффективен и не нужен. Такой подход нерационально использует ресурсы процессора и может значительно замедлить работу советника, особенно при запуске нескольких экземпляров.
Чтобы избежать этого, вводится механизм контролируемой загрузки, извлекающий только действительно необходимые события.
Почему необходимо кэширование
События экономических новостей не меняются каждую секунду: они запланированы заранее и могут повторно использоваться на многих тиках. Поэтому нет смысла повторно запрашивать данные календаря при каждом обновлении цены.
Вместо этого события календаря загружаются один раз при инициализации и затем периодически через заданный интервал времени, чтобы учитывать внезапные изменения в расписании публикаций или событиях.
Полученные данные сохраняются в массиве TodayEvents[], откуда последующая логика может повторно использовать их без дополнительных затрат.
Определение периода загрузки событий
В этой статье используется скользящий период продолжительностью 24 часа — от текущего серверного времени до момента через 24 часа.
Этот временной интервал достаточно широк, чтобы охватить новости перед сессией, внутридневные события, а также публикации в конце сессии и в ночное время. Точную продолжительность периода можно настроить, но 24 часа — понятная и удобная отправная точка для начинающих.
Функция загрузки событий календаря
Логика получения данных календаря помещается в отдельную функцию.
Это сохраняет структуру кода и предотвращает рассредоточение логики календаря по всему советнику.
Функция проверяет, загружался ли календарь недавно, пропускает повторную загрузку, если кэшированные данные все еще актуальны, запрашивает Экономический календарь MQL5 за заданный период времени и сохраняет результаты в массиве TodayEvents[].
На данном этапе фильтрация еще не применяется. Здесь мы лишь собираем исходные данные о событиях.
//=================================================================== // Load calendar (24-hour horizon) //=================================================================== void LoadTodayCalendarEvents() { datetime now = TimeCurrent(); datetime fromTime = now; datetime toTime = now + 24 * 3600; // Load next 24 hours ArrayFree(TodayEvents); int count = CalendarValueHistory(TodayEvents, fromTime, toTime); PrintFormat("Loaded %d calendar records for the next 24 hours.", count); if(count <= 0) { // Still update timestamp to prevent constant reloading attempts lastCalendarLoad = now; return; } // Debug: print first few events for verification for(int i = 0; i < MathMin(count, 5); i++) { MqlCalendarEvent ev; if(CalendarEventById(TodayEvents[i].event_id, ev)) { PrintFormat("Event %d: %s | Time: %s | Importance: %d", i, ev.name, TimeToString(TodayEvents[i].time), ev.importance); } } lastCalendarLoad = now; }

Шаг 3. Интеллектуальная фильтрация валют
Распространенная проблема базовых новостных фильтров — нерелевантная блокировка сделок.
Например, если советник торгует EURUSD, он не должен приостанавливать торговлю только из-за публикации новости высокой важности, связанной с австралийским долларом (AUD). К сожалению, во многих упрощенных реализациях все новости считаются одинаково опасными, что приводит к упущенным торговым возможностям и ненужным простоям.
Для решения этой проблемы вводится интеллектуальная фильтрация валют.
Цель этого шага проста: реагировать только на новостные события, действительно релевантные торгуемому символу.
Почему важна фильтрация валют
Каждое экономическое событие связано с конкретной страной и, следовательно, с конкретной валютой.
В то же время на каждый торговый символ влияют одна или несколько базовых валют.
Если эти два элемента не сопоставлены правильно:
- советник может приостанавливать торговлю, когда этого делать не следует, или, что еще хуже, игнорировать новости, действительно влияющие на символ.
Поэтому новостной фильтр должен ответить на два вопроса:
- от каких валют зависит этот торговый символ и к какой валюте относится данное новостное событие?
Только при совпадении этих двух ответов событие следует считать релевантным.
Извлечение релевантных валют из торгового символа
Сначала определяются валюты, влияющие на текущий символ.
Для стандартных валютных пар Forex это просто: первые три буквы обозначают базовую валюту, а следующие три — котируемую валюту.
Например:
- EURUSD → EUR и USD, GBPJPY → GBP и JPY.
Однако не все инструменты соответствуют этому формату.
Индексы, металлы и сырьевые товары часто требуют особой обработки.
Чтобы сохранить гибкость системы, эта логика инкапсулируется в функции GetRelevantCurrencies().
Эта функция автоматически извлекает базовую и котируемую валюты валютных пар, применяет простое распознавание по ключевым словам для индексов и сырьевых товаров, допускает ручное переопределение при недостаточности автоматического определения и возвращает разделенный запятыми список валют, релевантных символу.
//=================================================================== // Helper: Return CSV list of relevant currencies for symbol //=================================================================== string GetRelevantCurrencies(string symbol) { // 1. Check Manual Override if(StringLen(SymbolCurrencyOverride) > 0) { return SymbolCurrencyOverride; } string upper = symbol; StringToUpper(upper); // 2. Standard Forex Pair Logic (e.g. EURUSD -> EUR,USD) if(StringLen(symbol) == 6) { string baseCurr = StringSubstr(upper, 0, 3); string quoteCurr = StringSubstr(upper, 3, 3); return baseCurr + "," + quoteCurr; } // 3. Heuristics for Indices/Commodities if(StringFind(upper, "GER") != -1 || StringFind(upper, "DE40") != -1 || StringFind(upper, "DAX") != -1) return "EUR"; if(StringFind(upper, "UK") != -1 || StringFind(upper, "FTSE") != -1) return "GBP"; if(StringFind(upper, "US30") != -1 || StringFind(upper, "DJ") != -1) return "USD"; if(StringFind(upper, "SPX") != -1 || StringFind(upper, "US500") != -1) return "USD"; if(StringFind(upper, "NAS") != -1 || StringFind(upper, "US100") != -1) return "USD"; if(StringFind(upper, "XAU") != -1 || StringFind(upper, "GOLD") != -1) return "USD"; if(StringFind(upper, "XAG") != -1 || StringFind(upper, "SILVER") != -1) return "USD"; if(StringFind(upper, "OIL") != -1 || StringFind(upper, "WTI") != -1 || StringFind(upper, "BRENT") != -1) return "USD"; if(StringFind(upper, "JPN") != -1 || StringFind(upper, "NIK") != -1) return "JPY"; if(StringFind(upper, "AUD") != -1) return "AUD"; if(StringFind(upper, "CAD") != -1) return "CAD"; if(StringFind(upper, "NZD") != -1) return "NZD"; if(StringFind(upper, "CHF") != -1) return "CHF"; if(StringFind(upper, "EUR") != -1) return "EUR"; if(StringFind(upper, "GBP") != -1) return "GBP"; if(StringFind(upper, "JPY") != -1) return "JPY"; // Fallback: if we can't guess, return nothing (safe mode) return ""; }
На этом этапе советник знает релевантные валюты текущего символа, но еще не знает, к какой валюте относится новостное событие.
Далее решим эту задачу.
Определение валюты новостного события:
Записи Экономического календаря MQL5 не содержат код валюты, такой как USD или EUR, напрямую. Вместо этого каждое событие привязано к идентификатору страны. Чтобы получить валюту события, необходимо запросить сведения о стране события и определить связанную с ней валюту.
MQL5 предоставляет прямой и надежный способ выполнить это с помощью функции CalendarCountryById().
Эта логика выносится во вспомогательную функцию GetCurrencyFromEventDirect().
//=================================================================== // Utility: Get currency from calendar event (via Country ID) //=================================================================== string GetCurrencyFromEventDirect(const MqlCalendarEvent &ev) { MqlCalendarCountry country; if(CalendarCountryById(ev.country_id, country)) { return country.currency; // Returns "USD", "EUR", etc. } return ""; }
Эта функция позволяет преобразовать событие календаря в конкретный код валюты, например USD, EUR или GBP.
Что достигнуто на данном этапе
К концу этого этапа советник сможет определить валюты, влияющие на текущий символ, и установить валюту новостного события. Кроме того, будет заложена основа для игнорирования нерелевантных новостных событий.
Пока логика блокировки открытия новых сделок не применяется.
На этом этапе система еще не вмешивается в торговлю: она лишь определяет релевантность, что важно для любого интеллектуального новостного фильтра.Далее кэшированные события календаря из шага 2 сопоставляются с релевантными валютами символа из шага 3, чтобы определить активность релевантного события. На этом этапе определяются временные окна и фильтрация по уровню важности.
Шаг 4. Обнаружение релевантных новостных событий и ограничение торговли во время них
Теперь, когда события календаря можно загружать и кэшировать, а релевантные для торгового символа валюты определены, следует проверить, есть ли в данный момент релевантные экономические новости, влияющие на этот символ. На данном этапе советник только обнаруживает новости и определяет количество минут до и после их публикации, в течение которых следует избегать торговли.
Общие правила обнаружения
Новостное событие считается релевантным только при одновременном выполнении четырех условий: оно присутствует в кэшированных данных календаря, его уровень важности соответствует настройкам фильтра, его валюта совпадает с одной из релевантных валют символа, а текущее время попадает в заданное окно перед новостью или после нее.
Только при выполнении всех четырех условий функция сообщает об активности новостного периода.
Безопасное обновление данных календаря
Перед просмотром событий проверяется, остаются ли данные календаря актуальными.
Данные календаря обновляются только если они еще не загружались или кэшированные данные старше заданного интервала, например 6 часов.
Это позволяет избежать ненужных вызовов функций календаря на каждом тике и не пропустить обновление новостных данных.
Функция обнаружения:
//=================================================================== // Core Detection Logic // Returns true if 'now' is inside a news window for the specific symbol //=================================================================== bool isUpcomingNews(const string symbol) { datetime now = TimeCurrent(); // A. Cache Management if(lastCalendarLoad == 0 || (now - lastCalendarLoad) > (datetime)CacheReloadHours * 3600) { LoadTodayCalendarEvents(); } if(ArraySize(TodayEvents) == 0) return false; // B. Testing Simulation if(EnableNewsTesting) { if(TestNewsNow) return true; datetime t = StringToTime(TestNewsTime); if(t > 0) { datetime start = t - TestNewsDuration * 60; datetime end = t + TestNewsDuration * 60; if(now >= start && now <= end) return true; } } // C. Optimization: Prepare Currency List OUTSIDE the loop string relevant = GetRelevantCurrencies(symbol); if(StringLen(relevant) == 0) return false; string currencyArray[]; int currencyCount = StringSplit(relevant, ',', currencyArray); for(int k = 0; k < currencyCount; k++) { StringTrimLeft(currencyArray[k]); StringTrimRight(currencyArray[k]); StringToUpper(currencyArray[k]); } // D. Event Scan for(int i = 0; i < ArraySize(TodayEvents); i++) { MqlCalendarEvent ev; // Retrieve event details from ID if(!CalendarEventById(TodayEvents[i].event_id, ev)) continue; // 1. Importance Filter bool okImportance = false; switch(NewsImportanceMode) { case NEWS_HIGH_ONLY: okImportance = (ev.importance == CALENDAR_IMPORTANCE_HIGH); break; case NEWS_MODERATE_ONLY: okImportance = (ev.importance == CALENDAR_IMPORTANCE_MODERATE); break; case NEWS_HIGH_AND_MODERATE: okImportance = (ev.importance == CALENDAR_IMPORTANCE_HIGH || ev.importance == CALENDAR_IMPORTANCE_MODERATE); break; } if(!okImportance) continue; // 2. Currency Relevance Filter string eventCurrency = GetCurrencyFromEventDirect(ev); if(StringLen(eventCurrency) == 0) continue; bool affect = false; for(int j = 0; j < currencyCount; j++) { if(eventCurrency == currencyArray[j]) { affect = true; break; } } if(!affect) continue; // 3. Time Window Check datetime eventTime = TodayEvents[i].time; datetime windowStart = eventTime - (NewsMinutesBefore * 60); datetime windowEnd = eventTime + (NewsMinutesAfter * 60); if(now >= windowStart && now <= windowEnd) { // Optional: Print once per detection to avoid log spam static string lastDetectedKey = ""; string key = ev.name + "|" + TimeToString(eventTime); if(key != lastDetectedKey) { PrintFormat("NEWS: %s | Time: %s | Currency: %s", ev.name, TimeToString(eventTime), eventCurrency); lastDetectedKey = key; } return true; } } return false; }
Упрощение обнаружения для советника
Чтобы остальная часть советника оставалась ясной и читаемой, логика обнаружения помещается в простую интерфейсную функцию.
Благодаря этому логика обнаружения остается централизованной.
// Wrapper for external calls bool IsNewsTime(string symbol) { return isUpcomingNews(symbol); }
На этом этапе в других частях советника, где требуется новостной фильтр, можно безопасно использовать следующую конструкцию:
if(IsNewsTime(_Symbol))
{
// Detect News
}
Шаг 5. Блокировка открытия новых сделок во время новостных окон
На данном этапе советник уже способен точно выявлять релевантные экономические новостные события. Заключительный этап части 1 — использовать эту логику обнаружения для блокировки открытия новых сделок в заданном временном окне до и после новостных событий.Этот подход полностью соответствует требованиям проп-фирм, где наиболее распространено следующее ограничение: "Во время новостей высокой важности запрещено открывать новые сделки".
Важно отметить, что существующие сделки никак не изменяются: система лишь блокирует открытие новых сделок, пока действует новостное ограничение.
Почему в части 1 блокируется только открытие новых сделок
Блокировка открытия новых сделок — самая простая и безопасная форма защиты от новостей: она понятна начинающим, совместима с правилами проп-фирм и не вмешивается в существующие стратегии.
Ограничение части 1 только блокировкой открытия новых сделок исключает непреднамеренные побочные эффекты и некорректное изменение сделок, а также создает ясную основу для более сложной логики в будущем.
Важно – обязательные входные параметры для полноценного новостного фильтра
Чтобы сделать новостной фильтр настраиваемым и пригодным для разных стилей торговли и проп-фирм, вводится небольшой набор входных параметров.
Эти параметры определяют, включен ли новостной фильтр, какие уровни важности новостей учитываются и за сколько минут до и после новости блокируется открытие новых сделок.
//=================================================================== // INPUTS //=================================================================== input group "News Filter Configuration" input bool EnableNewsFilter = false; // Enable Economic News Filter input int NewsMinutesBefore = 5; // Minutes before news to restrict input int NewsMinutesAfter = 5; // Minutes after news to restrict input bool RestrictNewTradesDuringNews = true; // Block new trades during news window input bool CloseOpenTradesBeforeHighImpactNews = false; // Close all trades before news input string SymbolCurrencyOverride = ""; // Manual currency override e.g. "USD,JPY" enum ENUM_NEWS_IMPORTANCE_MODE { NEWS_HIGH_ONLY = 0, NEWS_MODERATE_ONLY, NEWS_HIGH_AND_MODERATE }; input ENUM_NEWS_IMPORTANCE_MODE NewsImportanceMode = NEWS_HIGH_ONLY; // Importance levels // Cache reload interval input int CacheReloadHours = 6; // Reload calendar cache (hours) // News Testing helpers (Simple simulation for Part 1 demonstration) input group "Testing Parameters" input bool EnableNewsTesting = false; // Enable news testing simulation with Current symbol input string TestNewsTime = "2025.12.15 14:30:00"; // Simulated news time (yyyy.MM.dd HH:mm:ss) input int TestNewsDuration = 10; // Simulated window length (minutes) input bool TestNewsNow = false; // Manual immediate trigger
Эти параметры позволяют советнику легко адаптироваться к различным правилам проп-фирм, консервативным или агрессивным стилям торговли, а также особенностям волатильности конкретного брокера.

| Название входного параметра | Использование / назначение |
|---|---|
| Включить фильтр экономических новостей | Полностью включает или отключает новостной фильтр советника. |
| За сколько минут до новости ограничивать торговлю | Определяет, за сколько минут до новостного события фильтр становится активным. |
| Сколько минут после новости действует ограничение | Определяет, сколько минут после новостного события фильтр остается активным. |
| Блокировать открытие новых сделок во время новостного окна | Блокировать открытие новых сделок на время действия новостного окна |
| Закрывать все сделки перед новостями | Закрывать существующие позиции при начале релевантного новостного окна |
| Ручное переопределение валюты | Позволяет вручную указать отслеживаемую валюту, если автоматического определения недостаточно. Оставьте поле пустым, если автоматическое определение работает. |
| Уровень важности | Выберите учитываемые уровни важности новостей: высокий, средний или оба. |
| Обновить кэш календаря | Определяет частоту обновления данных календаря. |
| Включить тестовую симуляцию новостей | Включает только ручной запуск новостного события. |
| Время имитируемой новости | Указывает время имитируемого новостного события в формате гггг/мм/дд чч/мм/сс в прошлом. |
| Длительность имитируемого новостного окна, в минутах | Определяет длительность активного окна для имитируемого новостного события. |
| Ручной немедленный запуск | Немедленно запускает имитируемое новостное окно для тестирования. |
Использование логики обнаружения для блокировки открытия новых сделок
Поскольку обнаружение уже реализовано на шаге 4, блокировка открытия новых сделок становится простой задачей. Вместо встраивания новостной логики в торговые функции используется единое условие допуска перед открытием любой новой позиции.
Это сохраняет торговую логику ясной и читаемой.
//=================================================================== // Check if new trades are allowed (Main Filter Gate) //=================================================================== bool CanOpenNewTrade(string symbol) { if(!EnableNewsFilter) return true; if(!RestrictNewTradesDuringNews) return true; if(IsNewsTime(symbol)) { return false; // Block trade } return true; }
Эта функция отвечает на один простой вопрос:
- безопасно ли открывать новую сделку прямо сейчас?
Применение условия допуска в торговой логике
В любом месте, где советник обычно открывает сделки, достаточно добавить в начало следующую проверку:
if(!CanOpenNewTrade(_Symbol)) { // News window active — do not open new trades return; } // Normal trade entry logic continues here
Благодаря этой проверке логика открытия сделок остается ясной и централизованной.
Опционально – закрытие всех сделок перед новостным окном
Приведенный ниже фрагмент кода позволяет советнику закрывать все сделки по символу один раз в момент начала предновостного окна ограничений.
В этом фрагменте кода используется уже реализованная логика обнаружения.
Входной параметр этой функции уже указан среди приведенных выше входных параметров.
//=================================================================== // CloseAllTradesForSymbol // Implements safe reverse iteration and CTrade closing //=================================================================== void CloseAllTradesForSymbol(string symbol) { // Iterate backward to safely close multiple positions for(int i = PositionsTotal() - 1; i >= 0; i--) { ulong ticket = PositionGetTicket(i); if(ticket == 0) continue; if(!PositionSelectByTicket(ticket)) continue; // Filter by symbol if(PositionGetString(POSITION_SYMBOL) != symbol) continue; // Close Logic bool closed = trade.PositionClose(ticket); if(closed) { PrintFormat("Closed position #%d on %s due to news.", ticket, symbol); } else { PrintFormat("Failed to close #%d. Error: %d", ticket, GetLastError()); } } }
Логика срабатывания в функции OnTick()
//=================================================================== // OnTick //=================================================================== void OnTick() { // Static latch to ensure we don't try to close trades multiple times per window static bool tradesClosedForThisNewsWindow = false; // 2. Main News Logic if(EnableNewsFilter) { bool isNews = IsNewsTime(_Symbol); // Feature: Close open trades before news if enabled if(CloseOpenTradesBeforeHighImpactNews && isNews) { if(!tradesClosedForThisNewsWindow) { Print("News window started -> Closing open trades."); CloseAllTradesForSymbol(_Symbol); tradesClosedForThisNewsWindow = true; // Latch } } else if(!isNews) { // Reset latch when we are out of the news window tradesClosedForThisNewsWindow = false; } } }
Что это дает
- Закрывает сделки до начала всплеска волатильности.
- Использует уже реализованную логику обнаружения.
- Срабатывает один раз для каждого новостного окна.
- Полностью опционально (присвойте входному параметру значение true либо false).
- Совместимость с требованиями проп-фирм.
- Во второй части будет реализован механизм временного снятия и повторной установки стоп-лосса и тейк-профита на период новостных ограничений, чтобы сохранить преимущество стратегии и избежать преждевременного закрытия позиций.
Заключение части 1
На этом этапе создан рабочий новостной фильтр: эффективный, учитывающий символ, соответствующий требованиям проп-фирм, удобный для начинающих и готовый к блокировке открытия новых сделок и закрытию позиций.
Часть 1 полностью самодостаточна.
Заключение
В этой статье создана полноценная работоспособная система новостного фильтра на MQL5: от базовых принципов до практического решения.
Вместо жестко заданного времени или блокировки торговли на основе веб-запросов система построена вокруг Экономического календаря MQL5 с учетом производительности, релевантности и ясности логики. События календаря эффективно загружаются, кэшируются, фильтруются по уровню важности и сопоставляются только с валютами, действительно влияющими на торгуемый символ.
Благодаря отделению обнаружения новостей от применения торговых ограничений логика остается понятной, легко тестируется и расширяется. В результате получается аккуратный механизм блокировки новых входов в настраиваемых окнах перед новостью и после нее, а также опциональное правило закрытия открытых позиций до начала новостной волатильности.
Этот подход особенно подходит для условий проп-фирм, где чаще всего требуется не открывать сделки в периоды новостных ограничений. В части 1 открытые позиции не изменяются и управление сделками не затрагивается. Поэтому во второй части будет рассмотрено временное снятие стоп-лоссов только на период новостных ограничений, чтобы они не срабатывали и не изменялись во время новостей, нарушая правила. Кроме того, досрочное закрытие сделок может нарушить логику стратегии. В целом система обеспечивает соблюдение требований и защиту, оставаясь непривязанной к конкретной стратегии.
Что еще важнее, все реализованное в этой статье можно полноценно использовать самостоятельно. Часть 1 предоставляет полноценный новостной фильтр, который можно встроить в любой советник и сразу использовать для применения новостных торговых ограничений.
В следующей части серии эта основа будет расширена более сложной логикой работы во время новостных событий, включая управление сделками и дополнительные механизмы защиты.
Представленная здесь система уже решает основную задачу ясным и аккуратным способом.
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/21235
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
Нейросети в трейдинге: Управление риском через распределение результатов (AC-SRM)
Мастер-класс по созданию пользовательских индикаторов (Часть 2): Разработка практического советника Supertrend на MQL5
Свинговые экстремумы и откаты в MQL5 (Часть 1): Разработка мультитаймфреймового индикатора
Интеграция внешних приложений с использованием OAuth MQL5 Community
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Пожалуйста, отвечайте на вопросы по этой статье здесь, а не в личных сообщениях. Именно для этого и предназначена эта тема.
Конечно, он сначала спросил в личных сообщениях, и я думал ответить там же.
Джамшид спросил, почему предстоящие новостные события, напечатанные и показанные на этом изображении, не соответствуют текущим новостным событиям Forex Factory
Мой ответ:
Этот вывод представлял собой актуальный календарь экономических новостей на момент написания мной этого сообщения, Я вывел несколько новостей из кэшированного календаря в целях отладки, просто чтобы проверить, правильно ли работает мой кэшированный календарьЕсли вы скомпилируете код со своей стороны и разместите советник на графике, вы также увидите около 5 актуальных предстоящих новостных событий на вкладке советника, что подтвердит работоспособность кэшированных событий.
Конечно, данные будут отличаться, так как время написания этой статьи и любое другое последующее время будут разными!
Еще одна причина, по которой данные могут отличаться, заключается в том, что Forex Factory и MQL5 не совсем одинаковы: между ними есть некоторые различия в уровне важности новостей, и иногда на MQL5 немного больше новостей с низким или средним уровнем влияния.
Отличная работа.
Потрясающая серия статей.
Буквально то, что нужно всем алгоритмическим трейдерам, торгующим в проп-фирмах Eval, для своих советников.
Надеюсь, что каждый, кто этим пользуется, хотя бы оставит комментарий.
Еще одна причина, по которой ситуация может отличаться, заключается в том, что Forex Factory и MQL5 не совсем одинаковы: между ними есть некоторые различия в уровне важности новостей, и иногда на MQL5 публикуется чуть больше новостей с низким или средним уровнем влияния
Форум, посвящённый торговле, автоматизированным торговым системам и тестированию торговых стратегий
Библиотеки: Календарь
fxsaber, 21.03.2024, 09:49
К сожалению, нынешнему календарю нельзя доверять.
Вот пример: в списке событий отсутствует важная новость по CHF, а рынок на неё отреагировал соответствующим образом.
А вот ещё один календарь, в котором эта новость присутствует.
Надеюсь, что каждый, кто ими пользуется, хотя бы оставит комментарий.