English 中文 Español Deutsch 日本語 Português
preview
Реализация торговой стратегии на основе полос Боллинджера с помощью MQL5: Пошаговое руководство

Реализация торговой стратегии на основе полос Боллинджера с помощью MQL5: Пошаговое руководство

MetaTrader 5Трейдинг | 25 апреля 2025, 12:13
300 4
Kikkih25
Kikkih25

Введение

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

Следуя этому пошаговому руководству, трейдеры могут создать советник, использующий полосы Боллинджера для исполнения ордеров на покупку и продажу в зависимости от конкретных условий на рынке. Будут рассматриваться важные темы, такие как конфигурирование индикатора «Полосы Боллинджера» (Bollinger Bands), контроль торговых позиций и управление обработкой ошибок. Независимо от уровня вашего опыта в разработке или знакомства с алгоритмической торговлей, это руководство даст трейдерам прочную основу для разработки и совершенствования методов торговли.

В этой статье будут рассматриваться следующие темы:

  1. Определение стратегии на основе полос Боллинджера
  2. Описание стратегии на основе полос Боллинджера
  3. Пошаговая реализация с помощью MQL5
  4. Заключение


Определение стратегии на основе полос Боллинджера

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


Описание стратегии на основе полос Боллинджера 

Популярным инструментом технического анализа, которые трейдеры используют для оценки волатильности рынка и выявления потенциальных торговых возможностей, является стратегия «Полосы Боллинджера». Джон Боллинджер создал эту тактику, состоящую из трех основных частей:

  1. Средняя полоса(SMA). Это простая скользящая средняя (SMA) цен закрытия актива за определенный период. Она представляет собой среднюю цену за указанный период и служит основной точкой отсчета для полосы.
  2. Верхняя полоса. Эта полоса рассчитывается путем умножения стандартного отклонения на SMA и отображается над средней полосой. Она обозначает верхнюю границу ценового диапазона и указывает на условия перекупленности или более высокой волатильности. Она рассчитывается по формуле: [{Верхняя полоса} = {Средняя полоса} + {Стандартное отклонение} {Отклонение полосы&}]
  3. Нижняя полоса. Эта полоса вычисляется путем вычитания из SMA значения, кратного стандартному отклонению, и отображается под средней полосой. В результате снижения волатильности или перепроданности он обозначает нижнюю границу ценового диапазона. Она рассчитывается по формуле: [{Нижняя полоса} = {Средняя полоса} - {Стандартное отклонение}]

Ключевые аспекты стратегии:

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

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



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

Применение стратегии:

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


Пошаговая реализация с помощью MQL5 

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

#include<Trade\Trade.mqh> // Include the trade library

Нам необходимо создать экземпляр класса CTrade для использования предлагаемых торговой библиотекой функций.

CTrade trade; // Create an instance of the CTrade class  

Мы можем использовать его методы для торговых операций, таких как открытие, закрытие и изменение ордеров, добавляя торговую библиотеку и инициализируя объект CTrade. Объект CTrade предлагает несколько способов совершения сделок. Используем его в нашем советнике Bollinger Bands для инициирования ордеров на покупку и продажу в соответствии с торговыми обстоятельствами, указанными в функции onTick. Объект trade используется для открытия ордеров на покупку и продажу. Ордер на покупку открывается советником, когда цена опускается ниже нижней полосы Боллинджера.

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

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

Входные данные переменных можно менять из терминала MetaTrader без необходимости вносить изменения в код. Ключевое слово input используется для их объявления. Советник Bollinger Bands использует следующие входные параметры:

 // Input parameters for the Bollinger Bands strategy
 input int BandPeriod = 30;
 input double BandDeviation = 2.0;
 input double LotSize = 0.2;
 input int Slippage = 3;
 const double StopLoss = 70;
 const double TakeProfit = 140;

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

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

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

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

Константы — неизменяемые значения, которые устанавливают во время компиляции, и их нельзя изменить во время исполнения. Для их определения используется ключевое слово const:

const double StopLoss = 70;           
const double TakeProfit = 140;   

Stop Loss — разница в пунктах между стоп-лоссом и ценой открытия. При движении рынка против вас на указанное количество пунктов можно ограничить возможные потери, закрыв сделку. Эту цифру следует определять в зависимости от волатильности рынка и установленных вами правил управления рисками.

