English Español Deutsch 日本語 Português
preview
Построение модели ограничения тренда свечей (Часть 2): Объединение нативных индикаторов

Построение модели ограничения тренда свечей (Часть 2): Объединение нативных индикаторов

MetaTrader 5Трейдинг | 17 сентября 2024, 14:31
312 2
Clemence Benjamin
Clemence Benjamin

Содержание

  1. Введение
  2. Оглядываясь назад
  3. Проблемы с текущей версией
  4. Управление версиями
  5. Скользящие средние
  6. Включение скользящих средних в нашу программу
  7. Изучение RSI
  8. Реализация RSI
  9. Сравнение результатов
  10. Заключение


Введение

MetaTrader 5 располагает встроенными индикаторами, которые обеспечивают трейдерам значительное аналитическое преимущество на рынке. В этой статье будут подробно рассмотрены два из них - скользящие средние и индекс относительной силы (RSI). Скользящие средние обычно используются для определения направления тренда и потенциальных уровней поддержки и сопротивления. Они сглаживают ценовые данные, создавая единую плавную линию, что упрощает выявление трендов. RSI представляет собой импульсный осциллятор, который измеряет скорость и изменение ценовых движений. Трейдеры используют RSI для определения состояний перекупленности и перепроданности на рынке, что может помочь им принимать более обоснованные торговые решения. Объединив эти два индикатора, трейдеры могут получить ценную информацию о рыночных трендах и потенциальных точках входа и выхода для своих сделок. 

Вот некоторые из часто используемых встроенных индикаторов в MetaTrader 5:

  • Скользящие средние
  • Полосы Боллинджера
  • Индекс относительной силы (RSI)
  • Схождение/расхождение скользящих средних (MACD)
  • Стохастический осциллятор
  • Средний истинный диапазон (Average True Range)
  • Облака Ишимоку (Ichimoku Kinko Hyo)
  • Уровни Фибоначчи

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


Оглядываясь назад

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


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

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

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

#define PLOT_MAXIMUM_BARS_BACK 10000 //the integer value can be made higher expanding the gap you can visualize in history
#define OMIT_OLDEST_BARS 50


Проблемы с текущей версией

На данном этапе мы изучаем сигналы, подаваемые на график индикатора Trend Constraint. Хотя ограничение успешно отфильтровывало негативные сигналы, мы по-прежнему сталкиваемся с проблемами, связанными с нетрендовыми сигналами в очень небольшом визуальном масштабе. Важно их устранить и сосредоточиться на настоящих трендовых сигналах. Это подчеркивает необходимость использования встроенных инструментов, таких как скользящая средняя и RSI с помощью MQL5. В следующих разделах мы более подробно рассмотрим эти инструменты.

Boom500 index; Off-Trend Signals

Рис. 1. Trend Constraint v1.00, индекс Boom 500

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


Управление версиями

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

///Indicator Name: Trend Constraint
#property copyright "Clemence Benjamin"
#property link      "https://mql5.com"
#property version   "1.00"
#property description "A model that seek to produce sell signal when D1 candle is Bearish only and  buy signal when it is Bullish"

Чтобы обновить нашу версию, нам просто нужно изменить цифры под свойством версии в коде. Например, в этой статье наша следующая версия Trend Constraint будет 1.01. Ниже представлен обновленный фрагмент кода, демонстрирующий, как она будет выглядеть в основном коде далее в статье.

///Indicator Name: Trend Constraint
#property copyright "Clemence Benjamin"
#property link      "https://mql5.com"
#property version   "1.01"
#property description "A model that seek to produce sell signal when D1 candle is Bearish only and  buy signal when it is Bullish"

Готово! Таким образом мы обновляем нашу программу MQL5. Далее мы перейдем к версиям 1.02, 1.03, 1.04 и т. д.


Скользящие средние

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

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

 Скользящие средние для анализа финансовых рынков начали использовать Ричард Дончиан и Жорж Марешаль в середине 20 века.

Формула расчета простой скользящей средней (SMA) довольно проста:

SMA = (P1 + P2 ... + Pn)/n

где:

  • SMA = простая скользящая средняя
  • P1,P2,...,Pn = цена за указанные периоды (например, цены закрытия)
  • n = количество периодов (например, дней), за которые рассчитываются средние значения.

