Трейлинг-стоп по фракталам Билла Вильямса в MQL5: Руководство

Трейлинг-стоп по фракталам Билла Вильямса в MQL5: Руководство MQL4 / MQL5 (MetaTrader)
Пошаговое руководство по созданию надежного трейлинг-стопа по фракталам Билла Вильямса в MQL5. Готовый код, разбор параметров и интеграция в советник.
Суть: Трейлинг-стоп по фракталам Билла Вильямса динамически подтягивает защитный ордер Stop Loss за локальные экстремумы (фракталы), сформированные на графике. Для Buy-позиций стоп-лосс устанавливается на уровень последнего нижнего фрактала (Down Fractal) с небольшим отступом, а для Sell-позиций — на уровень последнего верхнего фрактала (Up Fractal). Это позволяет защитить прибыль, минимизируя влияние рыночного шума.

Исходный код

Ниже представлен готовый к интеграции класс-модуль и функция автоматического сопровождения позиций. Код написан с использованием объектно-ориентированного подхода MQL5 и стандартного торгового класса CTrade. Алгоритм корректно обрабатывает пятибарные фракталы, игнорируя еще не сформированные (активные) бары на индексах 0 и 1, что исключает перерисовку уровней.

#property strict
#include 

// Input parameters
input group "--- Trailing Stop Settings ---"
input int             InpOffsetPoints   = 10;    // Offset from Fractal (Points)
input int             InpMinProfitPoints = 50;    // Min profit to start trailing (Points)

// Global variables
int      fractalsHandle = INVALID_HANDLE;
CTrade   trade;

int OnInit()
{
   // Инициализация хэндла индикатора Fractals
   fractalsHandle = iFractals(_Symbol, _Period);
   if(fractalsHandle == INVALID_HANDLE)
   {
      Print("Failed to create iFractals handle");
      return(INIT_FAILED);
   }
   return(INIT_SUCCEEDED);
}

void OnDeinit(const int reason)
{
   // Освобождаем хэндл индикатора для экономии ресурсов
   if(fractalsHandle != INVALID_HANDLE)
      IndicatorRelease(fractalsHandle);
}

void OnTick()
{
   if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) return;
   
   // Запуск функции трейлинг-стопа
   ApplyFractalsTrailing();
}

void ApplyFractalsTrailing()
{
   double upperFractals[];
   double lowerFractals[];
   
   // Копируем последние 100 значений буферов индикатора
   // Буфер 0: Верхние фракталы (UPPER_LINE)
   // Буфер 1: Нижние фракталы (LOWER_LINE)
   int copiedUpper = CopyBuffer(fractalsHandle, 0, 0, 100, upperFractals);
   int copiedLower = CopyBuffer(fractalsHandle, 1, 0, 100, lowerFractals);
   
   if(copiedUpper <= 0 || copiedLower <= 0)
   {
      Print("Failed to copy fractal buffers");
      return;
   }
   
   // Перебираем все открытые позиции по текущему символу
   for(int i = PositionsTotal() - 1; i >= 0; i--)
   {
      if(PositionGetSymbol(i) == _Symbol)
      {
         ulong ticket = PositionGetInteger(POSITION_TICKET);
         ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
         double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
         double currentSL = PositionGetDouble(POSITION_SL);
         double currentPrice = (type == POSITION_TYPE_BUY) ? SymbolInfoDouble(_Symbol, SYMBOL_BID) : SymbolInfoDouble(_Symbol, SYMBOL_ASK);
         
         if(type == POSITION_TYPE_BUY)
         {
            // Ищем последний сформированный нижний фрактал
            // Начинаем с индекса 2, так как 0 и 1 еще формируются
            double lastDownFractal = 0;
            for(int j = 2; j < copiedLower; j++)
            {
               if(lowerFractals[j] != EMPTY_VALUE && lowerFractals[j] > 0)
               {
                  lastDownFractal = lowerFractals[j];
                  break;
               }
            }
            
            if(lastDownFractal > 0)
            {
               double newSL = NormalizeDouble(lastDownFractal - InpOffsetPoints * _Point, _Digits);
               // Проверяем условие минимальной прибыли
               if(currentPrice - openPrice >= InpMinProfitPoints * _Point)
               {
                  // Новый стоп должен быть выше текущего и ниже текущей цены Bid
                  if(newSL > currentSL && newSL < currentPrice)
                  {
                     trade.PositionModify(ticket, newSL, PositionGetDouble(POSITION_TP));
                  }
               }
            }
         }
         else if(type == POSITION_TYPE_SELL)
         {
            // Ищем последний сформированный верхний фрактал
            double lastUpFractal = 0;
            for(int j = 2; j < copiedUpper; j++)
            {
               if(upperFractals[j] != EMPTY_VALUE && upperFractals[j] > 0)
               {
                  lastUpFractal = upperFractals[j];
                  break;
               }
            }
            
            if(lastUpFractal > 0)
            {
               double newSL = NormalizeDouble(lastUpFractal + InpOffsetPoints * _Point, _Digits);
               // Проверяем условие минимальной прибыли
               if(openPrice - currentPrice >= InpMinProfitPoints * _Point)
               {
                  // Новый стоп должен быть ниже текущего (или равен 0) и выше текущей цены Ask
                  if((newSL < currentSL || currentSL == 0) && newSL > currentPrice)
                  {
                     trade.PositionModify(ticket, newSL, PositionGetDouble(POSITION_TP));
                  }
               }
            }
         }
      }
   }
}

Разбор параметров

  • InpOffsetPoints: Величина отступа в пунктах от экстремальной точки фрактала. Необходима для предотвращения случайного срабатывания стоп-лосса при тестировании уровня тенями свечей.
  • InpMinProfitPoints: Минимальная прибыль в пунктах, которую должна достичь позиция, прежде чем функция трейлинг-стопа начнет свою работу. Предотвращает преждевременный выход из сделки в зоне безубытка.

Как запустить

Для запуска данного алгоритма выполните следующие шаги:

1. Создайте новый советник (Expert Advisor) в MetaEditor.

2. Скопируйте представленный код в тело вашего советника.

3. Инициализируйте хэндл индикатора в функции OnInit() и не забудьте освободить его в OnDeinit().

4. Вызовите функцию ApplyFractalsTrailing() внутри обработчика событий OnTick().

При разработке торговых роботов на MQL5, особенно при использовании нестандартных таймфреймов или синтетических баров, таких как описано в статье Как создать кастомный график Ренко в MetaTrader 5, классические индикаторы Билла Вильямса показывают отличные результаты для фильтрации рыночного шума.

Если вы строите сложную мультивалютную систему, где требуется рассчитывать фракталы по десяткам инструментов одновременно, стандартные методы MQL5 могут нагружать процессор. В таких случаях для оптимизации расчетов стоит изучить руководство Как вызвать C++ DLL в MQL5: Ускорение расчетов для Квантов.

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

Оцените статью
FinFluct