Take Profit — разница в пунктах между тейк-профитом и ценой открытия между уровнями entImpactacto и тейк-профит. Сохраняет прибыль, выходя из сделки при развороте рынка. Несколько пунктов для настройки. Корректируйте в зависимости от желаемого уровня прибыли и состояния рынка.

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

После этого рассмотрим переменную integer. На протяжении всего скрипта этот дескриптор необходим для ссылки на показание и взаимодействия с ним.

int Bb_Handle; // Handle for the Bollinger Bands indicator

Этот дескриптор — неотъемлемая часть работы с индикатором Bollinger Bands на MQL5. Он гарантирует бесперебойную и эффективную реализацию торговой стратегии за счет оптимизации управления данными и ресурсами индикатора.

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

Перед функцией OnInit советник определяет несколько используемых и неиспользуемых входных параметров. К ним относятся период, отклонение полос Боллинджера, размер лота, проскальзывание и стоп.

Создание дескриптора для индикатора Bollinger Bands — основная задача функции OnInit. Это делается с помощью функции iBands.

int OnInit()
  {
   Bb_Handle = iBands(_Symbol, _Period, BandPeriod, BandDeviation, 0, PRICE_CLOSE);

Здесь мы пытаемся создать индикатор Bollinger Bands с указанным параметром и назначаем дескриптору значение Bb_Handle.

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

if(Bb_Handle == INVALID_HANDLE)
     {
      Print("Error creating Bollinger Bands indicator");
      return(INIT_FAILED);
     }

Функция OnInit должна возвращать INIT_SUCCEEDED, чтобы показать, что процедура инициализации была успешно завершена, если дескриптор индикатора действителен.

return(INIT_SUCCEEDED);
  }

При комбинации всех этих шагов функция OnInit выглядит, как показано ниже:

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   // Create the Bollinger Bands indicator handle
   Bb_Handle = iBands(_Symbol, _Period, BandPeriod, BandDeviation, 0, PRICE_CLOSE); 
    { 
    if(Bb_Handle == INVALID_HANDLE)
     {
      Print("Error creating Bollinger Bands indicator"); 
      return(INIT_FAILED);
     }
   return(INIT_SUCCEEDED);
  }

Функция OnInit играет важную роль для настройки составных компонентов советника. Алгоритм обеспечивает собственную готовность к реализации торговой логике, устанавливая дескриптор для индикатора Bollinger Bands и справляясь с любыми рисками.

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

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   // Release the Bollinger Bands indicator hande
   IndicatorRelease(Bb_Handle);
  }