График EURUSD со скользящими средними

Рис. 2. Скользящие средние, EURUSD

Включение скользящих средних в программу

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

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

В предыдущей статье мы разработали индикатор D1 Trend Constraint с двумя буферами для покупки и продажи. Хотя изначально все выглядело удовлетворительно, сейчас наша цель — еще больше повысить его эффективность. Как и в нашей предыдущей работе, код состоит из 2 буферов. Наша цель — ограничить вывод медленными скользящими средними, чтобы отфильтровать ложные сигналы. Медленные скользящие средние играют важную роль в определении трендов. Ограничение предписывает покупать только тогда, когда цена выше SMA 400, и продавать только тогда, когда она ниже.

  1. Сглаженная простая скользящая средняя (SSMA) 7 для представления цены
  2. Простая скользящая средняя 400 для представления усиления тренда
  3. Код MQL5 условия.
///Indicator Name: Trend Constraint
#property copyright "Clemence Benjamin"
#property link      "https://mql5.com"
#property version   "1.00"
#property description "A model that seek to produce sell signal when D1 candle is Bearish only and  buy signal when it is Bullish"

//--- indicator settings
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_plots 2

#property indicator_type1 DRAW_ARROW
#property indicator_width1 5
#property indicator_color1 0xD42A00
#property indicator_label1 "Buy"

#property indicator_type2 DRAW_ARROW
#property indicator_width2 5
#property indicator_color2 0x0000D4
#property indicator_label2 "Sell"

#define PLOT_MAXIMUM_BARS_BACK 5000
#define OMIT_OLDEST_BARS 50

//--- indicator buffers
double Buffer1[];
double Buffer2[];

double myPoint; //initialized in OnInit
int MA_handle;
double MA[];
int MA_handle2;
double MA2[];
double Open[];
double Close[];
int MA_handle3;
double MA3[];
int MA_handle4;
double MA4[];
double Low[];
double High[];

