Возможности Мастера MQL5, которые вам нужно знать (Часть 97): Использование выпуклой оболочки и миниатюрной GRU-сети в пользовательском классе трейлинг-стопа
Введение
В этой серии о Мастере MQL5 поочередно рассматриваются сигналы входа, управление капиталом и трейлинг-стопы. Эти три области являются основными направлениями настройки советников, собранных с помощью Мастера MQL5, помимо встроенных классов. В предыдущих опубликованных статьях рассматривались сигналы входа и управление капиталом, поэтому эта статья посвящена трейлинг-стопам. В предыдущей статье о трейлинг-стопах алгоритм выборки из резервуара был объединен с сетью линейной регрессии для построения модели, ориентированной на справедливую медиану цены. Этот подход предназначался для защиты открытых позиций от бокового рыночного шума.
Этот подход может хорошо работать на рынках с пилообразными колебаниями, но на трендовых рынках его эффективность может снижаться. В этой статье переходим от торговли по медиане к торговле по внешнему контуру. Представляется класс трейлинг-стопа, использующий алгоритм выпуклой оболочки для определения внешней оболочки ценового движения. Как и ранее, он сочетается с нейронной сетью, в данном случае с упрощенным управляемым рекуррентным блоком (GRU). Сеть служит фильтром моментума.
Это дополнение к библиотеке MQL5 не является универсальным решением, а представляет альтернативный подход для трейдеров, работающих с моментумом и стремящихся извлечь выгоду из взрывных пробоев. В узких диапазонах ценового движения этот подход неизбежно работает хуже, поэтому он подходит трейдеру, у которого есть дисциплина и специализация в торговле пробойным моментумом.
Предполагаемые рыночные условия
Чтобы понять значимость нового сетапа трейлинг-стопа, рассмотрим определяющие его рыночные условия. В предыдущей статье о пользовательских трейлинг-стопах выборка из резервуара и линейная регрессия применялись прежде всего к рынкам с возвратом к среднему. В таких ситуациях бокового рынка цена постоянно возвращается к центру тяжести. Цель состояла в фильтрации шума ложных пробоев путем ориентации на справедливую медиану.
Однако при работе с активами, для которых характерны "толстые хвосты", то есть внезапные направленные всплески волатильности, может потребоваться альтернативный подход. Примерами служат реакция технологического сектора на отчетность, волатильные криптовалютные тренды или форекс, реагирующий на ключевую макростатистику США, например NFP. В таких условиях формирование новых ценовых уровней является нормой, а возврат к устойчивой медиане происходит редко.
Поэтому подход к торговле в таких условиях основан на следовании за трендом с учетом моментума. В этом случае трейдер не стремится получить 10 пипсов в узком канале, а работает на движении в 200 пипсов. Главная проблема состоит не в ошибке как таковой, а в преждевременном закрытии позиции из-за пилообразных колебаний или резких волатильных откатов до возобновления основного тренда.
Если трейдер, работающий с моментумом, попытается адаптировать модель линейной регрессии из предыдущей статьи о трейлинг-стопах, он, вероятно, будет запаздывать за движением рынка. Почему так? Потому что линейная регрессия по сути является механизмом сглаживания. Кроме того, выборка из резервуара намеренно сохраняла более старые ценовые данные для формирования сбалансированной исторической выборки. При взрывном пробое старые данные становятся токсичными! Это привязывает линию регрессии к прошлым данным, из-за чего трейлинг-стоп существенно запаздывает, а рассчитанные медианы цен не отражают новую рыночную ситуацию.
При торговле с высоким моментумом цель состоит не в сглаживании ценовых экстремумов, а в работе с ними. В этом случае алгоритм выпуклой оболочки особенно полезен. Вместо вычисления медианы этот алгоритм соединяет абсолютные структурные экстремумы, формируя внешнюю границу. В сочетании с GRU-сетью, оценивающей последовательную память моментума вместо простых средних значений, модель позволяет отличать временную структурную коррекцию от реального разворота тренда.
Дилемма пилообразных колебаний
Прежде чем продолжить, еще раз рассмотрим проблему, которую может помочь решить модель. Рассмотрим следующий сценарий. Был точно определен крупный ценовой пробой. Рынок резко растет, и принимается решение использовать трейлинг этой позиции для фиксации прибыли. Вы выставляете стандартный трейлинг-стоп на основе фиксированного расстояния в пипсах или ценового отступа от индикатора, например скользящей средней. В результате позиция уже в плюсе, и вы продолжаете удерживать позицию по тренду.
Если неожиданно формируется одиночная медвежья свеча, которую многие считают признаком институционального снятия ликвидности либо новостной аномалии, трейлинг-стоп может сработать. Сделка закрывается не с убытком, а с небольшой прибылью. Уже на следующем баре рынок преодолевает эту аномалию и затем резко возобновляет восходящий тренд еще на 150 пипсов. При этом трейдер остается вне рынка, наблюдая, как верно определенное движение продолжается без него. Это и есть дилемма пилообразных колебаний.
Для трейдера, работающего с моментумом, обычный трейлинг-стоп имеет фундаментальный недостаток. Если установить его слишком близко, его может задеть рыночным шумом. Если же расстояние слишком велико, при настоящем развороте будет потеряна значительная часть плавающей прибыли позиции.
В таких условиях трейдеры могут применять двухкомпонентные решения. Во-первых, можно использовать систему, динамически ориентированную на абсолютную внешнюю ценовую границу структуры тренда, а не на среднее значение. Иными словами, требуется пространственная карта крайних ценовых границ. Во-вторых, можно использовать механизм, выполняющий роль интеллектуального фильтра. Он должен уметь фиксировать трейлинг-стоп, когда волатильное ценовое движение направлено против более широкого сложившегося моментума. Теоретически это позволило бы позиции переживать волатильные колебания, не закрываясь из-за снятия ликвидности.
Описание модели
При решении дилеммы пилообразных колебаний трейлинг-стоп не должен зависеть только от одного показателя. Согласно определению проблемы выше, необходимо различать пространственное размещение стоп-лоссов и временной контекст рыночного моментума. Это реализуется разделением механизма модели на два отдельных взаимодействующих компонента, как и в предыдущих статьях с двумя механизмами.
Механизм 1 – алгоритм выпуклой оболочки
Задача первого механизма в основном геометрическая. Вместо вычисления скользящих средних определяются абсолютные границы недавнего ценового движения. Благодаря этому формируется динамическая оболочка вокруг торгуемого актива. По мере развития тренда эта оболочка соответствующим образом адаптируется. Теоретически это позволяет определить размещение стоп-лосса, защищенное от обычного рыночного шума.
Механизм 2 – GRU-сеть
Второй механизм обеспечивает временной контекст. На основе управляемого рекуррентного блока (GRU) он служит прогнозирующим фильтром моментума. GRU часто хорошо обрабатывают последовательные данные, поэтому эффективно анализируют недавнюю историю изменений цены и выявляют сдвиги моментума.
Синергия
Сила модели может заключаться во взаимодействии двух механизмов. Механизм 1 определяет размещение стоп-лосса на основе динамически обновляемой оболочки, а механизм 2 отслеживает аномалии, например всплески волатильности, не соответствующие преобладающим рыночным условиям. Сеть может временно переопределить алгоритм, приостановив корректировку текущих уровней стоп-лосса и позволив позиции выдержать ценовые всплески. Это должно обеспечить корректировку стоп-лосса, только когда геометрия цены и базовый моментум рынка подтверждают друг друга
Математика модели
Теперь можно перейти к части статьи, в которой мы заменяем метафоры математическим описанием. Напомним, что здесь наше внимание уже не сосредоточено на возврате к среднему, как в алгоритме выборки из резервуара, поэтому средние значения не вычисляются.
Пространственная математика – экстремумы выпуклой оболочки
Обычное скользящее среднее суммирует цены закрытия и делит эту сумму на период усреднения, смещая итоговое значение к центру всех усредняемых точек данных. Алгоритм выпуклой оболочки игнорирует центральную область данных. Вместо этого он выделяет абсолютные структурные экстремумы в скользящем окне из n периодов. Например, для трейлинг-стопа длинной позиции внешняя оболочка S_long – это наименьшее значение, зафиксированное в историческом окне буфера:
![]()
Привязка только к минимумам (либо, для короткой позиции, к максимумам) формирует устойчивую границу. Основная идея состоит в том, что ценовое движение, следующее за трендом, не может пересечь эту геометрическую линию без нарушения своей рыночной структуры.
Временная математика – механика вентилей GRU
Экспоненциальная скользящая средняя (EMA) может забывать старые данные с фиксированной линейной скоростью затухания, тогда как GRU забывает их с учетом контекста. Эта сеть не только обрабатывает текущие изменения цены x_t – она также обрабатывает их совместно со своим внутренним состоянием памяти h_t-1. Для этого GRU использует отдельные вентили, работа которых определяется сигмоидной функцией sigma и функцией гиперболического тангенса tanh. При этом используются обученные веса W и U, а также смещения b:
- 1. Вентиль обновления z_t. Он определяет, какая часть памяти о предыдущем тренде сохраняется. Если происходит внезапный ценовой всплеск, этот вентиль определяет, является ли этот всплеск временным шумом или системным сдвигом. Его формула имеет следующий вид:
![]()
- 2. Вентиль сброса r_t. Этот вентиль определяет, какая часть прошлой памяти уже несущественна и поэтому должна быть отброшена. Его формула имеет следующий вид:
![]()
- 3. Вычисление состояния-кандидата tilde_h_t и скрытого состояния h_t. На последнем шаге сеть вычисляет новое потенциальное представление о тренде tilde_h_t и объединяет его с предыдущей памятью с помощью вентиля обновления. В результате получается итоговое выходное значение направленного моментума h_t:
![]()
![]()
Таким образом, вместо использования запаздывающего среднего значения цены эти уравнения позволяют нейронной сети динамически отделять локальный структурный шум от действительной потери трендового моментума.
Реализация на MQL5
Теперь пространственная геометрия выпуклой оболочки и временная память GRU реализуются в пользовательском классе, совместимом с Мастером MQL5 и предназначенном для трейлинга открытых позиций на волатильных трендовых рынках. Как и обычно, для беспрепятственной интеграции с экосистемой MetaTrader 5 пользовательский класс наследуется от встроенного базового класса CExpertTrailing.
Архитектура модели разделена на две части в соответствии с двумя используемыми механизмами. Далее рассматриваются настройка и работа пространственного механизма – алгоритма выпуклой оболочки, – а затем временной механизм GRU-сети. В завершение рассматривается объединение этих двух механизмов для совместной работы.
1. Настройка класса и выбор индикаторов
В предыдущей статье с пользовательским классом трейлинг-стопа для определения центра ценового движения в основном использовались скользящие средние, служившие основой для корректировки стоп-лоссов. Однако здесь скользящие средние противоречат принципу работы алгоритма, поэтому их использовать нельзя. Поэтому необходимы необработанные, неотфильтрованные ценовые экстремумы. Поэтому в качестве первого "индикатора" для алгоритма выпуклой оболочки используются не встроенные индикаторы, а алгоритмические массивы необработанных данных m_high_history[] и m_low_history[]. Второй индикатор – средний истинный диапазон (ATR). Почему используется ATR? Потому что одной геометрии может быть недостаточно для учета меняющихся рыночных условий. Внешняя оболочка шириной 20 пипсов может быть вполне безопасной во время азиатской сессии, но оказаться слишком уязвимой при открытии Нью-Йоркской сессии. ATR преобразует необработанную структурную геометрию цены в формат с поправкой на волатильность.
class CTrailingConvexHullGRU : public CExpertTrailing { protected: //--- Indicators CiATR m_atr; // Indicator 1: ATR (Volatility) // Indicator 2: Price Action Local Extrema (Computed algorithmically) //--- Convex Hull Parameters int m_hull_period; int m_hull_mode; int m_atr_period; //--- Price History Buffers for Hull double m_high_history[]; double m_low_history[]; int m_history_count;
В виртуальной функции InitIndicators унаследованного класса инициализируются следующие "индикаторные" компоненты:
//+------------------------------------------------------------------+ //| Initialize Indicators and Arrays | //+------------------------------------------------------------------+ bool CTrailingConvexHullGRU::InitIndicators(CIndicators *indicators) { if(!CExpertTrailing::InitIndicators(indicators)) return false; //--- Parameter bounds check if(m_hull_period <= 0) m_hull_period = 20; if(m_atr_period <= 0) m_atr_period = 14; //--- Initialize ATR Indicator if(!indicators.Add(GetPointer(m_atr))) { printf(__FUNCTION__ + ": error adding ATR object"); return false; } if(!m_atr.Create(m_symbol.Name(), m_period, m_atr_period)) { printf(__FUNCTION__ + ": error initializing ATR"); return false; } //--- Resize rolling window buffers for Convex Hull ArrayResize(m_high_history, m_hull_period); ArrayResize(m_low_history, m_hull_period); ArrayInitialize(m_high_history, 0.0); ArrayInitialize(m_low_history, 0.0); return true; }
Ниже приведены ключевые элементы этой реализации:
- Первое условие if(!CExpertTrailing::InitIndicators(indicators)) проверяет успешность инициализации родительского класса перед дальнейшим выполнением.
- Второе условие if(m_hull_period <= 0) выполняет стандартную проверку допустимости параметра, предотвращая деление на ноль и выход за границы массива.
- Индикатор ATR инициализируется с помощью m_atr.Create(...) и привязывается к текущему символу и таймфрейму.
- Размеры массивов необработанных цен динамически задаются в соответствии с периодом n внешнего контура выпуклой оболочки.
2. Пространственный механизм – управление алгоритмической оболочкой
Перед расчетом оболочки необходимо непрерывно передавать алгоритму данные в реальном времени. В отличие от обычных индикаторов MQL5, считывающих значения закрытых ценовых баров, например через iClose, трейлинг-стопы в отдельных ситуациях должны быстро реагировать на изменения. Поэтому им необходим доступ к текущим максимумам и минимумам еще не закрытого бара, особенно на крупных таймфреймах, таких как H4 или D1.
//+------------------------------------------------------------------+ //| Hull Buffer Manager (Rolling Window) | //+------------------------------------------------------------------+ void CTrailingConvexHullGRU::UpdateHullState(double high, double low) { if(m_history_count < m_hull_period) { m_high_history[m_history_count] = high; m_low_history[m_history_count] = low; m_history_count++; } else { for(int i = 0; i < m_hull_period - 1; i++) { m_high_history[i] = m_high_history[i + 1]; m_low_history[i] = m_low_history[i + 1]; } m_high_history[m_hull_period - 1] = high; m_low_history[m_hull_period - 1] = low; } }
В приведенном выше коде сначала проверяется, есть ли еще место в массиве для добавления нового элемента. Если проверка пройдена, увеличивается счетчик значений экстремумов. Когда массив заполнен, запускается цикл for, в котором реализуется скользящее окно по принципу FIFO: каждый элемент массива сдвигается на один индекс влево. При таком сдвиге самая старая ценовая точка перезаписывается следующей по времени, в результате чего старые данные удаляются. После завершения цикла в конец массива добавляется самое последнее значение цены. После определения массива пространственной памяти необходимо рассмотреть четыре возможных режима работы. Это четыре режима выпуклой оболочки, каждый из которых представляет отдельный вариант торговли с использованием моментума.
Режим 1 – стандартные чистые экстремумы
Первый режим использует необработанную геометрическую модель для определения абсолютных границ поддержки и сопротивления в пределах скользящего окна:
//+------------------------------------------------------------------+ //| Mode 1: Standard Pure Extrema (Price Action Support/Resistance) | //+------------------------------------------------------------------+ double CTrailingConvexHullGRU::HullModeStandard(bool is_long) { int count = MathMin(m_history_count, m_hull_period); if(count == 0) return is_long ? m_symbol.Bid() : m_symbol.Ask(); double extreme_val = is_long ? m_low_history[0] : m_high_history[0]; for(int i = 1; i < count; i++) { if(is_long && m_low_history[i] < extreme_val) extreme_val = m_low_history[i]; if(!is_long && m_high_history[i] > extreme_val) extreme_val = m_high_history[i]; } return extreme_val; }
В приведенном выше коде базовый экстремум инициализируется самым старым значением в текущем окне. Затем в следующем цикле for перебираются остальные значения окна. Для короткой позиции определяется наивысшая точка, над которой размещается стоп-лосс. Если текущее значение в цикле выше базового, базовое значение перезаписывается.
Режим 2 – расширенная оболочка ATR
Иногда на рынке происходят неожиданные снятия ликвидности, усугубляющие описанную выше дилемму пилообразных колебаний. В таких ситуациях режим 1 будет недостаточно устойчивым и с большей вероятностью приведет к срабатыванию стоп-лосса. Поэтому в режиме 2 геометрическая граница цены смещается наружу.
//+------------------------------------------------------------------+ //| Mode 2: ATR Expanded Shell (Hull shifted by Volatility) | //+------------------------------------------------------------------+ double CTrailingConvexHullGRU::HullModeATRExpanded(bool is_long) { double base_shell = HullModeStandard(is_long); m_atr.Refresh(); double current_atr = m_atr.Main(1); // Get previous bar's ATR //--- Expand the shell outward based on current market volatility return is_long ? (base_shell - current_atr) : (base_shell + current_atr); }
В приведенном выше коде режима 2 сначала определяется абсолютный геометрический экстремум. Затем обновляется буфер ATR, после чего запрашивается значение последнего полностью сформированного ценового бара с определенными значениями OHLC. Для короткой позиции значение ATR прибавляется к наибольшему максимуму. Это расширяет оболочку вверх и создает больший запас против возможных всплесков волатильности.
Режим 3 – сглаженная усредненная оболочка
Хотя скользящие средние запаздывают относительно цены, расчет среднего значения границ иногда может быть полезен при слишком хаотичных волатильных движениях цены актива.
//+------------------------------------------------------------------+ //| Mode 3: Smoothed Average Shell (Median of boundaries) | //+------------------------------------------------------------------+ double CTrailingConvexHullGRU::HullModeSmoothed(bool is_long) { int count = MathMin(m_history_count, m_hull_period); if(count == 0) return is_long ? m_symbol.Bid() : m_symbol.Ask(); double sum = 0.0; for(int i = 0; i < count; i++) { sum += is_long ? m_low_history[i] : m_high_history[i]; } return sum / count; }
В приведенном выше коде вместо определения абсолютного минимума суммируются все минимумы в окне, после чего сумма делится на их количество. В результате получается усредненный уровень экстремумов, служащее ориентиром для размещения стоп-лосса.
Режим 4 – оболочка со смещением в сторону моментума
В последнем режиме больший вес придается геометрии недавнего ценового движения по сравнению с более ранними данными. Преимущество этого подхода состоит в том, что стоп-лосс может более агрессивно следовать за ускорением цены. Такой подход может быть оправдан при определенных рыночных условиях, для отдельных типов активов или во время новостных событий.
//+------------------------------------------------------------------+ //| Mode 4: Momentum-Biased Shell (Recent Extremes Weighted Higher) | //+------------------------------------------------------------------+ double CTrailingConvexHullGRU::HullModeRecentBiased(bool is_long) { int count = MathMin(m_history_count, m_hull_period); if(count == 0) return is_long ? m_symbol.Bid() : m_symbol.Ask(); double global_extreme = HullModeStandard(is_long); double recent_extreme = is_long ? m_low_history[count - 1] : m_high_history[count - 1]; //--- Bias: 60% standard absolute shell, 40% most recent price shell return (global_extreme * 0.6) + (recent_extreme * 0.4); }
Сначала в приведенном выше коде определяется фактический экстремум всего окна данных. Затем объявляется другой экстремум, recent_extreme, отражающий самый недавний экстремум в текущем окне данных. Наконец, эти два экстремальных значения объединяются в асимметричную оболочку. По умолчанию 60% веса отводится глобальной ценовой структуре, а оставшиеся 40% – недавнему ценовому движению. Хотя недавним данным отводится меньшая доля, чем всему набору данных, их итоговый вес все равно выше, чем при обычном усреднении по всему набору.
3. Временной механизм – реализация GRU-сети
Язык MQL5 создан на основе C++. Это позволяет очень быстро обрабатывать последовательную логику. Однако для использования моделей глубокого обучения часто требуется внешняя интеграция с ONNX. При разработке пользовательского класса трейлинга для советников, собранных Мастером MQL5, ONNX может оказаться избыточным, особенно из-за вносимых им задержек выполнения программы. Вместо этого математическая модель GRU реализуется непосредственно на MQL5 с использованием детерминированных псевдовесов, настроенных на обнаружение моментума.
//+------------------------------------------------------------------+ //| Initialize Deterministic Weights for GRU Filter | //+------------------------------------------------------------------+ void CTrailingConvexHullGRU::InitGRUWeights() { //--- Emulating a trained trend-following/momentum configuration Wz = 0.5; Uz = 0.5; bz = 0.0; Wr = 0.5; Ur = 0.5; br = 0.0; Wh = 0.8; Uh = 0.2; bh = 0.0; }
Эти инициализированные параметры определяют, насколько активно сеть "запоминает" или "забывает" моментум. Высокое значение Wh (0,8) придает текущему ценовому движению большой вес при расчете состояния-кандидата, тогда как Uh (0,2) ограничивает влияние прошлого контекста на текущую оценку. Такой подход может хорошо подходить для следования за трендом. Функции активации важны для работы GRU.
//+------------------------------------------------------------------+ //| Sigmoid Activation Function | //+------------------------------------------------------------------+ double CTrailingConvexHullGRU::Sigmoid(double x) { return 1.0 / (1.0 + MathExp(-x)); }
Используется встроенная экспоненциальная функция MQL5. Сигмоидная функция отображает неограниченные изменения цены в узкий диапазон от 0,0 до 1,0. Это диапазон вероятностей, поэтому он может использоваться как полноценный вентиль. После этого необходимо выполнять прямой проход GRU на каждом поступающем ценовом баре.
//+------------------------------------------------------------------+ //| Update GRU Network States (Forward Pass) | //+------------------------------------------------------------------+ void CTrailingConvexHullGRU::UpdateGRU(double price) { if(m_gru_prev_price == 0.0) { m_gru_prev_price = price; return; } //--- Input x is the normalized price delta double x = (price - m_gru_prev_price) / m_symbol.Point(); m_gru_prev_price = price; //--- GRU Equations double z_gate = Sigmoid((Wz * x) + (Uz * m_gru_h) + bz); double r_gate = Sigmoid((Wr * x) + (Ur * m_gru_h) + br); double h_candidate = MathTanh((Wh * x) + (Uh * (r_gate * m_gru_h)) + bh); //--- Update hidden state (memory) m_gru_h = (1.0 - z_gate) * m_gru_h + (z_gate * h_candidate); }
В приведенном выше коде вычисляется нормализованный входной вектор x. GRU получает не необработанные ценовые данные, а дельты, то есть изменения цены, преобразованные в пункты. Параметр вентиля обновления z_gate рассчитывается умножением текущей дельты x на вес Wz с добавлением предыдущего скрытого состояния m_gru_h, умноженного на вес Uz. Эта сумма передается в сигмоидную функцию, формируя значение, определяющее, насколько можно опереться на текущий тренд. Переменная вентиля сброса r_gate рассчитывается аналогично. Он определяет, какую часть m_gru_h следует полностью отбросить.
Затем определяется состояние-кандидат h_candidate. При расчете этого параметра r_gate умножается на m_gru_h. Когда значение m_gru_h близко к нулю, GRU игнорирует прошлое и реагирует только на x. Функция MathTanh ограничивает выходное значение диапазоном от -1 до +1. Последнее ключевое действие в приведенном выше коде – обновление скрытого состояния. Это итоговое состояние памяти моментума. При высоком значении z_gate система заменяет старую память m_gru_h новым состоянием-кандидатом h_candidate.
4. Логика исполнения – объединение пространственного и временного механизмов
После описания основ алгоритма и сети рассмотрим, как эти компоненты объединяются. На этом этапе геометрическая оболочка объединяется с нейронным фильтром.
bool CTrailingConvexHullGRU::CheckTrailingStopLong(CPositionInfo *position, double &sl, double &tp) { if(position == NULL) return false; double current_bid = m_symbol.Bid(); //--- 1. Update State UpdateHullState(m_symbol.Ask(), m_symbol.Bid()); // Simplified H/L emulation using Ask/Bid //--- 2. Network: GRU Filter if(m_use_gru) { UpdateGRU(current_bid); // If GRU trend implies heavy downward momentum, hold the stop where it is if(m_history_count >= m_hull_period && GetGRUTrend() < -0.5) return false; }
В основной функции корректировки стоп-лосса для длинных позиций сначала в массив передаются текущие ценовые данные для обновления геометрии выпуклой оболочки. Затем ценовые данные передаются в прямой проход GRU для обновления памяти моментума. При этом перед использованием необходимо убедиться, что массивы и память GRU полностью заполнены данными. Строчка кода if(m_history_count >= m_hull_period && GetGRUTrend() < -0.5) является ключевым элементом взаимодействия двух механизмов.
Функция GetGRUTrend() возвращает ограниченное значение в диапазоне от -1 до 1; значение ниже -0,5 практически наверняка указывает на сильный нисходящий моментум. В этой ситуации, даже если алгоритм выпуклой оболочки дает зеленый свет на перенос стоп-лосса вверх, GRU как вторичный фильтр не соглашается с этим и фактически переопределяет решение алгоритма. В этом случае функция возвращает false и немедленно прекращает свое выполнение. Цена трейлинг-стопа при этом фиксируется, что теоретически защищает позицию от возможного снятия ликвидности на фоне пилообразных колебаний.
//--- 3. Algorithm: Select Convex Hull Mode double shell_price = current_bid; switch(m_hull_mode) { case 1: shell_price = HullModeStandard(true); break; case 2: shell_price = HullModeATRExpanded(true); break; case 3: shell_price = HullModeSmoothed(true); break; case 4: shell_price = HullModeRecentBiased(true); break; default: shell_price = HullModeStandard(true); break; } //--- 4. Execution Logic double new_sl = NormalizeDouble(shell_price - (((2 * m_symbol.Spread()) + m_symbol.FreezeLevel() + m_symbol.StopsLevel()) * m_symbol.Point()), m_symbol.Digits()); double current_sl = position.StopLoss(); sl = EMPTY_VALUE; tp = EMPTY_VALUE; //--- Only move stop up if(new_sl > current_sl || current_sl == 0.0) { sl = new_sl; return true; } return false; }
В заключительной части выполняется оператор switch по входному параметру советника m_hull_mode. Это задает функцию пространственного расчета алгоритма. После этого на основе внешней границы shell_price вычисляется new_sl с учетом минимального уровня стопов и уровня заморозки, установленных брокером. Также проверяется, что новая цена стоп-лосса находится от текущего уровня стоп-лосса на расстоянии не меньше текущего спреда. Наконец, новая целевая цена стоп-лосса нормализуется с учетом количества знаков, допустимого для торгуемого символа. Перед возвратом true, то есть разрешением корректировки стоп-лосса, следующее условие if проверяет соблюдение основного правила трейлинг-стопов. Стоп-лосс перемещается только в направлении прибыли. Таким образом, реализация на MQL5 увязывает текущее ценовое движение с прогнозом по моментуму.
Анализ результатов оптимизации
Для перехода от теории к практической реализации в Мастере MQL5 собирается советник с пользовательским классом трейлинг-стопа CTrailingConvexHullGRU и встроенными классами сигналов Envelopes и RSI. Тестирование проводится на символе USDJPY на таймфрейме H2. Как обычно, для каждого теста сначала проводится оптимизация, а затем форвард-тестирование. Период оптимизации охватывает весь 2025 год, а форвард-период длится с 1.01.2026 по 1.05.2026. Поскольку используются два механизма, первый тест проводится только с алгоритмом, а второй объединяет алгоритм и нейронную сеть.
Базовый тест – только алгоритм
Для оптимизации советника только с алгоритмом выпуклой оболочки GRU отключается. В этом тесте выбранные входные параметры были ориентированы на высокореактивные сетапы краткосрочной памяти: период усреднения Envelopes – всего 3, отклонение – 0,425, а порог открытия позиции – 96. Запуск только с алгоритмом, по-видимому, дал ожидаемый результат: алгоритм использовал ценовые экстремумы, чтобы защищать уже заработанную прибыль.

Тем не менее этот отчет, по-видимому, демонстрирует описанную во введении дилемму пилообразных колебаний, поскольку несколько позиций были закрыты слишком рано. В итоге значительный убыток составил лишь половину максимальной зафиксированной просадки средств счета. Обычно это указывает на отрицательную корреляцию между прибылью и MAE, что особенно нежелательно при разработке пользовательского класса трейлинг-стопа.
Добавление сети
Подключение GRU-сети заметно меняет картину. Следует учитывать, что тестирование проводится на ограниченном временном интервале и только на одной валютной паре рынка Forex. Эти результаты не гарантируют их повторяемости в будущем ни для этого символа, ни для других активов на том же временном интервале. Если начать с оптимизированных входных параметров, видно, что период усреднения Envelopes был увеличен до 21, а отклонение уменьшено до 0,03. Кроме того, порог открытия позиции был снижен до 50.

С добавлением миниатюрного GRU совершается больше сделок, а итоговый результат выходит в плюс. Однако просадка средств счета почти в три раза больше чистой прибыли. Отсрочка корректировки стоп-лосса могла дать некоторые преимущества, но результаты не позволяют сделать однозначный вывод. Очевидно, требуются дополнительные тесты за пределами этого временного интервала и на других символах. Кроме того, поскольку рассматривается только трейлинг-стоп, сигналы входа на основе Envelopes и RSI играют здесь второстепенную роль. Почти полная перенастройка входных параметров для каждого тестового прогона также не позволяет четко оценить сравнительные преимущества алгоритма и нейронной сети. Эти аспекты читатель может исследовать самостоятельно, чтобы лучше понять, что подходит для его торговой системы, а без чего можно обойтись.
Заключение
Сначала была рассмотрена дилемма пилообразных колебаний: позиции преждевременно закрываются из-за локальных аномалий волатильности. Затем было показано, как эту проблему можно решать с помощью двух механизмов – выпуклой оболочки и GRU-сети. Для определения внешних границ ценового движения использовался пространственный механизм на основе алгоритма выпуклой оболочки. Временной механизм – GRU-сеть – служил фильтром последовательного моментума и позволял приостанавливать корректировку стоп-лосса в сценариях или рыночных сетапах, напоминающих снятие ликвидности либо краткосрочные ценовые рывки.
Рынки в конечном счете проходят через разные фазы, и некоторые трейдеры специализируются на определенной фазе либо извлекают выгоду из активов с характерным типом ценового движения. Представлен инструмент, который может помочь трейдерам эффективнее работать в трендовых режимах, избегая последствий взрывных движений, характерных для распределений с толстыми хвостами.
| имя | описание |
|---|---|
| wz_97.mq5 | Советник, собранный Мастером MQL5 |
| TrailingConvexHullGRU.mqh | Пользовательский класс трейлинга, необходимый для сборки в Мастере MQL5 |
| r1.set | Входные параметры для первого прогона |
| r2.set | Входные параметры для второго прогона |
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/23055
Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.
Разработка инструментария для анализа Price Action (Часть 74): Создание советника MQL5 на основе буферов индикатора
Разработка инструментария для анализа Price Action (Часть 73): Построение системы торговых сигналов для гэпов выходного дня в MQL5
Пайплайны Codex: от Python до MQL5 для выбора индикаторов — анализ ETF XLF по нескольким кварталам с применением машинного обучения
Моделирование рынка: В единстве — сила (II)
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования