preview
От "лучшего прохода" к устойчивым решениям: исследование поверхности оптимизации в MetaTrader 5

От "лучшего прохода" к устойчивым решениям: исследование поверхности оптимизации в MetaTrader 5

MetaTrader 5Тестер |
45 0
MetaQuotes
MetaQuotes

Введение

Оптимизация торговых стратегий давно стала обязательной частью разработки алгоритмических систем. MetaTrader 5 предоставляет для этого мощный инструментарий: многопоточный тестер, распределённые вычисления и пользовательские критерии. Результаты оптимизации можно визуализировать в виде одно-, двух- и трёхмерных зависимостей показателей от параметров советника. На первый взгляд этого более чем достаточно: запускается оптимизация, результаты сортируются по Profit Factor или иному сводному критерию, после чего выбирается лучший проход. Однако именно здесь и начинается одна из самых распространённых иллюзий алгоритмического трейдинга.

Проблема заключается в том, что оптимизация почти всегда концентрируется на поиске максимального результата отдельного прохода. Тестер показывает вершину поверхности параметров — самый высокий Profit Factor, лучший Sharpe Ratio или максимальную прибыль. Но рынок редко вознаграждает системы, построенные на одиночных экстремумах. Напротив, подобные пики часто оказываются следствием случайного совпадения параметров с локальной структурой исторических данных. Достаточно незначительно изменить период индикатора, величину стоп-лосса или рыночный режим — и впечатляющий результат начинает стремительно разрушаться.

Именно поэтому высокий Profit Factor сам по себе ещё ничего не гарантирует. Две стратегии могут демонстрировать одинаковую доходность, но принципиально различаться по устойчивости. Первая сохраняет приемлемые результаты во всём диапазоне соседних параметров. Вторая существует лишь в виде узкой иглы на поверхности оптимизации, окружённой хаотичными и убыточными конфигурациями. Формально обе системы прибыльны. Практически же только одна из них имеет шанс пережить реальный рынок.

Встроенные средства визуализации MetaTrader 5 хорошо показывают зависимости итоговых метрик от отдельных параметров оптимизации. Тестер показывает значения метрик и распределение результатов. Однако он почти не помогает оценить соседние конфигурации: скорость деградации, наличие устойчивых плато, чувствительность к параметрам и границы переоптимизации. Иными словами, важен уже не столько максимум функции, сколько геометрия всей поверхности оптимизации.

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

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

Оптимизация без самообмана



Фреймы оптимизации как система исследовательской телеметрии

Несмотря на все возможности встроенного тестера, стандартная оптимизация в MetaTrader 5 по своей природе остаётся сухой процедурой. Агент выполняет расчёты. Тестер фиксирует итог. А на выходе пользователь видит уже готовый набор цифр: Profit Factor, Sharpe Ratio, просадку, прибыль и другие сводные показатели. Для первичного отбора этого достаточно. Но для серьёзного анализа — мало. Видна вершина, но почти не видно самого рельефа местности.

Именно здесь и вступают в игру Optimization Frames. Это не просто ещё один способ сохранить результат прохода. Это полноценный канал передачи исследовательских данных между тестовыми агентами и анализирующим кодом. Через фреймы можно передавать всё, что помогает понять поведение стратегии глубже: дополнительные статистики, промежуточные параметры, состояние модели, особенности equity-кривой, оценки устойчивости и любые другие собственные метрики.

Работа этого механизма выглядит довольно естественно. По завершении очередного прохода эксперт передаёт данные через FrameAdd() из OnTester(). Затем в терминале возникает событие TesterPass, и именно оно вызывает OnTesterPass(). Внутри этого обработчика можно сразу разобрать поступивший фрейм: последовательно прочитать данные через FrameFirst() и FrameNext(), а при необходимости отфильтровать нужные записи. На практике это даёт ощущение живого потока результатов: проход завершён, фрейм пришёл, данные уже можно анализировать.

Но у этого потока есть важная особенность. Фреймы могут поступать не по одному, а пакетами. И иногда с заметной задержкой. Особенно это чувствуется при распределённой оптимизации, когда часть расчётов выполняют удалённые агенты. Поэтому не каждый TesterPass успевает обработаться строго в момент завершения очередного прохода. Именно по этой причине OnTesterDeinit() остаётся последним надёжным этапом работы с результатами. Если какие-то фреймы пришли позже, их можно дочитать после завершения оптимизации, пройдя весь массив данных ещё раз с начала через FrameFirst() и при необходимости отсортировать или отфильтровать через FrameFilter().

В результате оптимизация перестаёт быть просто чередой изолированных проходов. Она превращается в систему накопления исследовательской телеметрии по всей поверхности параметров. Это принципиально меняет саму логику работы. Теперь разработчик видит не только итоговое значение критерия, но и контекст, в котором оно было получено. Вместе с Profit Factor можно хранить дополнительные метрики: концентрацию прибыли, равномерность сделок, устойчивость по временным сегментам и характеристики equity-кривой. Отдельно можно сохранять показатели деградации на соседних параметрах и чувствительность к рыночному режиму.

Так каждый проход начинает выглядеть уже как полноценный диагностический пакет. И чем длиннее или сложнее оптимизация, тем выше ценность такого подхода. По сути, настоящая ценность фреймов оптимизации — в post-analysis всей поверхности оптимизации. Вместо анализа отдельных точек появляется возможность изучать пространство параметров как целое: искать устойчивые области, измерять скорость деградации результатов, оценивать чувствительность стратегии и строить собственные критерии устойчивости на основе соседних конфигураций.

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



Простая стратегия как объект исследования

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

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

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

Такой подход решает сразу несколько задач. Стратегия остаётся чрезвычайно компактной и читаемой. Сигнальная логика оказывается хорошо декомпозированой: индикаторы занимаются только генерацией событий, а советник — только обработкой состояний и управлением позицией. И именно событийная архитектура особенно хорошо сочетается с исследовательским характером статьи, поскольку позволяет легко накапливать диагностическую телеметрию о поведении системы.

В основе логики лежит простая идея. Пересечение EMA используется как триггер потенциального входа.

//--- chek signal
   if(fast_buff[1] > slow_buff[1] &&
      fast_buff[0] <= slow_buff[0])
      SendSignalEvent(EVENT_EMA_CROSS, DIR_BUY, 0.0, "EMA CROSS");
   if(fast_buff[1] < slow_buff[1] &&
      fast_buff[0] >= slow_buff[0])
      SendSignalEvent(EVENT_EMA_CROSS, DIR_SELL, 0.0, "EMA CROSS");

Однако сам по себе сигнал пересечения не открывает позицию. Сначала система проверяет текущий режим RSI.

При этом RSI формирует событие только в момент смены режима — при пересечении заданных уровней.

//--- chek signal
   ENUM_SIGNAL_DIRECTION new_regime = current_regime;
   if(rsi_buff[0] <= UpperLevel &&
      rsi_buff[1] > UpperLevel)
      new_regime = DIR_BUY;
   if(rsi_buff[0] >= LowerLevel &&
      rsi_buff[1] < LowerLevel)
      new_regime = DIR_SELL;
   if(rsi_buff[1] >= LowerLevel &&
      rsi_buff[1] <= UpperLevel)
      new_regime = DIR_NONE;
//--- send signal
   if(new_regime != current_regime)
     {
      current_regime = new_regime;
      SendSignalEvent(EVENT_RSI_REGIME, current_regime,
                      rsi_buff[1], "RSI REGIME");
     }

Благодаря этому удаётся существенно снизить шум. Советник хранит текущее состояние RSI в виде внутреннего флага и использует его как контекст рынка. При совпадении сигналов событие считается синхронизированным, и советник открывает сделку.

void OnChartEvent(const int32_t id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---
   if(id-CHARTEVENT_CUSTOM == EVENT_RSI_REGIME)
     {
      rsi_regime = (ENUM_SIGNAL_DIRECTION)lparam;
      rsi_regime_changes++;
      CloseConflictingPosition();
     }
   if(id-CHARTEVENT_CUSTOM == EVENT_EMA_CROSS)
     {
      ema_events++;
      ProcessEntry((int)lparam);
     }
  }

Это важный момент для всей дальнейшей оптимизации. Мы сознательно строим систему вокруг согласованности независимых источников информации.

Управление риском также намеренно оставлено простым. Stop Loss и Take Profit рассчитываются через множители ATR непосредственно в момент открытия позиции. Значение ATR используется только как оценка текущей волатильности и не участвует в событийной модели. Это позволяет сохранить архитектуру максимально чистой: события отвечают за направление, ATR — за масштаб риска.

void ProcessEntry(const int signal)
  {
   if(PositionSelect(_Symbol))
      return;
   if(signal == DIR_BUY &&
      rsi_regime == DIR_BUY)
     {
      if(!atr_buff.CopyIndicatorBuffer(atr_handle, 0, 1, 2))
         return;
      double atr = atr_buff[0];
      double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
      synchronized_entries++;
      double sl = NormalizeDouble(bid - atr * iSLmult,
                                  _Digits);
      double tp = NormalizeDouble(bid + atr * iTPmult,
                                  _Digits);
      trade.Buy(iLots, _Symbol, 0, sl, tp);
     }
   if(signal == DIR_SELL &&
      rsi_regime == DIR_SELL)
     {
      if(!atr_buff.CopyIndicatorBuffer(atr_handle, 0, 1, 2))
         return;
      double atr = atr_buff[0];
      double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
      synchronized_entries++;
      double sl = NormalizeDouble(ask + atr * iSLmult,
                                  _Digits);
      double tp = NormalizeDouble(ask - atr * iTPmult,
                                  _Digits);
      trade.Sell(iLots, _Symbol, 0, sl, tp);
     }
  }

С практической точки зрения подобная стратегия интересна именно своей предсказуемостью. Здесь нет сложной логики, скрытых зависимостей или тяжёлой фильтрации. Любое изменение результатов оптимизации почти напрямую связано с изменением параметров модели. А значит, поверхность оптимизации становится значительно более читаемой и пригодной для исследовательского анализа.



Пользовательские метрики и анализ уровня выше

Тестер MetaTrader 5 умеет считать множество встроенных показателей: прибыль, Profit Factor, Recovery Factor, Sharpe Ratio, просадку, математическое ожидание и другие характеристики прохода. Для оценки отдельной конфигурации этого вполне достаточно. Но вся проблема в том, что такие показатели описывают только одну точку пространства параметров. Они отвечают на вопрос, насколько удачным оказался конкретный проход. Но почти ничего не говорят о том, как ведёт себя стратегия рядом с этой точкой.

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

Визуализация результатов оптимизации в терминале

Две конфигурации могут выглядеть очень похоже по итоговому отчёту, но вести себя совершенно по-разному. Одна даёт высокий Profit Factor, однако держится лишь на узком пике, который рассыпается при малейшем сдвиге параметров. Другая показывает результат скромнее, зато сохраняет близкие значения в более широкой области. Стандартный тестер почти всегда выделит первую конфигурацию как лучшую. Но с исследовательской точки зрения вторая нередко оказывается ценнее, потому что её поведение выглядит устойчивым.

Поэтому уже на уровне одного прохода мы начинаем собирать не только встроенные статистики, но и собственные диагностические метрики. Через FrameAdd можно передавать любую дополнительную телеметрию, которая помогает понять внутреннее поведение стратегии. В нашем случае вместе с базовыми данными сохраняются количество событий пересечения EMA, число смен режимов RSI, число синхронизированных входов, коэффициент конверсии сигналов, прибыль на сигнал и пользовательский критерий устойчивости. Это попытка увидеть, как именно работает система внутри.

double OnTester()
  {
//---
   double profit_per_signal = 0.0;
   double trigger_conversion_ratio = 0.0;
//---
   double profit = TesterStatistics(STAT_PROFIT);
   double pf = TesterStatistics(STAT_PROFIT_FACTOR);
   if(ema_events > 0)
     {
      trigger_conversion_ratio =
         (double)synchronized_entries / (double)ema_events;
     }
   if(synchronized_entries > 0)
     {
      profit_per_signal =
         profit / synchronized_entries;
     }
   double ret =
      CalculateCustomCriterion(pf,
                               trigger_conversion_ratio,
                               profit_per_signal
                              );
//---
   double telemetry[12];
   telemetry[0]  = profit;
   telemetry[1]  = pf;
   telemetry[2]  = ema_events;
   telemetry[3]  = rsi_regime_changes;
   telemetry[4]  = synchronized_entries;
   telemetry[5]  = trigger_conversion_ratio;
   telemetry[6]  = profit_per_signal;
   telemetry[7]  = ret;
   telemetry[8]  = iFastEMA;
   telemetry[9]  = iSlowEMA;
   telemetry[10] = iSLmult;
   telemetry[11] = iTPmult;
//---
   FrameAdd("Telemetry", 0, ret, telemetry);
//---
   return(ret);
  }

Особенно полезен коэффициент конверсии сигналов trigger_conversion_ratio. Он показывает, какая доля триггеров EMA действительно приводит к сделке. Если значение высокое, значит базовый сигнал и режимный фильтр ведут себя согласованно. Если низкое — система либо слишком избирательна, либо слишком шумна, либо сама логика параметров работает неудачно. В любом случае эта метрика говорит не о прибыли как таковой, а о качестве взаимодействия между компонентами модели.

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

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

Именно поэтому экспортированные через фреймы данные сохраняются в CSV-файл.

void OnTesterDeinit()
  {
   ArrayResize(frames, 0, 100);
   FrameFirst();
   int pos = 0;
   ulong pass = 0;
   string name = "";
   long id = 0;
   double value = 0;
   double data[];
   SFrameData item;
//---
   while(FrameNext(pass, name, id, value, data))
     {
      if(ArraySize(data) < 12)
         continue;
      item.pass                 = id;
      item.profit               = data[0];
      item.pf                   = data[1];
      item.ema_events           = data[2];
      item.regime_changes       = data[3];
      item.synchronized_entries = data[4];
      item.conversion_ratio     = data[5];
      item.profit_per_signal    = data[6];
      item.custom_criterion     = data[7];
      item.fast_ema             = data[8];
      item.slow_ema             = data[9];
      item.sl_mult              = data[10];
      item.tp_mult              = data[11];
      pos = ArraySize(frames);
      if(ArrayResize(frames, pos + 1, (pos + 49) / 50) < pos + 1)
         return;
      frames[pos] = item;
     }
   ExportCSV();
//---
  }

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

Для тестирования и последующего анализа мы взяли исторические данные по EURUSD на таймфрейме H1 за период с 1.01.2020 по 1.01.2026. Такой диапазон достаточно длинный, чтобы в нём успели проявиться разные рыночные режимы: спокойные участки, импульсные движения, затяжные тренды и фазы повышенной шумности. Это важно не только для получения правдоподобного результата, но и для того, чтобы поверхность оптимизации не выглядела искусственно гладкой.

Период оптимизации

На первом этапе советник оптимизируется по четырём параметрам: быстрой EMA, медленной EMA, множителю стоп-лосса и множителю тейк-профита. Именно эта четвёрка задаёт базовую форму стратегии и определяет её реакцию на рынок. Чтобы расширить активный диапазон генерации событий и не допустить излишне узкой фильтрации, границы RSI были сдвинуты к значениям 40 и 60. В такой конфигурации режимный фильтр становится более чувствительным, а событийная модель — менее зажатой. Это позволяет советнику чаще входить в исследуемые рыночные состояния и, следовательно, формировать более выразительную поверхность оптимизации.

После завершения оптимизации результаты сохраняются в CSV-файл и переходят в Python-обработку. Здесь для каждой пары параметров строится двумерная поверхность через pivot_table, после чего к ней применяется гауссово сглаживание. Так появляется более спокойная сглаженная поверхность критериев — исследовательская версия, где случайные пики становятся заметно менее выразительными.

Сырая и сглаженная поверхность критерия

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

Визуализация локальной стабильности

Затем строится карта градиента, показывающая, где поверхность меняется резко, а где остаётся сравнительно ровной.

Карта градиентов

Такие графики позволяют увидеть, есть ли в пространстве параметров широкое плато или лишь узкий, хрупкий пик.

Отдельный слой анализа даёт график координат по всем параметрам сразу. Перед его построением параметры нормируются, а затем на Parallel Coordinates выделяются только лучшие прогоны по выбранному критерию. Это удобно, когда нужно увидеть не только отдельную удачную точку, но и её положение среди остальных конфигураций. Скрипт печатает 5% лучших результатов по критерию, чтобы визуальная картина сразу сопровождалась числовой опорой.

Параллельные координаты оптимизируемых параметров

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



От поиска максимума к поиску устойчивого плато

Главная цель исследовательской оптимизации — не максимизация результата, а поиск таких диапазонов параметров, в которых стратегия остаётся устойчивой даже при небольших изменениях конфигурации.

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

Именно поэтому после выгрузки результатов в Python мы смотрим не на отдельные проходы, а на всю поверхность параметров целиком.

Сначала полезно сравнить сырую и сглаженную поверхности критерия оптимизации. Исходная поверхность выглядит пёстро: много локальных всплесков, резких максимумов и одиночных пиков. Это типичная картина шумовой оптимизации, когда случайные совпадения легко маскируются под удачные решения. После сглаживания большая часть таких выбросов исчезает, и на первый план выходят уже не случайности, а более устойчивые структуры.

Именно здесь становится хорошо видно, что не каждый красивый пик заслуживает доверия. Если после сглаживания поверхность распадается и теряет форму, значит найденные экстремумы были скорее случайностью, чем закономерностью. В нашем случае картина другая: сохраняются два выраженных хребта около SlowEMA в диапазонах 120–150 и 220–240. Это уже серьёзный признак того, что перед нами не разовый всплеск, а статистически устойчивый рисунок. Причём оптимум здесь выглядит не как острая игла, а как широкий гребень. А это как раз хороший знак. Устойчивые стратегии редко рождаются в одной точке. Чаще они держатся на плато, где соседние значения дают близкий результат.

После этого имеет смысл посмотреть на температурную карту градиентов. Этот график показывает, насколько быстро меняется целевая функция при смещении параметров EMA. И вот здесь уже становятся заметны области повышенной чувствительности, прежде всего при SlowEMA в диапазонах 70–90 и 200–220. В этих диапазонах даже небольшое изменение настроек может резко изменить результат. А это уже прямой намёк на повышенный риск переоптимизации.

Сам градиент при этом имеет выраженный вертикальный характер. Это означает, что SlowEMA влияет на результат заметно сильнее, чем FastEMA. Логика здесь вполне естественная: медленная средняя задаёт рыночный режим, а быстрая отвечает скорее за точку входа и локальную настройку поведения системы. Напротив, области около SlowEMA в диапазонах 160–190 и 30–50 демонстрируют низкий градиент. Но важно не переоценить этот факт: на Raw Surface и Smoothed Surface видно, что это скорее зоны слабой или близкой к нулю доходности, а не действительно рабочие участки. Плавность поверхности ещё не делает стратегию ценной.

Завершает картину график Parallel Coordinates, построенный для лучших 5% конфигураций по пользовательскому критерию. И здесь видно главное: устойчивые решения не стягиваются в одну магическую точку. Они распределяются по нескольким рабочим комбинациям. Это очень важный сигнал. Узкий одиночный максимум часто выглядит эффектно, но обычно связан с переоптимизацией. А вот распределённые кластеры говорят о том, что система умеет работать в нескольких режимах.

Особенно заметно, что лучшие конфигурации тяготеют к более высоким значениям FastEMA. Это логично: более сглаженные значения уменьшают шум и делают сигналы чище. При этом SlowEMA формирует несколько кластеров, что может указывать на разные рыночные режимы работы стратегии. Параметры SLMult и TPMult распределены более ровно. Это говорит о том, что управление позицией влияет на итоговый результат слабее, чем сама структура EMA-сигналов. Иначе говоря, ядро системы находится в логике входа, а сопровождение сделки играет уже вспомогательную роль.

Следующий шаг логично сделать уже не по всей исходной сетке параметров, а по области, которая показала признаки устойчивой работы. После первого этапа мы сужаем диапазоны FastEMA, SlowEMA, SLMult и TPMult до тех зон, где поверхность выглядит как широкое плато. Затем в модель добавляются ещё два параметра — нижняя и верхняя границы RSI, которые на этом этапе мы оптимизируем уже как часть общей структуры входа. Это позволяет не распыляться на весь параметрический массив сразу, а двигаться от найденной устойчивой конфигурации к её более тонкой настройке.

Именно здесь очень к месту оказывается форвард-тестирование. В MetaTrader 5 при форвард-оптимизации период, заданный для исследования, автоматически делится на две части: на первой выполняется оптимизация, а на второй — форвард-проверка. Причём в форвард-период запускаются не все прогоны, а только лучшие: при полном переборе параметров отбирается 10% лучших, а при генетическом алгоритме — 25%. Затем результаты оптимизации и форварда можно сравнить на отдельных вкладках тестера. Это удобно для контроля подгонки. Также так можно проверить, сохраняет ли выбранный кластер параметров устойчивость вне обучающего участка истории.

Первый этап уже показал, что стратегия не обязана жить на одном остром пике. Теперь задача состоит в том, чтобы проверить, выдерживает ли найденная зона параметров переход в более жёсткий режим проверки. Форвард-тест помогает отделить устойчивую область параметров от той, что хорошо выглядит только на прошлом участке данных.

Форвард-оптимизация

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

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

Результаты форвард-тестирования

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

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

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

  • iFastEMA = 25,
  • iSlowEMA = 135,
  • iUpperLevel = 60,
  • iLowerLevel = 40,
  • iTPmult = 5,
  • iSLmult = 4.

Такая комбинация уже не стремится выжать максимум из одного благоприятного рыночного участка, а скорее формирует более ровную и сдержанную структуру входов. В результате стратегия показывает профит 134.16 USD, Profit Factor на уровне 4.08, Drawdown — 7.05% и 5 сделок. Для данного периода это выглядит как вполне рабочий и при этом осторожный профиль.

График баланса и equity по этому набору параметров подтверждает ту же картину.

График баланса
График одиночного прохода за два периода — оптимизации и форвард-тестирования.
 

На этапе оптимизации, охватившем 72 месяца, стратегия совершила 259 сделок и показала прибыль 141,16% при максимальной просадке по балансу 63,57% и Profit Factor 1,25.

На форвард-тесте продолжительностью 3 месяца было совершено 5 сделок: прибыль составила 13,42%, просадка — 3,91%, а Profit Factor — 4,08.

Стартовав с депозита 1000 USD, стратегия сначала демонстрирует рост до уровня около 1700 USD, после чего проходит через существенную коррекцию, опускаясь к локальному минимуму примерно 620 USD в сентябре 2022 года. Далее следует длительное восстановление и устойчивый восходящий участок, завершающийся на уровне около 2400 USD к концу периода оптимизации. На форвард-отрезке также заметна тенденция к росту баланса, что дополнительно поддерживает вывод о практической жизнеспособности выбранной конфигурации.