void myAlert(string type, string message)
  {
   if(type == "print")
      Print(message);
   else if(type == "error")
     {
      Print(type+" | Trend Constraint @ "+Symbol()+","+IntegerToString(Period())+" | "+message);
     }
   else if(type == "order")
     {
     }
   else if(type == "modify")
     {
     }
  }

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {   
   SetIndexBuffer(0, Buffer1);
   PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1));
   PlotIndexSetInteger(0, PLOT_ARROW, 241);
   SetIndexBuffer(1, Buffer2);
   PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1));
   PlotIndexSetInteger(1, PLOT_ARROW, 242);
   //initialize myPoint
   myPoint = Point();
   if(Digits() == 5 || Digits() == 3)
     {
      myPoint *= 10;
     }
   MA_handle = iMA(NULL, PERIOD_CURRENT, 7, 0, MODE_EMA, PRICE_CLOSE);
   if(MA_handle < 0)
     {
      Print("The creation of iMA has failed: MA_handle=", INVALID_HANDLE);
      Print("Runtime error = ", GetLastError());
      return(INIT_FAILED);
     }
   
   MA_handle2 = iMA(NULL, PERIOD_CURRENT, 21, 0, MODE_EMA, PRICE_CLOSE);
   if(MA_handle2 < 0)
     {
      Print("The creation of iMA has failed: MA_handle2=", INVALID_HANDLE);
      Print("Runtime error = ", GetLastError());
      return(INIT_FAILED);
     }
   
   MA_handle3 = iMA(NULL, PERIOD_CURRENT, 7, 0, MODE_SMMA, PRICE_CLOSE);
   if(MA_handle3 < 0)
     {
      Print("The creation of iMA has failed: MA_handle3=", INVALID_HANDLE);
      Print("Runtime error = ", GetLastError());
      return(INIT_FAILED);
     }
   
   MA_handle4 = iMA(NULL, PERIOD_CURRENT, 400, 0, MODE_SMA, PRICE_CLOSE);
   if(MA_handle4 < 0)
     {
      Print("The creation of iMA has failed: MA_handle4=", INVALID_HANDLE);
      Print("Runtime error = ", GetLastError());
      return(INIT_FAILED);
     }
   
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime& time[],
                const double& open[],
                const double& high[],
                const double& low[],
                const double& close[],
                const long& tick_volume[],
                const long& volume[],
                const int& spread[])
  {
   int limit = rates_total - prev_calculated;
   //--- counting from 0 to rates_total
   ArraySetAsSeries(Buffer1, true);
   ArraySetAsSeries(Buffer2, true);
   //--- initial zero
   if(prev_calculated < 1)
     {
      ArrayInitialize(Buffer1, EMPTY_VALUE);
      ArrayInitialize(Buffer2, EMPTY_VALUE);
     }
   else
      limit++;
   
   datetime TimeShift[];
   if(CopyTime(Symbol(), PERIOD_CURRENT, 0, rates_total, TimeShift) <= 0) return(rates_total);
   ArraySetAsSeries(TimeShift, true);
   int barshift_M1[];
   ArrayResize(barshift_M1, rates_total);
   int barshift_D1[];
   ArrayResize(barshift_D1, rates_total);
   for(int i = 0; i < rates_total; i++)
     {
      barshift_M1[i] = iBarShift(Symbol(), PERIOD_M1, TimeShift[i]);
      barshift_D1[i] = iBarShift(Symbol(), PERIOD_D1, TimeShift[i]);
   }
   if(BarsCalculated(MA_handle) <= 0) 
      return(0);
   if(CopyBuffer(MA_handle, 0, 0, rates_total, MA) <= 0) return(rates_total);
   ArraySetAsSeries(MA, true);
   if(BarsCalculated(MA_handle2) <= 0) 
      return(0);
   if(CopyBuffer(MA_handle2, 0, 0, rates_total, MA2) <= 0) return(rates_total);
   ArraySetAsSeries(MA2, true);
   if(CopyOpen(Symbol(), PERIOD_M1, 0, rates_total, Open) <= 0) return(rates_total);
   ArraySetAsSeries(Open, true);
   if(CopyClose(Symbol(), PERIOD_D1, 0, rates_total, Close) <= 0) return(rates_total);
   ArraySetAsSeries(Close, true);
   if(BarsCalculated(MA_handle3) <= 0) 
      return(0);
   if(CopyBuffer(MA_handle3, 0, 0, rates_total, MA3) <= 0) return(rates_total);
   ArraySetAsSeries(MA3, true);
   if(BarsCalculated(MA_handle4) <= 0) 
      return(0);
   if(CopyBuffer(MA_handle4, 0, 0, rates_total, MA4) <= 0) return(rates_total);
   ArraySetAsSeries(MA4, true);
   if(CopyLow(Symbol(), PERIOD_CURRENT, 0, rates_total, Low) <= 0) return(rates_total);
   ArraySetAsSeries(Low, true);
   if(CopyHigh(Symbol(), PERIOD_CURRENT, 0, rates_total, High) <= 0) return(rates_total);
   ArraySetAsSeries(High, true);
   //--- main loop
   for(int i = limit-1; i >= 0; i--)
     {
      if (i >= MathMin(PLOT_MAXIMUM_BARS_BACK-1, rates_total-1-OMIT_OLDEST_BARS)) continue; //omit some old rates to prevent "Array out of range" or slow calculation   
      
      if(barshift_M1[i] < 0 || barshift_M1[i] >= rates_total) continue;
      if(barshift_D1[i] < 0 || barshift_D1[i] >= rates_total) continue;
      
      //Indicator Buffer 1
      if(MA[i] > MA2[i]
      && MA[i+1] < MA2[i+1] //Moving Average crosses above Moving Average
      && Open[barshift_M1[i]] >= Close[1+barshift_D1[i]] //Candlestick Open >= Candlestick Close
      && MA3[i] > MA4[i] //Moving Average > Moving Average
      )
        {
         Buffer1[i] = Low[i]; //Set indicator value at Candlestick Low
        }
      else
        {
         Buffer1[i] = EMPTY_VALUE;
        }
      //Indicator Buffer 2
      if(MA[i] < MA2[i]
      && MA[i+1] > MA2[i+1] //Moving Average crosses below Moving Average
      && Open[barshift_M1[i]] <= Close[1+barshift_D1[i]] //Candlestick Open <= Candlestick Close
      && MA3[i] < MA4[i] //Moving Average < Moving Average
      )
        {
         Buffer2[i] = High[i]; //Set indicator value at Candlestick High
        }
      else
        {
         Buffer2[i] = EMPTY_VALUE;
        }
     }
   return(rates_total);
  }
//Thank you for following along this is ready to  compile


Изучение осциллятора RSI

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

Приведенная ниже формула RSI приписывается Джону Уэллсу Уайлдеру-младшему, который представил эту концепцию в 1978 году.

RSI = 100 - (100/(1+RS))

где:

  • RS = Average Gain / Average Loss
  • Average Gain = сумма прибыли за указанный период / количество периодов
  • Average Loss = сумма убытков за указанный период / количество периодов

RSI индекса Boom 500

Рис. 3. Уровни RSI, индекс Boom 500

Реализация RSI

Определение уровней RSI в коде и сопоставление их с основными трендами может быть очень полезным. В этом разделе мы добавим условия RSI в наш MQL5-индикатор. Это позволяет нам лучше анализировать рыночные тренды и принимать более обоснованные торговые решения. Совмещая уровни RSI с основными трендами, мы можем с большей точностью определять потенциальные точки входа и выхода, повышая эффективность нашей торговой стратегии. Раньше мы полагались на пересечение скользящих средних в качестве условия входа. Теперь мы убираем пересечение скользящих средних и вместо него используем уровни RSI для входа, а также другие недавно добавленные условия для создания новой версии Trend Constrain V1.02.

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

input double Oversold = 30;
input double Overbought = 70;
//I have set the default standard values, but you can alter them to suit your strategy and instrument being traded.

Реализуем условия RSI в нашем коде, чтобы улучшить функциональность индикатора. Начнем с определения уровней RSI, которые мы хотим использовать в индикаторе. Мы можем установить уровень перекупленности на уровне 70, а уровень перепроданности на уровне 30. Это поможет нам определить потенциальные точки разворота на рынке. Далее мы добавим в наш код необходимую логику для проверки условий RSI и генерации соответствующих сигналов. Это даст нам более полное представление о динамике рынка и поможет принимать более обоснованные торговые решения. Давайте приступим к внедрению этих изменений в наш MQL5-индикатор.

///Indicator Name: Trend Constraint
#property copyright "Clemence Benjamin"
#property link      "https://mql5.com"
#property version   "1.02"
#property description "A model that seek to produce sell signal when D1 candle is Bearish only and  buy signal when it is Bullish"

///--- indicator settings
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_plots 2

#property indicator_type1 DRAW_ARROW
#property indicator_width1 5
#property indicator_color1 0xFF3C00
#property indicator_label1 "Buy"

#property indicator_type2 DRAW_ARROW
#property indicator_width2 5
#property indicator_color2 0x0000FF
#property indicator_label2 "Sell"

#define PLOT_MAXIMUM_BARS_BACK 5000
#define OMIT_OLDEST_BARS 50

//--- indicator buffers
double Buffer1[];
double Buffer2[];

input double Oversold = 30;
input double Overbought = 70;
double myPoint; //initialized in OnInit
int RSI_handle;
double RSI[];
double Open[];
double Close[];
int MA_handle;
double MA[];
int MA_handle2;
double MA2[];
double Low[];
double High[];