Освобождение дескриптора индикатора Bollinger Bands — основная задача функции OnDeinit в нашем советнике. Используется функция IndicatorRelease.

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

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
    double upperBand[], lowerBand[], middleBand[];
   
    // Copy the Bollinger Bands values into arrays
    if(CopyBuffer(Bb_Handle, 0, 0, 1, upperBand) <= 0||
      (CopyBuffer(Bb_Handle, 1, 0, 1, middleBand) <= 0||
      (CopyBuffer(Bb_Handle, 2, 0, 1, lowerBand) <= 0||
   {
     Print("Error copying band values");
     return;
    
     double upper = upperBand[0];
     double lower = lowerBand[0];
     double middle = middleBand[0];
     double price = Close[0];
     double Ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
     double Bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
     
     // Buy signal: price is below the lower band and no open positions 
    if(price < lower && ! IsPositionOpen(_symbol))
      {
       double sl, tp;
       CalculateSLTP(sl, tp, price, true);
      if(trade.Buy(LotSize, _symbol, Ask, sl, tp, "Buy Order"))
        Print("Buy order opened at price: ", price);
      else
      { 
       Print("Error opening BUY order:", trade.ResultRetcode());
     }
      // Sell signal: price is above the upper band no open positions
      else if(price > upper && ! IsPositionOpen(_symbol))
       {
        double sl, tp;
        CalculateSLTP(sl, tp, price, false);
       if(trade.Sell(LotSize, _Symbol, Bid, sl, tp, "Sell Order"));
         Print("Sell order opened at price:", Price);
      else
         print("Error opening SELL order:", trade.ResultRetcode())
    }
  }

Ниже приводится подробный разбор функции OnTick для облегчения понимания:

Определение и извлечение значений Bollinger Bands: первоочередная задача — извлечение текущих значений полос Боллинджера. Для этой цели используется функция CopyBuffer, копирующая значения индикатора в массивы.

double upperBand[], lowerBand[], middleBand[];
   
    // Copy the Bollinger Bands values into arrays
    if(CopyBuffer(Bb_Handle, 0, 0, 1, upperBand) <= 0||
      (CopyBuffer(Bb_Handle, 1, 0, 1, middleBand) <= 0||
      (CopyBuffer(Bb_Handle, 2, 0, 1, lowerBand) <= 0||
   {
     Print("Error copying band values");
     return;

Присвоение значений полос переменным: значения из массива затем присваиваются переменным для упрощения обращений к ним.

     double upper = upperBand[0];
     double lower = lowerBand[0];
     double middle = middleBand[0];
     double price = Close[0];

Извлечение текущих цен Ask и Bid: именно здесь нам нужны текущие цены Ask и Bid для размещения сделок.

     double Ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
     double Bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);

Торговая логика на основе полос Боллинджера: цена условий tBuy — основа торговой логики.

  • Условие покупки: размещайте ордер на покупку, если нет открытых позиций и цена находится ниже нижней полосы. 
   // Buy signal: price is below the lower band and no open positions 
    if(price < lower && ! IsPositionOpen(_symbol))
      {
       double sl, tp;
       CalculateSLTP(sl, tp, price, true);
      if(trade.Buy(LotSize, _symbol, Ask, sl, tp, "Buy Order"))
        Print("Buy order opened at price: ", price);
      else
      { 
       Print("Error opening BUY order:", trade.ResultRetcode());
     }
  • Условие продажи: размещайте ордер на продажу, если нет открытых позиций и цена находится выше верхней полосы.
 // Sell signal: price is above the upper band no open positions
      else if(price > upper && ! IsPositionOpen(_symbol))
       {
        double sl, tp;
        CalculateSLTP(sl, tp, price, false);
       if(trade.Sell(LotSize, _Symbol, Bid, sl, tp, "Sell Order"));
         Print("Sell order opened at price:", Price);
      else
         print("Error opening SELL order:", trade.ResultRetcode())
    }
  }

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

В дополнение к основной функции OnTick наш советник опирается на вспомогательные функции для управления позициями, определения уровней стоп-лосса и тейк-профита и обеспечения бесперебойных торговых операций. Функции поддержки имеют большое значение для сохранения устойчивости и эффективности торговой стратегии. Рассмотрим вспомогательные функции, которые используются в нашем пошаговом советнике Bollinger Bands.

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

//+------------------------------------------------------------------+
//| Check if there's an open position for a symbol                   |
//+------------------------------------------------------------------+
   
   bool IsPositionOpen(string symbol)
   }
    for(int i = 0;  i< PositionsTotal(); i++)
    }
     if(PositionSelectByIndex(i) && PositionGetString(POSITION_SYMBOL) == symbol)
       return true;
     {
      return false;
    }

Пошаговая разбивка функции проверки наличия открытой позиции:

  • Перебрать все позиции: 
for(int i = 0;  i< PositionsTotal(); i++)
    }

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

  • Выбор позиции по индексу:  
if(PositionSelectByIndex(i) && PositionGetString(POSITION_SYMBOL) == symbol)
       

Эта функция выбирает местоположение индекса i. Получает символ выбранной позиции с помощью PositionGetString.

  • Проверяет символ и возвращает true при совпадении:
if(PositionSelectByIndex(i) && PositionGetString(POSITION_SYMBOL) == symbol)
       return true;
     

Сравнивает символ позиции с входным символом. При обнаружении совпадения возвращает true.

  • Возвращает false, если совпадений не найдено.
return false;
    }

После перебора всех позиций возвращает false, если для символа не обнаружена открытая позиция.

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

//+------------------------------------------------------------------+
//|Close all positions for a symbol                                  |
//+------------------------------------------------------------------+
   void CloseAllPositions(string symbol)
  {
   for(int i = PositionsTotal() - 1; i >= 0; i--)
   {
    if(PositionSelectByIndex(i) && PositionGetString(POSITION_SYMBOL) == symbol)
     {
      ulong ticket = PositionGetInteger(POSITION_TICKET);
    if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
         trade.sell(LotSize, symbol, symbolInfoDouble(symbol, SYMBOL_BID), Slippage, 0, "Close Buy");
     {
     if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
          trade.Buy(LotSize, symbol, SymbolInfoDouble(symbol, SYMBOL_ASK), Slippage, 0, "Close Sell");
          // Wait for order to be processed before continuing
            Sleep(1000);
           }
          }
         }
        

Пошаговая разбивка закрытия всех позиций по функции as symbol:

  • Перебрать все позиции в обратном порядке
for(int i = 0;  i< PositionsTotal(); i++)    

Возвращается в исходную точку после выполнения цикла. Гарантирует, что закрытие позиции не изменит порядок индекса.

  • Выбор позиции по индексу и символу check:

   if(PositionSelectByIndex(i) && PositionGetString(POSITION_SYMBOL) == symbol

Выбирает местоположение и определяет, совпадают ли входной символ и текущий.

  • Получим тикет и тип позиции:

      ulong ticket = PositionGetInteger(POSITION_TICKET);

Получает номер тикета позиции.

  • Закрываем позиции на покупку или продажу:

if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
        trade.Sell(LotSize, symbol, SymbolInfoDouble(symbol, SYMBOL_BID), Slippage, 0, "Close Buy");
  else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
        trade.Buy(LotSize, symbol, SymbolInfoDouble(symbol, SYMBOL_ASK), Slippage, 0, "Close Sell");

Закрывает позиции на покупку через продажи и позиции на продажу через продажи, а также позиции на продажу через покупки. Использует текущие цены Ask и Bid.

  • Сделаем паузу, чтобы можно было обработать ордера:
      // Wait for order to be processed before continuing
            Sleep(1000);
           }
          }
         }

Перед переходом к следующему полю делает паузу на мгновение, чтобы убедиться, что ордер обработан.

Далее следует последняя из наших вспомогательных функций, которая рассчитывает уровни Stop Loss и Take Profit. Уровни Stop Loss (SL) и Take Profit (TP) определяются функцией CalculateSLTP с использованием текущей цены и статуса (покупки или продажи) сделки.

//+------------------------------------------------------------------+
//| Calculate Stop Loss and Take Profit levels                       |
//+------------------------------------------------------------------+
   void CalculateSLTP(double &sl, double &tp, double price, bool isBuy)
   {
    if(isBuy)
     {
      sl = price - StopLoss *_Point;
      tp = price + TakeProfit *_Point;
     }
     else 
      {
       sl = price + StopLoss *_Point;
       tp = price - TakeProfit *_Point;
      }
     }

Пошаговый разбор расчета функции уровней Stop Loss и Take Profit:

  • Определим параметры функции:

void CalculateSLTP(double &sl, double &tp, double price, bool isBuy)
  • sl: Упоминается уровень Stop Loss.
  • tp: Порог для Take Profit.
  • price: Фактическая ставка.
  • sBuy: Логическое значение, которое указывает, является сделка покупкой (true) или продажей (false).

Определяем SL и TP при открытии ордера на покупку:

if(isBuy)
  {
    sl = price - StopLoss * _Point;
    tp = price + TakeProfit * _Point;
  }

Stop Loss: вычитает заданное значение StopLoss (в пунктах) из текущего значения Take Profit.

Take Profit: прибавляет заданное значение TakeProfit (в пунктах) к текущей цене. Рассчитаем SL и TP для сделок на продажу.

else
  {
    sl = price + StopLoss * _Point;
    tp = price - TakeProfit * _Point;
  }
}

Stop Loss: увеличивает текущую цену на значение StopLoss (в пунктах).

Take Profit: вычитает указанное значение TakeProfit (в пунктах) из текущей цены.

Полный код вспомогательных функций выглядит так:

//+------------------------------------------------------------------+
//| Check if there's an open position for a symbol                   |
//+------------------------------------------------------------------+
   
   bool IsPositionOpen(string symbol)
   }
    for(int i = 0;  i< PositionsTotal(); i++)
    }
     if(PositionSelectByIndex(i) && PositionGetString(POSITION_SYMBOL) == symbol)
       return true;
     {
      return false;
    }