Таким образом, форвард-оптимизация позволила отсеять чрезмерно агрессивные и статистически хрупкие решения, включая конфигурации с PF выше 8, которые при ближайшем рассмотрении оказываются подогнанными под период тестирования. На их фоне проход 244 выглядит как наиболее сбалансированный вариант: он сочетает приемлемую прибыльность, умеренную просадку и достаточную стабильность на независимом участке данных. Именно такие решения и представляют наибольший интерес в исследовательской оптимизации — не потому, что они дают самый яркий пик, а потому, что они лучше выдерживают проверку временем и сменой рыночного режима.



Заключение

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

Отсюда и главный вывод работы:

Сильная оптимизация — это не максимум прибыли, а максимум понимания того, что именно было оптимизировано.

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


Программы, используемые в статье

# Имя Тип Описание
1 Expert.mq5 Советник Советник оптимизируемой в статье стратегии
2 CrossEMA.mq5 Индикатор Индикатор генерацией событий при пересечении EMA
3 RSI.mq5 Индикатор Индикатор RSI с генерацией событий при пересечении уровней
4 postanalysis.py Скрипт Скрипт пост-анализа в Python
5 defines.mqh Библиотека Библиотека макроподстановок и общих методов
Прикрепленные файлы |
MQL5.zip (10.13 KB)
Архитектура машинного обучения для MetaTrader 5 (Часть 8): Байесовская оптимизация гиперпараметров с Purged Cross-Validation и ранним отсечением испытаний Архитектура машинного обучения для MetaTrader 5 (Часть 8): Байесовская оптимизация гиперпараметров с Purged Cross-Validation и ранним отсечением испытаний
GridSearchCV и RandomizedSearchCV имеют фундаментальное ограничение в финансовом ML: каждое испытание независимо, поэтому качество поиска не улучшается с ростом вычислительного бюджета. В этой статье Optuna — с использованием Tree-structured Parzen Estimator — интегрируется с кросс-валидацией PurgedKFold, ранней остановкой HyperbandPruner и соглашением о двух типах весов, которое разделяет веса обучения и веса оценки. В результате получается система из пяти компонентов: целевая функция с отсечением на уровне фолдов, слой преобразования/подстановки параметров, совместно оптимизирующий схему взвешивания и гиперпараметры модели, финансово откалиброванное отсечение, возобновляемый оркестратор на базе SQLite и конвертер в формат scikit-learn cv_results_. В статье также проводится четкое разграничение — на основе Тимоти Мастерса — между статистическими целями, где направленный поиск полезен, и финансовыми целями, где он вреден.
Алгоритм оптимизации Архимеда — Archimedes Optimization Algorithm (AOA) Алгоритм оптимизации Архимеда — Archimedes Optimization Algorithm (AOA)
В статье рассматривается алгоритм оптимизации Архимеда — метаэвристика, в которой агент представлен физическим объектом с плотностью, объёмом и ускорением, а сам поиск переосмыслен как стремление погружённых в жидкость тел к равновесию. Баланс между разведкой и эксплуатацией здесь не задаётся внешним расписанием, а вытекает из физики затихающей турбулентности. Реализуем алгоритм на MQL5, прогоняем на стандартном стенде и разбираем, где такая идея работает.
Особенности написания экспертов Особенности написания экспертов
Написание и тестирование экспертов в торговой системе MetaTrader 4.
Разработка инструментария для анализа Price Action (Часть 44): Создание в MQL5 сигнального советника на основе пересечений VWMA Разработка инструментария для анализа Price Action (Часть 44): Создание в MQL5 сигнального советника на основе пересечений VWMA
В этой статье представлен инструмент для MetaTrader 5, сигнализирующий о пересечениях VWMA, который помогает трейдерам выявлять потенциальные бычьи и медвежьи развороты, сочетая анализ движения цены и торгового объема. Советник генерирует четкие сигналы на покупку и продажу прямо на графике, оснащен информативной панелью и позволяет гибко настраивать входные параметры, что делает его практичным дополнением к торговой стратегии.