void myAlert(string type, string message)
  {
   if(type == "print")
      Print(message);
   else if(type == "error")
     {
      Print(type+" | Trend Constraint V1.02 @ "+Symbol()+","+IntegerToString(Period())+" | "+message);
     }
   else if(type == "order")
     {
     }
   else if(type == "modify")
     {
     }
  }

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {   
   SetIndexBuffer(0, Buffer1);
   PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1));
   PlotIndexSetInteger(0, PLOT_ARROW, 241);
   SetIndexBuffer(1, Buffer2);
   PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE);
   PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1));
   PlotIndexSetInteger(1, PLOT_ARROW, 242);
   //initialize myPoint
   myPoint = Point();
   if(Digits() == 5 || Digits() == 3)
     {
      myPoint *= 10;
     }
   RSI_handle = iRSI(NULL, PERIOD_CURRENT, 14, PRICE_CLOSE);
   if(RSI_handle < 0)
     {
      Print("The creation of iRSI has failed: RSI_handle=", INVALID_HANDLE);
      Print("Runtime error = ", GetLastError());
      return(INIT_FAILED);
     }
   
   MA_handle = iMA(NULL, PERIOD_CURRENT, 7, 0, MODE_SMMA, PRICE_CLOSE);
   if(MA_handle < 0)
     {
      Print("The creation of iMA has failed: MA_handle=", INVALID_HANDLE);
      Print("Runtime error = ", GetLastError());
      return(INIT_FAILED);
     }
   
   MA_handle2 = iMA(NULL, PERIOD_CURRENT, 400, 0, MODE_SMA, PRICE_CLOSE);
   if(MA_handle2 < 0)
     {
      Print("The creation of iMA has failed: MA_handle2=", INVALID_HANDLE);
      Print("Runtime error = ", GetLastError());
      return(INIT_FAILED);
     }
   
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime& time[],
                const double& open[],
                const double& high[],
                const double& low[],
                const double& close[],
                const long& tick_volume[],
                const long& volume[],
                const int& spread[])
  {
   int limit = rates_total - prev_calculated;
   //--- counting from 0 to rates_total
   ArraySetAsSeries(Buffer1, true);
   ArraySetAsSeries(Buffer2, true);
   //--- initial zero
   if(prev_calculated < 1)
     {
      ArrayInitialize(Buffer1, EMPTY_VALUE);
      ArrayInitialize(Buffer2, EMPTY_VALUE);
     }
   else
      limit++;
   
   datetime TimeShift[];
   if(CopyTime(Symbol(), PERIOD_CURRENT, 0, rates_total, TimeShift) <= 0) return(rates_total);
   ArraySetAsSeries(TimeShift, true);
   int barshift_M1[];
   ArrayResize(barshift_M1, rates_total);
   int barshift_D1[];
   ArrayResize(barshift_D1, rates_total);
   for(int i = 0; i < rates_total; i++)
     {
      barshift_M1[i] = iBarShift(Symbol(), PERIOD_M1, TimeShift[i]);
      barshift_D1[i] = iBarShift(Symbol(), PERIOD_D1, TimeShift[i]);
   }
   if(BarsCalculated(RSI_handle) <= 0) 
      return(0);
   if(CopyBuffer(RSI_handle, 0, 0, rates_total, RSI) <= 0) return(rates_total);
   ArraySetAsSeries(RSI, true);
   if(CopyOpen(Symbol(), PERIOD_M1, 0, rates_total, Open) <= 0) return(rates_total);
   ArraySetAsSeries(Open, true);
   if(CopyClose(Symbol(), PERIOD_D1, 0, rates_total, Close) <= 0) return(rates_total);
   ArraySetAsSeries(Close, true);
   if(BarsCalculated(MA_handle) <= 0) 
      return(0);
   if(CopyBuffer(MA_handle, 0, 0, rates_total, MA) <= 0) return(rates_total);
   ArraySetAsSeries(MA, true);
   if(BarsCalculated(MA_handle2) <= 0) 
      return(0);
   if(CopyBuffer(MA_handle2, 0, 0, rates_total, MA2) <= 0) return(rates_total);
   ArraySetAsSeries(MA2, true);
   if(CopyLow(Symbol(), PERIOD_CURRENT, 0, rates_total, Low) <= 0) return(rates_total);
   ArraySetAsSeries(Low, true);
   if(CopyHigh(Symbol(), PERIOD_CURRENT, 0, rates_total, High) <= 0) return(rates_total);
   ArraySetAsSeries(High, true);
   //--- main loop
   for(int i = limit-1; i >= 0; i--)
     {
      if (i >= MathMin(PLOT_MAXIMUM_BARS_BACK-1, rates_total-1-OMIT_OLDEST_BARS)) continue; //omit some old rates to prevent "Array out of range" or slow calculation   
      
      if(barshift_M1[i] < 0 || barshift_M1[i] >= rates_total) continue;
      if(barshift_D1[i] < 0 || barshift_D1[i] >= rates_total) continue;
      
      //Indicator Buffer 1
      if(RSI[i] < Oversold
      && RSI[i+1] > Oversold //Relative Strength Index crosses below fixed value
      && Open[barshift_M1[i]] >= Close[1+barshift_D1[i]] //Candlestick Open >= Candlestick Close
      && MA[i] > MA2[i] //Moving Average > Moving Average
      )
        {
         Buffer1[i] = Low[i]; //Set indicator value at Candlestick Low
        }
      else
        {
         Buffer1[i] = EMPTY_VALUE;
        }
      //Indicator Buffer 2
      if(RSI[i] > Overbought
      && RSI[i+1] < Overbought //Relative Strength Index crosses above fixed value
      && Open[barshift_M1[i]] <= Close[1+barshift_D1[i]] //Candlestick Open <= Candlestick Close
      && MA[i] < MA2[i] //Moving Average < Moving Average
      )
        {
         Buffer2[i] = High[i]; //Set indicator value at Candlestick High
        }
      else
        {
         Buffer2[i] = EMPTY_VALUE;
        }
     }
   return(rates_total);
  }