//+------------------------------------------------------------------+
//|Close all positions for a symbol                                  |
//+------------------------------------------------------------------+
   void CloseAllPositions(string symbol)
  {
   for(int i = PositionsTotal() - 1; i >= 0; i--)
   {
    if(PositionSelectByIndex(i) && PositionGetString(POSITION_SYMBOL) == symbol)
     {
      ulong ticket = PositionGetInteger(POSITION_TICKET);
    if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
         trade.sell(LotSize, symbol, symbolInfoDouble(symbol, SYMBOL_BID), Slippage, 0, "Close Buy");
     {
     if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
          trade.Buy(LotSize, symbol, SymbolInfoDouble(symbol, SYMBOL_ASK), Slippage, 0, "Close Sell");
          // Wait for order to be processed before continuing
            Sleep(1000);
           }
          }
         }
        
//+------------------------------------------------------------------+
//| Calculate Stop Loss and Take Profit levels                       |
//+------------------------------------------------------------------+
   void CalculateSLTP(double &sl, double &tp, double price, bool isBuy)
   {
    if(isBuy)
     {
      sl = price - StopLoss *_Point;
      tp = price + TakeProfit *_Point;
     }
     else 
      {
       sl = price + StopLoss *_Point;
       tp = price - TakeProfit *_Point;
      }
     }

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

Так выглядит полный код нашей статьи:

//+------------------------------------------------------------------+
//|                                               BollingerBands.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

 #include<Trade\Trade.mqh> // Include the trade library
 CTrade trade; // Create an instance of the CTrade class  

 // Input parameters for the Bollinger Bands strategy
 input int BandPeriod = 30;
 input double BandDeviation = 2.0;
 input double LotSize = 0.2;
 input int Slippage = 3;
 const double StopLoss = 70;
 const double TakeProfit = 140;
 
 int Bb_Handle; // Handle for the Bollinger Bands indicator 

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   // Create the Bollinger Bands indicator handle
   Bb_Handle = iBands(_Symbol, _Period, BandPeriod, BandDeviation, 0, PRICE_CLOSE); 
    { 
    if(Bb_Handle == INVALID_HANDLE)
     {
      Print("Error creating Bollinger Bands indicator"); 
      return(INIT_FAILED);
     }
   return(INIT_SUCCEEDED);
  }
 
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   // Release the Bollinger Bands indicator hande
   IndicatorRelease(Bb_Handle);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
    double upperBand[], lowerBand[], middleBand[];
   
    // Copy the Bollinger Bands values into arrays
    if(CopyBuffer(Bb_Handle, 0, 0, 1, upperBand) <= 0||
      (CopyBuffer(Bb_Handle, 1, 0, 1, middleBand) <= 0||
      (CopyBuffer(Bb_Handle, 2, 0, 1, lowerBand) <= 0||
   {
     Print("Error copying band values");
     return;
    
     double upper = upperBand[0];
     double lower = lowerBand[0];
     double middle = middleBand[0];
     double price = Close[0];
     double Ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
     double Bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
     
     // Buy signal: price is below the lower band and no open positions 
    if(price < lower && ! IsPositionOpen(_symbol))
      {
       double sl, tp;
       CalculateSLTP(sl, tp, price, true);
      if(trade.Buy(LotSize, _symbol, Ask, sl, tp, "Buy Order"))
        Print("Buy order opened at price: ", price);
      else
      { 
       Print("Error opening BUY order:", trade.ResultRetcode());
     }
      // Sell signal: price is above the upper band no open positions
      else if(price > upper && ! IsPositionOpen(_symbol))
       {
        double sl, tp;
        CalculateSLTP(sl, tp, price, false);
       if(trade.Sell(LotSize, _Symbol, Bid, sl, tp, "Sell Order"));
         Print("Sell order opened at price:", Price);
      else
         print("Error opening SELL order:", trade.ResultRetcode())
    }
  }

//+------------------------------------------------------------------+
//| Check if there's an open position for a symbol                   |
//+------------------------------------------------------------------+
   
   bool IsPositionOpen(string symbol)
   }
    for(int i = 0;  i< PositionsTotal(); i++)
    }
     if(PositionSelectByIndex(i) && PositionGetString(POSITION_SYMBOL) == symbol)
       return true;
     {
      return false;
    }
//+------------------------------------------------------------------+
//|Close all positions for a symbol                                  |
//+------------------------------------------------------------------+
   void CloseAllPositions(string symbol)
  {
   for(int i = PositionsTotal() - 1; i >= 0; i--)
   {
    if(PositionSelectByIndex(i) && PositionGetString(POSITION_SYMBOL) == symbol)
     {
      ulong ticket = PositionGetInteger(POSITION_TICKET);
    if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
         trade.sell(LotSize, symbol, symbolInfoDouble(symbol, SYMBOL_BID), Slippage, 0, "Close Buy");
     {
     if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
          trade.Buy(LotSize, symbol, SymbolInfoDouble(symbol, SYMBOL_ASK), Slippage, 0, "Close Sell");
          // Wait for order to be processed before continuing
            Sleep(1000);
           }
          }
         }
        
//+------------------------------------------------------------------+
//| Calculate Stop Loss and Take Profit levels                       |
//+------------------------------------------------------------------+
   void CalculateSLTP(double &sl, double &tp, double price, bool isBuy)
   {
    if(isBuy)
     {
      sl = price - StopLoss *_Point;
      tp = price + TakeProfit *_Point;
     }
     else 
      {
       sl = price + StopLoss *_Point;
       tp = price - TakeProfit *_Point;
      }
     }

Ай да мы! Нам удалось создать интеллектуальную систему торговли на основе полос Боллинджера для генерации торговых сигналов.


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

Вот результаты тестирования в тестере стратегий:

График:

Результат:


В период с 2016 по 2019 гг. стратегия совершила 1425 сделок, из которых 857 закрылись с прибылью, что на 20.28% больше, чем убыточных сделок.          

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

Вот настройки, которые мы использовали для проведения теста:


Заключение

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

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

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

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

Прикрепленные файлы |
BollingerBands.mq5 (5.15 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (4)
Lucas Damien Lafon
Lucas Damien Lafon | 8 авг. 2024 в 18:06

Мы находимся в 2024 году, а ваш бэктест останавливается в 2019 году.

Это потому, что он не работает после 2019 года?

Richard Poster
Richard Poster | 8 авг. 2024 в 18:19
Советник содержит многочисленные ошибки компиляции.
Frederic Metraux
Frederic Metraux | 16 авг. 2024 в 02:24

Вот один код, который, по крайней мере, компилируется в MT5 :)

Shashank Rai
Shashank Rai | 29 сент. 2024 в 21:17

В этом коде слишком много ошибок. Я исправил ошибки и выкладываю обновленный код здесь. Пожалуйста!

//+------------------------------------------------------------------+
//|BollingerBands.mq5 |
//|Copyright 2024, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include <Trade\Trade.mqh> // Включите торговую библиотеку
CTrade trade; // Создайте экземпляр класса CTrade 

// Входные параметры для стратегии Bollinger Bands
input int BandPeriod = 30;
input double BandDeviation = 2.0;
input double LotSize = 0.2;
input int Slippage = 3;
input double StopLoss = 70;
input double TakeProfit = 140;

int Bb_Handle; // Ручка для индикатора Bollinger Bands 

//+------------------------------------------------------------------+
//| Функция инициализации эксперта|
//+------------------------------------------------------------------+
int OnInit()
{
   // Создайте ручку индикатора Bollinger Bands
   Bb_Handle = iBands(_Symbol, PERIOD_CURRENT, BandPeriod, 0, BandDeviation, PRICE_CLOSE);
   
   if(Bb_Handle == INVALID_HANDLE)
   {
      Print("Error creating Bollinger Bands indicator"); 
      return(INIT_FAILED);
   }
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Функция деинициализации эксперта|
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   // Отпустите ручку индикатора Bollinger Bands
   IndicatorRelease(Bb_Handle);
}

//+------------------------------------------------------------------+
//| Функция экспертного тика|
//+------------------------------------------------------------------+
void OnTick()
{
   double upperBand[], lowerBand[], middleBand[];
   
   // Скопируйте значения полос Боллинджера в массивы
   if(CopyBuffer(Bb_Handle, 0, 0, 1, upperBand) <= 0 ||
      CopyBuffer(Bb_Handle, 1, 0, 1, middleBand) <= 0 ||
      CopyBuffer(Bb_Handle, 2, 0, 1, lowerBand) <= 0)
   {
      Print("Error copying band values");
      return;
   }
   
   double upper = upperBand[0];
   double lower = lowerBand[0];
   double middle = middleBand[0];
   double price = SymbolInfoDouble(_Symbol, SYMBOL_LAST);
   double Ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double Bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   
   // Сигнал к покупке: цена находится ниже нижней полосы и нет открытых позиций 
   if(price < lower && !IsPositionOpen(_Symbol))
   {
      double sl, tp;
      CalculateSLTP(sl, tp, Ask, true);
      if(trade.Buy(LotSize, _Symbol, Ask, sl, tp, "Buy Order"))
         Print("Buy order opened at price: ", Ask);
      else
         Print("Error opening BUY order:", trade.ResultRetcode());
   }
   // Сигнал на продажу: цена находится выше верхней полосы и нет открытых позиций
   else if(price > upper && !IsPositionOpen(_Symbol))
   {
      double sl, tp;
      CalculateSLTP(sl, tp, Bid, false);
      if(trade.Sell(LotSize, _Symbol, Bid, sl, tp, "Sell Order"))
         Print("Sell order opened at price:", Bid);
      else
         Print("Error opening SELL order:", trade.ResultRetcode());
   }
}

//+------------------------------------------------------------------+
//| Проверьте, есть ли открытая позиция для символа |
//+------------------------------------------------------------------+
bool IsPositionOpen(string symbol)
{
   for(int i = 0; i < PositionsTotal(); i++)
   {
      if(PositionGetSymbol(i) == symbol)
         return true;
   }
   return false;
}

//+------------------------------------------------------------------+
//| Закрыть все позиции для символа|
//+------------------------------------------------------------------+
void CloseAllPositions(string symbol)
{
   for(int i = PositionsTotal() - 1; i >= 0; i--)
   {
      if(PositionGetSymbol(i) == symbol)
      {
         ulong ticket = PositionGetTicket(i);
         if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
            trade.PositionClose(ticket, Slippage);
         else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
            trade.PositionClose(ticket, Slippage);
         // Подождите, пока заказ будет обработан, прежде чем продолжить
         Sleep(1000);
      }
   }
}

//+------------------------------------------------------------------+
//| Рассчитайте уровни стоп-лосса и тейк-профита |
//+------------------------------------------------------------------+
void CalculateSLTP(double &sl, double &tp, double price, bool isBuy)
{
   if(isBuy)
   {
      sl = price - StopLoss * _Point;
      tp = price + TakeProfit * _Point;
   }
   else 
   {
      sl = price + StopLoss * _Point;
      tp = price - TakeProfit * _Point;
   }
}
Создание самооптимизирующихся советников на языках MQL5 и Python (Часть II): Настройка глубоких нейронных сетей Создание самооптимизирующихся советников на языках MQL5 и Python (Часть II): Настройка глубоких нейронных сетей
Модели машинного обучения имеют различные настраиваемые параметры. В этой серии статей мы рассмотрим, как настроить ИИ-модели в соответствии с конкретным рынком с помощью библиотеки SciPy.
Разрабатываем мультивалютный советник (Часть 26): Информер для торговых инструментов Разрабатываем мультивалютный советник (Часть 26): Информер для торговых инструментов
Прежде, чем двигаться дальше в разработке мультивалютных советников, попробуем переключиться на создание нового проекта, использующего разработанную библиотеку. На этом примере выявим, как лучше организовать хранение исходного кода, и как нам может помочь использование нового репозитория кода от MetaQuotes.
HTTP и Connexus (Часть 2): Понимание архитектуры HTTP и дизайна библиотеки HTTP и Connexus (Часть 2): Понимание архитектуры HTTP и дизайна библиотеки
В настоящей статье рассматриваются основы протокола HTTP, описываются основные методы (GET, POST, PUT, DELETE), коды состояния, а также структура URL-адресов. Кроме того, в ней представлено начало создания библиотеки Connexus с классами CQueryParam и CURL, облегчающими манипулирование URL-адресами и параметрами запросов в HTTP-запросах.
Нейросети в трейдинге: Оптимизация LSTM для целей прогнозирования многомерных временных рядов (DA-CG-LSTM) Нейросети в трейдинге: Оптимизация LSTM для целей прогнозирования многомерных временных рядов (DA-CG-LSTM)
Статья знакомит с алгоритмом DA-CG-LSTM, который предлагает новые подходы к анализу временных рядов и их прогнозированию. Из нее вы узнаете, как инновационные механизмы внимания и гибкость модели позволяют улучшить точность прогнозов.