// Thank you for following along we are here


Сравнение результатов

В предыдущей статье, мы добились значительного прогресса в создании наглядной диаграммы с количеством представленных сигналов. RSI и скользящие средние оказали положительное влияние на наши результаты, выступая в качестве визуальных индикаторов для отслеживания изменений тренда. Наш индикатор ограничения тренда по свечам на более высоком таймфрейме также продемонстрировал улучшение. Кроме того, включение индикатора SMA 400 дало дополнительные сведения о возможных разворотах рынка, повысив общую точность анализа. Объединяя эти различные сигналы, мы лучше подготовлены к принятию обоснованных торговых решений и адаптации к меняющимся рыночным условиям. Я воодушевлен достигнутым прогрессом и намерен совершенствовать эту стратегию для достижения еще лучших результатов в будущем.

Индекс Boom 500, Smart Chart

Рис. 4. Trend Constraint v1.02, индекс Boom 500

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

Boom 500 индекс Trend Constraint V1.02

Рис. 5. Trend Constraint v1.02, индекс Boom 500


Заключение

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

Учебник по алготрейдингу


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

Прикрепленные файлы |
Последние комментарии | Перейти к обсуждению на форуме трейдеров (2)
Taque Matumbah
Taque Matumbah | 19 мая 2024 в 00:23
Глубоко!
Clemence Benjamin
Clemence Benjamin | 20 мая 2024 в 08:19
Taque Matumbah #:
Глубоко!

Спасибо. Надеюсь, вы нашли это полезным.

Торговля на разрывах справедливой стоимости (FVG)/дисбалансах шаг за шагом: Подход Smart Money Торговля на разрывах справедливой стоимости (FVG)/дисбалансах шаг за шагом: Подход Smart Money
Пошаговое руководство по созданию и реализации автоматизированного торгового алгоритма на основе разрывов справедливой стоимости (Fair Value Gap, FVG) на языке MQL5. Подробное руководство может быть полезно как новичкам, так и опытным трейдерам.
Пользовательские индикаторы (Часть 1): Пошаговое руководство по разработке простых индикаторов на MQL5 Пользовательские индикаторы (Часть 1): Пошаговое руководство по разработке простых индикаторов на MQL5
В этой статье рассказывается о том, как писать пользовательские индикаторы на языке MQL5. Это вводная часть, в которой вы познакомитесь с основами создания простых пользовательских индикаторов. В ней продемонстрирован практический подход к программированию различных пользовательских индикаторов. Материал предназначен для тех, кто еще в начал пути по изучению программирования на MQL5.
Алгоритм выбора признаков с использованием энергетического обучения на чистом MQL5 Алгоритм выбора признаков с использованием энергетического обучения на чистом MQL5
Статья представляет реализацию алгоритма выбора признаков, описанного в научной работе "FREL: Стабильный алгоритм выбора признаков" (FREL: A stable feature selection algorithm). Сам алгоритм называется "Взвешивание признаков как регуляризованное обучение на основе энергии" (Feature weighting as regularized energy based learning).
Нейросети в трейдинге: Изучение локальной структуры данных Нейросети в трейдинге: Изучение локальной структуры данных
Эффективное выявление и сохранение локальной структуры рыночных данных в условиях шума является важной задачей в трейдинге. Использование механизма Self-Attention показало хорошие результаты в обработке подобных данных, но классический метод не учитывают локальные особенности исходной структуры. В данной статье я предлагаю познакомиться с алгоритмом, способным учитывать эти структурные зависимости.