English 中文 Español Deutsch 日本語 Português
preview
Поиск свечных паттернов с помощью MQL5

Поиск свечных паттернов с помощью MQL5

MetaTrader 5Трейдинг | 12 мая 2023, 16:24
2 777 10
Mohamed Abdelmaaboud
Mohamed Abdelmaaboud

Введение

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

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

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

Паттерны из одиночной свечи

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

Свеча Доджи:

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

Доджи

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

Что нам нужно сделать, так это сделать так, чтобы программа сама обнаруживала паттерн Доджи, определяя цены и время последней свечи на каждом тике и сравнивая эти значения для определения формации. Если цена открытия равна цене закрытия, программа должна вернуть сигнал о том, что это паттерн свечи Доджи.

Давайте посмотрим, как создать программу, которая сможет находить такой паттерн. Рассмотрим этот процесс по шагам:

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

void OnTick()
  {
   getDoji();
  }

Создаем функцию (getDoji), у нас будет переменная integer.

int getDoji()

Определяем функцию путем определения времени, цен открытия, максимума, минимума и закрытия последней свечи.

Для этого используем функции iTime, которая возвращает время открытия свечи, iOpen, которая возвращает цену открытия свечи, iHigh, которая возвращает максимальную цену, iLow, которая возвращает минимальную цену, и iClose, которая возвращает цену закрытия свечи. Параметры у всех одинаковые:

  • symbol — имя символа; у нас это "_Symbol", то есть рассчитываем индикатор по символу текущего графика.
  • timeframe — таймфрейм для расчетов, мы укажем PERIOD_CURRENT, чтобы работать на таймфрейме текущего графика.
  • shift — индекс свечи, для которой будем возвращать значения, используем 1 — последняя сформированная свеча.
   datetime time=iTime(_Symbol,PERIOD_CURRENT,1);
   double open=iOpen(_Symbol,PERIOD_CURRENT,1);
   double high=iHigh(_Symbol,PERIOD_CURRENT,1);
   double low=iLow(_Symbol,PERIOD_CURRENT,1);
   double close=iClose(_Symbol,PERIOD_CURRENT,1);

Определим условия для поиска доджи с помощью оператора if

if(open==close)

Если это условие выполняется, наша программа будет создавать объект на основе функции createObj. Для создания объекта будем использовать определенные параметры времени, цены, кода стрелки, цвета и текста. Завершим функцию и вернем 1.

   if(open==close)
     {
      createObj(time,low,217, clrBlack,"Doji");
        {
         return 1;
        }
     }

Для завершения функции getDoji возвращать будем 0

   return 0;

Добавляем функцию createObj с параметрами time, price, arrowcode, clr и txt с помощью функции void

void createObj(datetime time, double price, int arrawCode, color clr, string txt)

Создаем строковую переменную objName и присвоим ей значение " "

string objName=" ";

Объединяем строки для присвоения их переменной objName с помощью функции StringConcatenate, которая формирует строку переданных параметров и возвращает размер сформированной строки. Параметры функции:

  • string_var — строку, которая будет сформирована после конкатенации (objName).
  • argument1 — параметр простого типа, мы укажем текст "Signal at  ", чтобы отобразить сигнал.
  • argument2 — аргумент определяет время найденной свечи, у нас это время из предопределенной переменной.
  • argument3 — третьим добавим текст " at ".
  • argument4 — далее добавим в текст округленную цену с помощью DoubleToString, которая преобразует значение double в строку.
  • argument5 — снова добавим текст " (".
  • argument6 — присвоим значение предопределенной целочисленной переменной (arrowcode). Коды можно найти по поиску Wingdings в справочнике mql5.
  • argument7 — завершим текст ")".
StringConcatenate(objName, "Signal at ",time, " at ",DoubleToString(price,_Digits)," (",arrawCode,")");

Далее добавляем условие для определения паттерна с помощью оператора if и функцию ObjectCreate в качестве выражения. Функция ObjectCreate создает объект, используя предопределенное имя objName. Ее параметры:

  • chart_id — определяем график, используем 0 для текущего графика.
  • name — имя объекта, используем предопределенное objName.
  • type — тип объекта, у нас это OBJ_ARROW.
  • nwin — номер подокна графика, в котором будем работать, 0 — главное окно графика.
  • time1 — время привязки, используем предопределенную переменную time.
  • price1 — цена привязки, используем предопределенную переменную price.
if(ObjectCreate(0,objName,OBJ_ARROW,0,time,price))

Если это условие выполнено, создаем объект. Для этого нужно установить его свойства, форму, определить код стрелки и ее цвет с помощью функции ObjectSetInteger, которая и устанавливает значение свойства объекта. Параметры функции:

  • chart_id — определяем график, используем 0 для текущего графика.
  • name — имя объекта, используем предопределенное objName.
  • prop_id — идентификатор свойства объекта, используем значение из перечисления ENUM_OBJECT_PROPERTY_INTEGER: OBJPROP_ARROWCODE для выбора вида объекта и OBJPROP_COLOR для цвета.
  • prop_value — значение свойства, arrawCode для кода стрелки и предопределенную переменную (clr) для цвета.
ObjectSetInteger(0,objName,OBJPROP_ARROWCODE,arrawCode);
ObjectSetInteger(0,objName,OBJPROP_COLOR,clr);

После этого создадим текст, который будет показывать информацию о свече. Создадим переменную типа string candleName с присвоением предопределенных переменных objName и txt.

string candleName=objName+txt;

Создаем текстовый объект, используем оператор if и функцию ObjectCreate в качестве выражения, а оператором будет ObjectSetString для установки строкового значения свойства объекта и ObjectSetInteger для установки цвета текстового объекта.

      ObjectSetString(0,candleName,OBJPROP_TEXT," "+txt);
      ObjectSetInteger(0,candleName,OBJPROP_COLOR,clr);

Давайте теперь взглянем на то, что получилось. Полный код советника выглядит так:

//+------------------------------------------------------------------+
//|                                        Doji pattern detector.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
void OnTick()
  {
   getDoji();
  }
int getDoji()
  {
   datetime time=iTime(_Symbol,PERIOD_CURRENT,1);
   double open=iOpen(_Symbol,PERIOD_CURRENT,1);
   double high=iHigh(_Symbol,PERIOD_CURRENT,1);
   double low=iLow(_Symbol,PERIOD_CURRENT,1);
   double close=iClose(_Symbol,PERIOD_CURRENT,1);
//Doji
   if(open==close)
     {
      createObj(time,low,217, clrBlack,"Doji");
        {
         return 1;
        }
     }
   return 0;
  }
void createObj(datetime time, double price, int arrawCode, color clr, string txt)
  {
   string objName=" ";
   StringConcatenate(objName, "Signal at ",time, " at ",DoubleToString(price,_Digits)," (",arrawCode,")");
   if(ObjectCreate(0,objName,OBJ_ARROW,0,time,price))
     {
      ObjectSetInteger(0,objName,OBJPROP_ARROWCODE,arrawCode);
      ObjectSetInteger(0,objName,OBJPROP_COLOR,clr);
     }
   string candleName=objName+txt;
   if(ObjectCreate(0,candleName,OBJ_TEXT,0,time,price))
     {
      ObjectSetString(0,candleName,OBJPROP_TEXT," "+txt);
      ObjectSetInteger(0,candleName,OBJPROP_COLOR,clr);
     }
  }

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

Пример Doji

Как видите, у нас есть объект с черной стрелкой под свечой и текст "Doji", определяющий паттерн свечи.

Паттерн "Молот"

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

  • Бычий молот

Бычий молот

Такой паттерн указывает на то, что продавец пытался толкнуть цену ниже, но покупатель контролирует рынок. Свеча закрывается выше открытия, что означает силу покупателя.

  • Медвежий молот

Медвежий молот

Данная модель указывает на то, что продавец пытался толкнуть цену ниже, а покупатель закрылся около цены открытия, что означает. что покупатель все еще в игре.

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

  • Бычий перевернутый молот

Бычий перевернутый молот

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

  • Медвежий перевернутый молот

Медвежий перевернутый молот

Такой паттерн указывает на то, что покупатель пытался толкнуть цену ниже, но продавец контролирует рынок. Свеча закрывается ниже открытия, что означает силу продавца.

Этот паттерн, как и все свечные модели, будет более значимым в сочетании с другими техническими инструментами. 

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

Полный код программы выглядит так:

//+------------------------------------------------------------------+
//|                                      Hammer pattern detector.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
void OnTick()
  {
   getHammer(0.07,0.7);
  }
int getHammer(double smallShadowRatio, double longShadowRatio)
  {
   datetime time=iTime(_Symbol,PERIOD_CURRENT,1);
   double open=iOpen(_Symbol,PERIOD_CURRENT,1);
   double high=iHigh(_Symbol,PERIOD_CURRENT,1);
   double low=iLow(_Symbol,PERIOD_CURRENT,1);
   double close=iClose(_Symbol,PERIOD_CURRENT,1);
   double candleSize=high-low;
   if(open<close)
     {
      if(high-close < candleSize*smallShadowRatio)
        {
         if(open-low>candleSize*longShadowRatio)
            createObj(time,low,217, clrGreen,"Hammer");
           {
            return 1;
           }
        }
     }
   if(open>close)
     {
      if(high-open<candleSize*smallShadowRatio)
        {
         if(close-low>candleSize*longShadowRatio)
            createObj(time,high,218,clrRed,"Hammer");
           {
            return 1;
           }
        }
     }
   if(open<close)
     {
      if(open-low < candleSize*smallShadowRatio)
        {
         if(high-close>candleSize*longShadowRatio)
            createObj(time,low,217, clrGreen,"Inverted Hammer");
           {
            return -1;
           }
        }
     }
   if(open>close)
     {
      if(close-low < candleSize*smallShadowRatio)
        {
         if(high-open>candleSize*longShadowRatio)
            createObj(time,high,218, clrRed,"Inverted Hammer");
           {
            return -1;
           }
        }
     }
   return 0;
  }
void createObj(datetime time, double price, int arrawCode, color clr, string txt)
  {
   string objName=" ";
   StringConcatenate(objName, "Signal@",time, "at",DoubleToString(price,_Digits),"(",arrawCode,")");
   if(ObjectCreate(0,objName,OBJ_ARROW,0,time,price))
     {
      ObjectSetInteger(0,objName,OBJPROP_ARROWCODE,arrawCode);
      ObjectSetInteger(0,objName,OBJPROP_COLOR,clr);
      if(clr==clrGreen)
         ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_TOP);
      if(clr==clrRed)
         ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_BOTTOM);
     }
   string candleName=objName+txt;
   if(ObjectCreate(0,candleName,OBJ_TEXT,0,time,price))
     {
      ObjectSetString(0,candleName,OBJPROP_TEXT," "+txt);
      ObjectSetInteger(0,candleName,OBJPROP_COLOR,clr);
     }
  }

Какие отличия появились в этом коде:

Здесь мы вызываем функцию getHammer в OnTick() с определением нужных параметров smallShadowRatio и longShadowRatio.

void OnTick()
  {
   getHammer(0.07,0.7);
  }

Создаем функцию getHammer с параметрами двух переменных типа double smallShadowRatio и longShadowRatio

int getHammer(double smallShadowRatio, double longShadowRatio)

Создаем double-переменную для размера свечи candleSize, которая будет использоваться для сравнения

double candleSize=high-low;

Условия паттерна "Молот":

В случае бычьего молота (открытие меньше закрытия), последняя свеча должна быть бычьей, верхняя тень свечи (максимум-закрытие) меньше соотношения короткой тени (0.07), а нижняя тень (открытие-минимум) выше соотношения длинной тени (0.7). Создаем зеленую стрелку с кодом 217 из Wingdings и текстовым объектом с надписью "Hammer" на графике под минимумом свечи молота и завершаем функцию.

   if(open<close)
     {
      if(high-close < candleSize*smallShadowRatio)
        {
         if(open-low>candleSize*longShadowRatio)
            createObj(time,low,217, clrGreen,"Hammer");
           {
            return 1;
           }
        }
     }

В случае медвежьего молота (открытие выше закрытия), последняя свеча должна быть медвежьей, верхняя тень свечи (максимум-открытие) меньше соотношения короткой тени (0.07), а нижняя тень (закрытие-минимум) больше соотношения длинной тени (0.7). Рисуем красную стрелку с кодом 218 из Wingdings и текстовым объектом с надписью "Hammer" на графике над максимумом свечи молота и завершаем функцию.

   if(open>close)
     {
      if(high-open<candleSize*smallShadowRatio)
        {
         if(close-low>candleSize*longShadowRatio)
            createObj(time,high,218,clrRed,"Hammer");
           {
            return 1;
           }
        }
     }

В случае бычьего перевернутого молота (открытие ниже закрытия), последняя свеча должна быть бычьей, нижняя тень свечи (открытие-минимум) меньше соотношения короткой тени (0.07), а верхняя тень (максимум-закрытие) выше соотношения длинной тени (0.7). Рисуем зеленую стрелку с кодом 217 из Wingdings и текстовым объектом с надписью "Inverted Hammer" на графике под минимумом свечи молота и завершаем функцию.

   if(open<close)
     {
      if(open-low < candleSize*smallShadowRatio)
        {
         if(high-close>candleSize*longShadowRatio)
            createObj(time,low,217, clrGreen,"Inverted Hammer");
           {
            return -1;
           }
        }
     }

В случае медвежьего перевернутого молота (открытие выше закрытия), последняя свеча должна быть медвежьей, нижняя тень свечи (закрытие-минимум) меньше соотношения короткой тени (0.07), а верхняя тень (максимум-открытие) выше соотношения длинной тени (0.7). Рисуем красную стрелку с кодом 218 из Wingdings и текстовым объектом с надписью "Inverted Hammer" на графике над максимумом свечи молота и завершаем функцию.

   if(open>close)
     {
      if(close-low < candleSize*smallShadowRatio)
        {
         if(high-open>candleSize*longShadowRatio)
            createObj(time,high,218, clrRed,"Inverted Hammer");
           {
            return -1;
           }
        }
     }

Редактируем положение стрелки и ее цвета в зависимости от типа свечи с помощью оператора (if), выражение будет цветом, а оператор, если он истинен, будет положением стрелки через функцию ObjectSetInteger.

Если под свечой зеленая стрелка

      if(clr==clrGreen)
         ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_TOP);

Если над свечой красная

      if(clr==clrRed)
         ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_BOTTOM);

Компилируем код советника, и он появляется в окне Навигатора в терминале, откуда запускаем его на графике. Ниже показан пример работы::

  • Бычий молот:

Пример бычьего молота

Как видите, у нас есть зеленая стрелка и зеленый текстовый объект "Hammer" на графике ниже минимума бычьего молота.

  • Медвежий молот:

Пример медвежьего молота

Здесь отображена красная стрелка и красный текстовый объект "Hammer" на графике выше максимума медвежьего молота.

  • Бычий перевернутый молот:

Пример бычьего перевернутого молота

На графике показана зеленая стрелка и зеленый текстовый объект "Inverted Hammer" ниже минимума паттерна бычьего молота.

  • Медвежий перевернутый молот:

Пример медвежьего перевернутого молота

Красная стрелка и красный текстовый объект "Inverted Hammer" добавлены на графике выше максимума медвежьего молота.

Паттерны из двух свечей

В этой части мы увидим другой тип свечных паттернов — паттерны, состоящие из двух свечей. Рассмотрим два популярных паттерна: "Поглощение" (бычье и медвежье), а также бычий "Просвет в облаках" и противоположный ей медвежий паттерн "Завеса из темных облаков".

Паттерн "Поглощение":

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

Тип свечи поглощения зависит от цвета и направления свечи:

  • Бычье поглощение:

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

Бычье поглощение

Может указывать на то, что покупатель контролирует рынок и цена может продолжить рост после такой свечи.

  • Медвежье поглощение:

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

Медвежье поглощение

Может указывать на то, что продавец контролирует рынок и цена может продолжить снижение после такой свечи.

Теперь создадим программу для автоматического поиска этого паттерна. Нам нужно определить время последней свечи и цены последних двух свечей. Для этого на каждом тике будем проверять эти значения и определять позиции свечей относительно друг друга. На основе этого будем определять наличие необходимого типа паттерна поглощения. Есть паттерн поглощения найден, будем выводить на график определенный сигнал, который представляет собой цветную стрелку и текстовый объект в зависимости от типа паттерна (бычий или медвежий).

Ниже приведен полный код для создания этой программы:

//+------------------------------------------------------------------+
//|                                   Engulfing pattern detector.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
void OnTick()
  {
   getEngulfing();
  }
int getEngulfing()
  {
   datetime time=iTime(_Symbol,PERIOD_CURRENT,1);
   double open=iOpen(_Symbol,PERIOD_CURRENT,1);
   double high=iHigh(_Symbol,PERIOD_CURRENT,1);
   double low=iLow(_Symbol,PERIOD_CURRENT,1);
   double close=iClose(_Symbol,PERIOD_CURRENT,1);
   double open2=iOpen(_Symbol,PERIOD_CURRENT,2);
   double high2=iHigh(_Symbol,PERIOD_CURRENT,2);
   double low2=iLow(_Symbol,PERIOD_CURRENT,2);
   double close2=iClose(_Symbol,PERIOD_CURRENT,2);
   if(open<close)
     {
      if(open2>close2)
        {
         if(high>high2&&low<low2)
           {
            if(close>open2&&open<close2)
              {
               createObj(time,low,217, clrGreen,"Bullish Engulfing");
                 {
                  return 1;
                 }
              }
           }
        }
     }
   if(open>close)
     {
      if(open2<close2)
        {
         if(high>high2&&low<low2)
           {
            if(close<open2&&open>close2)
              {
               createObj(time,high,218, clrRed,"Bearish Engulfing");
                 {
                  return -1;
                 }
              }
           }
        }
     }
   return 0;
  }
void createObj(datetime time, double price, int arrawCode, color clr, string txt)
  {
   string objName=" ";
   StringConcatenate(objName, "Signal@",time, "at",DoubleToString(price,_Digits),"(",arrawCode,")");
   if(ObjectCreate(0,objName,OBJ_ARROW,0,time,price))
     {
      ObjectSetInteger(0,objName,OBJPROP_ARROWCODE,arrawCode);
      ObjectSetInteger(0,objName,OBJPROP_COLOR,clr);
      if(clr==clrGreen)
         ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_TOP);
      if(clr==clrRed)
         ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_BOTTOM);
     }
   string candleName=objName+txt;
   if(ObjectCreate(0,candleName,OBJ_TEXT,0,time,price))
     {
      ObjectSetString(0,candleName,OBJPROP_TEXT," "+txt);
      ObjectSetInteger(0,candleName,OBJPROP_COLOR,clr);
     }
  }

Отличия в этом коде:

Создаем doule-переменные для времени последней свечи и цены последних двух свечей для использования в функции getEngulfing. Параметры time, open, high, low и close используются для последней свечи, а open2, high2, low2 и close2 — для предпоследней.

   datetime time=iTime(_Symbol,PERIOD_CURRENT,1);
   double open=iOpen(_Symbol,PERIOD_CURRENT,1);
   double high=iHigh(_Symbol,PERIOD_CURRENT,1);
   double low=iLow(_Symbol,PERIOD_CURRENT,1);
   double close=iClose(_Symbol,PERIOD_CURRENT,1);
   double open2=iOpen(_Symbol,PERIOD_CURRENT,2);
   double high2=iHigh(_Symbol,PERIOD_CURRENT,2);
   double low2=iLow(_Symbol,PERIOD_CURRENT,2);
   double close2=iClose(_Symbol,PERIOD_CURRENT,2);

Условия для определения этого типа свечного паттерна

В случае бычьего поглощения последняя свеча является бычьей (open < close), предпоследняя должна быть медвежьей (open2 > close2), максимум последней (high) больше максимума предпоследней (high2), а минимум последней (low) ниже минимума предпоследней (low2). Кроме того, закрытие последней (close) выше открытия предпоследней (open2), а открытие предпоследней (open) ниже закрытия предпоследней (close2). После определения такой свечи создаем объект на основе созданной функции (createObj) со следующими параметрами:

  • time — время последней свечи, предопределенная переменной.
  • price — минимум последней свечи, под которой будет отражаться наш объект.
  • arrowCode — стрелка с кодом 217 Wingdings.
  • clr — цвет clrGreen.
  • txt — текст "Bullish Engulfing".

Завершаем функцию.

   if(open<close)
     {
      if(open2>close2)
        {
         if(high>high2&&low<low2)
           {
            if(close>open2&&open<close2)
              {
               createObj(time,low,217, clrGreen,"Bullish Engulfing");
                 {
                  return 1;
                 }
              }
           }
        }
     }

В случае медвежьего поглощения последняя свеча является медвежьей (open > close), предпоследняя — бычьей (open2 < close2), high выше high2, low ниже low2, close ниже open2, а open выше close2. После определения такой свечи создаем объект на основе созданной функции (createObj) со следующими параметрами:

  • time — время последней свечи, предопределенная переменной.
  • price — максимум последней свечи, над которой будет отражаться наш объект.
  • arrowCode — стрелка с кодом 218 Wingdings.
  • clr — цвет clrRed.
  • txt — текст "Bearish Engulfing".

Завершаем функцию.

   if(open>close)
     {
      if(open2<close2)
        {
         if(high>high2&&low<low2)
           {
            if(close<open2&&open>close2)
              {
               createObj(time,high,218, clrRed,"Bearish Engulfing");
                 {
                  return -1;
                 }
              }
           }
        }
     }

Компилируем код советника, и он появляется в окне Навигатора в терминале, откуда запускаем его на графике. Ниже показан пример работы:

  • Бычье поглощение:

Пример бычьего поглощения

На графике у нас есть зеленая стрелка и текст "Bullish Engulfing" ниже минимума последней свечи в паттерне.

  • Медвежье поглощение:

Пример медвежьего поглощения

На графике видим красную стрелку и подпись "Bearish Engulfing" над максимумом последней свечи в паттерне.

Просвет в облаках / Завеса из темных облаков

  • Паттерн "Просвет в облаках"

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

Piercing line (Просвет в облаках)

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

  • Завеса из темных облаков

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

Завеса из темных облаков

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

Теперь создадим программу для автоматического поиска этого паттерна. Для этого проверяем время и цены первой свечи (time, open, high, low и close) и цены второй свечи (open2, high2, low2 и close2), размер первой (candleSize2) и середину второй (candleMidPoint2). Программа будет постоянно проверять эти значения и определять их положение относительно друг друга. Будем возвращать определенный сигнал на основе определенных условий, основанных на бычьем или медвежьем настроении.

Ниже приведен полный код для создания этой программы:

//+------------------------------------------------------------------+
//|                      Piercing && Dark Cloud pattern detector.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
void OnTick()
  {
   getPiercing();  
  }
int getPiercing()
  {
   datetime time=iTime(_Symbol,PERIOD_CURRENT,1);
   double open=iOpen(_Symbol,PERIOD_CURRENT,1);
   double high=iHigh(_Symbol,PERIOD_CURRENT,1);
   double low=iLow(_Symbol,PERIOD_CURRENT,1);
   double close=iClose(_Symbol,PERIOD_CURRENT,1);
   double open2=iOpen(_Symbol,PERIOD_CURRENT,2);
   double high2=iHigh(_Symbol,PERIOD_CURRENT,2);
   double low2=iLow(_Symbol,PERIOD_CURRENT,2);
   double close2=iClose(_Symbol,PERIOD_CURRENT,2);
   double candleSize2=high2-low2;
   double candleMidPoint2=high2-(candleSize2/2);
   if(open<close)
     {
      if(open2>close2)
        {
         if(open<low2)
           {
            if(close>candleMidPoint2&&close<high2)
              {
               createObj(time,low,217, clrGreen,"Piercing");
                 {
                  return 1;
                 }
              }
           }
        }
     }
   if(open>close)
     {
      if(open2<close2)
        {
         if(open>high2)
           {
            if(close<candleMidPoint2&&close>low2)
              {
               createObj(time,high,218, clrRed,"Dark Cloud");
                 {
                  return -1;
                 }
              }
           }
        }
     }
   return 0;
  }
void createObj(datetime time, double price, int arrawCode, color clr, string txt)
  {
   string objName=" ";
   StringConcatenate(objName, "Signal@",time, "at",DoubleToString(price,_Digits),"(",arrawCode,")");
   if(ObjectCreate(0,objName,OBJ_ARROW,0,time,price))
     {
      ObjectSetInteger(0,objName,OBJPROP_ARROWCODE,arrawCode);
      ObjectSetInteger(0,objName,OBJPROP_COLOR,clr);
      if(clr==clrGreen)
         ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_TOP);
      if(clr==clrRed)
         ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_BOTTOM);
     }
   string candleName=objName+txt;
   if(ObjectCreate(0,candleName,OBJ_TEXT,0,time,price))
     {
      ObjectSetString(0,candleName,OBJPROP_TEXT," "+txt);
      ObjectSetInteger(0,candleName,OBJPROP_COLOR,clr);
     }
  }

Что добавилось в этом коде

Определение CandleSize2 и CandleMidPoint2

   double candleSize2=high2-low2;
   double candleMidPoint2=high2-(candleSize2/2);

Условия паттерна

В случае паттерна "Просвет в облаках"

Если последняя свеча бычья (open < close), и при этом open2 выше close2, open ниже low2, а close выше candleMidPoint2, и при этом close ниже high2, будем рисовать на графике зеленую стрелку с надписью "Piercing" ниже минимума паттерна, после чего завершаем функцию.

   if(open<close)
     {
      if(open2>close2)
        {
         if(open<low2)
           {
            if(close>candleMidPoint2&&close<high2)
              {
               createObj(time,low,217, clrGreen,"Piercing");
                 {
                  return 1;
                 }
              }
           }
        }
     }

В случае паттерна "Завеса темных облаков":

Если последняя свеча медвежья (открытие выше закрытия), а open2 ниже, чем close2, open больше, чем high2, и close ниже, чем CandleMidPoint2, и при этом close выше, чем low2, на графике будем рисовать объект в виде красной стрелки с текстом "Dark Cloud" над максимумом паттерна, затем завершаем работу функции.

   if(open>close)
     {
      if(open2<close2)
        {
         if(open>high2)
           {
            if(close<candleMidPoint2&&close>low2)
              {
               createObj(time,high,218, clrRed,"Dark Cloud");
                 {
                  return -1;
                 }
              }
           }
        }
     }

Компилируем код советника, и он появляется в окне Навигатора в терминале, откуда запускаем его на графике. Ниже показан пример работы:

  • Паттерн "Просвет в облаках"

Пример паттерна "Просвет в облаках"

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

  • Завеса из темных облаков

Пример паттерна Завеса из темных облаков

На графике теперь красная стрелка и текст "Dark Cloud" выше максимума паттерна, как мы и ожидали.

Паттерны из трех свечей

Давайте посмотрим на два примера смешанных паттернов, это паттерн "Звезда" (Утренняя и Вечерняя) и паттерн "Три изнутри" (вверх, вниз).

Паттерн Звезда

  • Утренняя звезда:

Это структура из трех свечей. Он состоит из маленькой свечой между двумя свечами, первая из которых является длинной медвежьей, а вторая – длинной бычьей. Такая свеча на графике:

Утренняя звезда

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

  • Паттерн Вечерняя звезда (Evening Star)
Это структура из трех свечей. Он состоит из маленькой свечой между двумя свечами, первая из которых является длинной бычьей, а вторая – длинной медвежьей. Такая свеча на графике:

Evening star (вечерняя звезда)

Такая модель указывает на переход силы от покупателей к продавцам: продавец контролирует рынок и толкает цену вниз после ралли под давлением покупателя.

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

Ниже приведен полный код для создания этой программы:

//+------------------------------------------------------------------+
//|                                        Star pattern detector.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
void OnTick()
  {
   getStar(0.5);
  }
int getStar(double middleCandleRatio)
  {
   datetime time=iTime(_Symbol,PERIOD_CURRENT,1);
   double open=iOpen(_Symbol,PERIOD_CURRENT,1);
   double high=iHigh(_Symbol,PERIOD_CURRENT,1);
   double low=iLow(_Symbol,PERIOD_CURRENT,1);
   double close=iClose(_Symbol,PERIOD_CURRENT,1);
   double open2=iOpen(_Symbol,PERIOD_CURRENT,2);
   double high2=iHigh(_Symbol,PERIOD_CURRENT,2);
   double low2=iLow(_Symbol,PERIOD_CURRENT,2);
   double close2=iClose(_Symbol,PERIOD_CURRENT,2);
   double open3=iOpen(_Symbol,PERIOD_CURRENT,3);
   double high3=iHigh(_Symbol,PERIOD_CURRENT,3);
   double low3=iLow(_Symbol,PERIOD_CURRENT,3);
   double close3=iClose(_Symbol,PERIOD_CURRENT,3);
   double candleSize=high-low;
   double candleSize2=high2-low2;
   double candleSize3=high3-low3;
   if(open<close)
     {
      if(open3>close3)
        {
         if(candleSize2<candleSize*middleCandleRatio && candleSize2<candleSize3*middleCandleRatio)
           {
            createObj(time,low,217, clrGreen,"Morning Star");
              {
               return 1;
              }
           }
        }

     }
   if(open>close)
     {
      if(open3<close3)
        {
         if(candleSize2<candleSize*middleCandleRatio && candleSize2<candleSize3*middleCandleRatio)
           {
            createObj(time,high,218, clrRed,"Evening Star");
              {
               return -1;
              }
           }
        }

     }
   return 0;
  }
void createObj(datetime time, double price, int arrawCode, color clr, string txt)
  {
   string objName=" ";
   StringConcatenate(objName, "Signal@",time, "at",DoubleToString(price,_Digits),"(",arrawCode,")");
   if(ObjectCreate(0,objName,OBJ_ARROW,0,time,price))
     {
      ObjectSetInteger(0,objName,OBJPROP_ARROWCODE,arrawCode);
      ObjectSetInteger(0,objName,OBJPROP_COLOR,clr);
      if(clr==clrGreen)
         ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_TOP);
      if(clr==clrRed)
         ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_BOTTOM);
     }
   string candleName=objName+txt;
   if(ObjectCreate(0,candleName,OBJ_TEXT,0,time,price))
     {
      ObjectSetString(0,candleName,OBJPROP_TEXT," "+txt);
      ObjectSetInteger(0,candleName,OBJPROP_COLOR,clr);
     }
  }

Что добавилось в этом коде

Функция getStar с параметром middleCandleRatio

int getStar(double middleCandleRatio)

Переменные времени для последней свечи и ценовых данных (open, high, low, close) и размера свечи для последних трех свечей (candleSize, candleSize2 и candleSize3)

   datetime time=iTime(_Symbol,PERIOD_CURRENT,1);
   double open=iOpen(_Symbol,PERIOD_CURRENT,1);
   double high=iHigh(_Symbol,PERIOD_CURRENT,1);
   double low=iLow(_Symbol,PERIOD_CURRENT,1);
   double close=iClose(_Symbol,PERIOD_CURRENT,1);
   double open2=iOpen(_Symbol,PERIOD_CURRENT,2);
   double high2=iHigh(_Symbol,PERIOD_CURRENT,2);
   double low2=iLow(_Symbol,PERIOD_CURRENT,2);
   double close2=iClose(_Symbol,PERIOD_CURRENT,2);
   double open3=iOpen(_Symbol,PERIOD_CURRENT,3);
   double high3=iHigh(_Symbol,PERIOD_CURRENT,3);
   double low3=iLow(_Symbol,PERIOD_CURRENT,3);
   double close3=iClose(_Symbol,PERIOD_CURRENT,3);
   double candleSize=high-low;
   double candleSize2=high2-low2;
   double candleSize3=high3-low3;

Условия паттерна

В случае паттерна Утренняя звезда:

Если последняя свеча бычья (open < close), третья медвежья (open3 > close3), CandleSize2 меньше, чем значение middleCandleRatio от CandleSize, которое равно 0,5, и при этом CandleSize2 меньше, чем middleCandleRatio от CandleSize3, будем выводить объект зеленой стрелки и текст "Morning star" ниже минимума паттерна, а затем завершать функцию.

   if(open<close)
     {
      if(open3>close3)
        {
         if(candleSize2<candleSize*middleCandleRatio && candleSize2<candleSize3*middleCandleRatio)
           {
            createObj(time,low,217, clrGreen,"Morning Star");
              {
               return 1;
              }
           }
        }
     }

В случае с Вечерней звездой:

Если последняя свеча бычья (open > close), третья медвежья (open3 > close3), CandleSize2 меньше, чем значение middleCandleRatio от CandleSize, которое равно 0,5, и при этом CandleSize2 меньше, чем middleCandleRatio от CandleSize3, будем выводить красную стрелку и текст "Morning star" над максимумом паттерна, а затем завершать функцию.

   if(open>close)
     {
      if(open3<close3)
        {
         if(candleSize2<candleSize*middleCandleRatio && candleSize2<candleSize3*middleCandleRatio)
           {
            createObj(time,high,218, clrRed,"Evening Star");
              {
               return -1;
              }
           }
        }
     }

Компилируем код советника. После этого он появится в окне Навигатора в терминале, оттуда запускаем его на графике. Ниже показан пример работы:

  • Утренняя звезда:

Пример утренней звезды

Паттерн был обнаружен, и на графике отобразился нужный объект:

  • Вечерняя звезда:

Пример вечерней звезды

Паттерн был обнаружен, и на графике отобразился нужный объект:

В качестве примечания для паттерна Звезды: альтернативное формирование паттерна имеет разрыв со средней маленькой свечой, вы можете добавить это как дополнительное условие в код.

Паттерн "Три изнутри"

  • Три изнутри вверх:

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

Три изнутри вверх:

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

  • Три внутри вниз:

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

Три изнутри вниз

Паттерн указывает на потенциальное медвежье поведение со стороны продавца. Создадим программу для автоматического поиска этого паттерна. Будем определять время последней свечи и цены последних трех свечей. Для этого на каждом тике будем проверять эти значения и определять их положения относительно друг друга. На основе этого будем определять наличие необходимого типа паттерна. Код такой программы:
//+------------------------------------------------------------------+
//|                                Three inside pattern detector.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
void OnTick()
  {
   getthreeInside();
  }
int getthreeInside()
  {
   datetime time=iTime(_Symbol,PERIOD_CURRENT,1);
   double open=iOpen(_Symbol,PERIOD_CURRENT,1);
   double high=iHigh(_Symbol,PERIOD_CURRENT,1);
   double low=iLow(_Symbol,PERIOD_CURRENT,1);
   double close=iClose(_Symbol,PERIOD_CURRENT,1);
   double open2=iOpen(_Symbol,PERIOD_CURRENT,2);
   double high2=iHigh(_Symbol,PERIOD_CURRENT,2);
   double low2=iLow(_Symbol,PERIOD_CURRENT,2);
   double close2=iClose(_Symbol,PERIOD_CURRENT,2);
   double open3=iOpen(_Symbol,PERIOD_CURRENT,3);
   double high3=iHigh(_Symbol,PERIOD_CURRENT,3);
   double low3=iLow(_Symbol,PERIOD_CURRENT,3);
   double close3=iClose(_Symbol,PERIOD_CURRENT,3);
   if(open3>close3)
     {
      if(open2<close2)
        {
         if(open2>low3&&close2<high3)
           {
            if(open<close&&open>open2&&open<close2)
              {
               if(close>high3)
                 {
                  createObj(time,low,217, clrGreen,"3 Inside Up");
                    {
                     return 1;
                    }
                 }
              }
           }
        }

     }
   if(open3<close3)
     {
      if(open2>close2)
        {
         if(open2<high3&&close2>low3)
           {
            if(open>close&&open<open2&&open>close2)
              {
               if(close<low3)
                 {
                  createObj(time,high,218, clrRed,"3 Inside Down");
                    {
                     return -1;
                    }
                 }
              }
           }
        }
     }
   return 0;
  }
void createObj(datetime time, double price, int arrawCode, color clr, string txt)
  {
   string objName=" ";
   StringConcatenate(objName, "Signal@",time, "at",DoubleToString(price,_Digits),"(",arrawCode,")");
   if(ObjectCreate(0,objName,OBJ_ARROW,0,time,price))
     {
      ObjectSetInteger(0,objName,OBJPROP_ARROWCODE,arrawCode);
      ObjectSetInteger(0,objName,OBJPROP_COLOR,clr);
      if(clr==clrGreen)
         ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_TOP);
      if(clr==clrRed)
         ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_BOTTOM);
     }
   string candleName=objName+txt;
   if(ObjectCreate(0,candleName,OBJ_TEXT,0,time,price))
     {
      ObjectSetString(0,candleName,OBJPROP_TEXT," "+txt);
      ObjectSetInteger(0,candleName,OBJPROP_COLOR,clr);
     }
  }

Код отличается условиями паттерна

В случае «Три изнутри вверх»

   if(open3>close3)
     {
      if(open2<close2)
        {
         if(open2>low3&&close2<high3)
           {
            if(open<close&&open>open2&&open<close2)
              {
               if(close>high3)
                 {
                  createObj(time,low,217, clrGreen,"3 Inside Up");
                    {
                     return 1;
                    }
                 }
              }
           }
        }

     }

В случае «Три изнутри вниз»

   if(open3<close3)
     {
      if(open2>close2)
        {
         if(open2<high3&&close2>low3)
           {
            if(open>close&&open<open2&&open>close2)
              {
               if(close<low3)
                 {
                  createObj(time,high,218, clrRed,"3 Inside Down");
                    {
                     return -1;
                    }
                 }
              }
           }
        }
     }

Компилируем код советника, он появится в окне Навигатора в терминале, запускаем его на графике. Ниже показан пример работы:

  • Три изнутри вверх:

Пример Три изнутри вверх

Паттерн найден и показан на графике.

  • Три внутри вниз:

Пример Три изнутри вниз

Также здесь паттерн найден и показан на графике.

Заключение

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

  • Паттерны из одной свечи: как находить свечи Доджи и Молот.
  • Двойные свечные паттерны: научились находить паттерны "Поглощение", "Просвет в облаках" и "Завеса из темных облаков".
  • Паттерны из трех свечей: создали программы для поиска паттернов "Звезда" и "Три изнутри".

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

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

Последние комментарии | Перейти к обсуждению на форуме трейдеров (10)
Mohamed Abdelmaaboud
Mohamed Abdelmaaboud | 17 мая 2023 в 18:20
Спасибо за ваш комментарий. Сначала мне нужно уточнить, что вы можете сделать это так, как вам нужно, это может быть индикатор, который может обнаружить и показать их, или советник, который может дать вам необходимые действия, такие как торговля, если вы хотите, и вы можете объединить их в продвинутый советник. чтобы получить их все при правильном исполнении, которые будут прикреплены к графику как один советник. здесь нет правды или лжи, цель здесь только образовательная, чтобы поделиться тем, как мы можем кодировать эти типы моделей свечей, после чего вы можете использовать их в своей подходящей программе, будь то индикатор или советник.
FINANSE-BOND
FINANSE-BOND | 18 мая 2023 в 04:17
Mohamed Abdelmaaboud #:
Спасибо за ваш комментарий. Сначала мне нужно уточнить, что вы можете сделать это так, как вам нужно, это может быть индикатор, который может обнаружить и показать их, или советник, который может дать вам необходимые действия, такие как торговля, если вы хотите, и вы можете объединить их в продвинутый советник. чтобы получить их все при правильном исполнении, которые будут прикреплены к графику как один советник. здесь нет правды или лжи, цель здесь только образовательная, чтобы поделиться тем, как мы можем кодировать эти типы моделей свечей, после чего вы можете использовать их в своей подходящей программе, будь то индикатор или советник.

Я так и сделал, объединил все в один советник. Но когда попробовал записать как Индикатор, в терминале всё равно загружается как Советник. Что-то нужно менять в Коде, но что именно я не знаю, не сильно разбираюсь. Ещё я заметил, что нужна его доработка в плане, что когда меняется Тайм Фрейм, на другой то сигнал остаётся на графике и уже на новом не соответствует бару на том же месте. По идее при смене нужно, чтобы удалялся или сохранялся только на том Тайм Фрейме где он был обнаружен. На всякий случай выставлю собраный мой Код, посмотрите что можно подправить или оптимизировать, я всего лишь скопировал со всех советников в один, но думаю там можно объявить некоторые переменные в начале, чтобы не повторяться в Коде несколько раз.   

//+------------------------------------------------------------------+
//|                                                PATTERN-INDIK.mq5 |
//|                                            Copyright 2023,VIKTOR |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023,VIKTOR"
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//+ createObj1 = Doji                                                |
//+ createObj2 = Hammer                                              |
//+ createObj3 = Engulfing                                           |
//+ createObj4 = Piercing                                            |
//+ createObj5 = Star                                                |
//+ createObj6 = threeInside                                         |
//+------------------------------------------------------------------+
void OnTick()
  {
   getDoji();
   getHammer(0.07,0.7);
   getEngulfing();
   getPiercing();
   getStar(0.5);
   getthreeInside();
  }
int getDoji()
  {
   datetime time  =iTime  (_Symbol,PERIOD_CURRENT,1);
   double   open  =iOpen  (_Symbol,PERIOD_CURRENT,1);
   double   high  =iHigh  (_Symbol,PERIOD_CURRENT,1);
   double   low   =iLow   (_Symbol,PERIOD_CURRENT,1);
   double   close =iClose (_Symbol,PERIOD_CURRENT,1);
   
//Doji
   if(open==close)
     {
      createObj1a(time,low,217, clrBlack,"Doji");
        {
         return 1;
        }
     }
   return 0;
  }
void createObj1a(datetime time, double price, int arrawCode, color clr, string txt)
  {
   string objName=" ";
   StringConcatenate(objName, "Signal at ",time, " at ",DoubleToString(price,_Digits)," (",arrawCode,")");
   if(ObjectCreate(0,objName,OBJ_ARROW,0,time,price))
     {
      ObjectSetInteger(0,objName,OBJPROP_ARROWCODE,arrawCode);
      ObjectSetInteger(0,objName,OBJPROP_COLOR,clr);
     }
   string candleName=objName+txt;
   if(ObjectCreate(0,candleName,OBJ_TEXT,0,time,price))
     {
      ObjectSetString(0,candleName,OBJPROP_TEXT," "+txt);
      ObjectSetInteger(0,candleName,OBJPROP_COLOR,clr);
     }
  }
//+------------------------------------------------------------------+
int getHammer(double smallShadowRatio, double longShadowRatio)
  {
//creating variables for prices data - open,  high, low, close
   datetime time=iTime(_Symbol,PERIOD_CURRENT,1);
   double open=iOpen(_Symbol,PERIOD_CURRENT,1);
   double high=iHigh(_Symbol,PERIOD_CURRENT,1);
   double low=iLow(_Symbol,PERIOD_CURRENT,1);
   double close=iClose(_Symbol,PERIOD_CURRENT,1);
   double candleSize=high-low;
//green hammer
   if(open<close)
     {
      if(high-close < candleSize*smallShadowRatio)
        {
         if(open-low>candleSize*longShadowRatio)
            createObj2(time,low,217, clrGreen,"Hammer");
           {
            return 1;
           }
        }
     }
//red hammer
   if(open>close)
     {
      if(high-open<candleSize*smallShadowRatio)
        {
         if(close-low>candleSize*longShadowRatio)
            createObj2(time,high,218,clrRed,"Hammer");
           {
            return 1;
           }
        }
     }
//green inverse hammer
   if(open<close)
     {
      if(open-low < candleSize*smallShadowRatio)
        {
         if(high-close>candleSize*longShadowRatio)
            createObj2(time,low,217, clrGreen,"Inverted Hammer");
           {
            return -1;
           }
        }
     }
//red inverse hammer
   if(open>close)
     {
      if(close-low < candleSize*smallShadowRatio)
        {
         if(high-open>candleSize*longShadowRatio)
            createObj2(time,high,218, clrRed,"Inverted Hammer");
           {
            return -1;
           }
        }
     }
   return 0;
  }
void createObj2(datetime time, double price, int arrawCode, color clr, string txt)
  {
   string objName=" ";
   StringConcatenate(objName, "Signal@",time, "at",DoubleToString(price,_Digits),"(",arrawCode,")");
   if(ObjectCreate(0,objName,OBJ_ARROW,0,time,price))
     {
      ObjectSetInteger(0,objName,OBJPROP_ARROWCODE,arrawCode);
      ObjectSetInteger(0,objName,OBJPROP_COLOR,clr);
      if(clr==clrGreen)
         ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_TOP);
      if(clr==clrRed)
         ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_BOTTOM);
     }
   string candleName=objName+txt;
   if(ObjectCreate(0,candleName,OBJ_TEXT,0,time,price))
     {
      ObjectSetString(0,candleName,OBJPROP_TEXT," "+txt);
      ObjectSetInteger(0,candleName,OBJPROP_COLOR,clr);
     }
  }
//+------------------------------------------------------------------+
int getEngulfing()
  {
   datetime time=iTime(_Symbol,PERIOD_CURRENT,1);
   double open=iOpen(_Symbol,PERIOD_CURRENT,1);
   double high=iHigh(_Symbol,PERIOD_CURRENT,1);
   double low=iLow(_Symbol,PERIOD_CURRENT,1);
   double close=iClose(_Symbol,PERIOD_CURRENT,1);
   double open2=iOpen(_Symbol,PERIOD_CURRENT,2);
   double high2=iHigh(_Symbol,PERIOD_CURRENT,2);
   double low2=iLow(_Symbol,PERIOD_CURRENT,2);
   double close2=iClose(_Symbol,PERIOD_CURRENT,2);
   if(open<close)
     {
      if(open2>close2)
        {
         if(high>high2&&low<low2)
           {
            if(close>open2&&open<close2)
              {
               createObj3(time,low,217, clrGreen,"Bullish Engulfing");
                 {
                  return 1;
                 }
              }
           }
        }
     }
   if(open>close)
     {
      if(open2<close2)
        {
         if(high>high2&&low<low2)
           {
            if(close<open2&&open>close2)
              {
               createObj3(time,high,218, clrRed,"Bearish Engulfing");
                 {
                  return -1;
                 }
              }
           }
        }
     }
   return 0;
  }
void createObj3(datetime time, double price, int arrawCode, color clr, string txt)
  {
   string objName=" ";
   StringConcatenate(objName, "Signal@",time, "at",DoubleToString(price,_Digits),"(",arrawCode,")");
   if(ObjectCreate(0,objName,OBJ_ARROW,0,time,price))
     {
      ObjectSetInteger(0,objName,OBJPROP_ARROWCODE,arrawCode);
      ObjectSetInteger(0,objName,OBJPROP_COLOR,clr);
      if(clr==clrGreen)
         ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_TOP);
      if(clr==clrRed)
         ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_BOTTOM);
     }
   string candleName=objName+txt;
   if(ObjectCreate(0,candleName,OBJ_TEXT,0,time,price))
     {
      ObjectSetString(0,candleName,OBJPROP_TEXT," "+txt);
      ObjectSetInteger(0,candleName,OBJPROP_COLOR,clr);
     }
  }
//+------------------------------------------------------------------+
int getPiercing()
  {
   datetime time=iTime(_Symbol,PERIOD_CURRENT,1);
   double open=iOpen(_Symbol,PERIOD_CURRENT,1);
   double high=iHigh(_Symbol,PERIOD_CURRENT,1);
   double low=iLow(_Symbol,PERIOD_CURRENT,1);
   double close=iClose(_Symbol,PERIOD_CURRENT,1);
   double open2=iOpen(_Symbol,PERIOD_CURRENT,2);
   double high2=iHigh(_Symbol,PERIOD_CURRENT,2);
   double low2=iLow(_Symbol,PERIOD_CURRENT,2);
   double close2=iClose(_Symbol,PERIOD_CURRENT,2);
   double candleSize2=high2-low2;
   double candleMidPoint2=high2-(candleSize2/2);
   if(open<close)
     {
      if(open2>close2)
        {
         if(open<low2)
           {
            if(close>candleMidPoint2&&close<high2)
              {
               createObj4(time,low,217, clrGreen,"Piercing");
                 {
                  return 1;
                 }
              }
           }
        }
     }
   if(open>close)
     {
      if(open2<close2)
        {
         if(open>high2)
           {
            if(close<candleMidPoint2&&close>low2)
              {
               createObj4(time,high,218, clrRed,"Dark Cloud");
                 {
                  return -1;
                 }
              }
           }
        }
     }
   return 0;
  }
void createObj4(datetime time, double price, int arrawCode, color clr, string txt)
  {
   string objName=" ";
   StringConcatenate(objName, "Signal@",time, "at",DoubleToString(price,_Digits),"(",arrawCode,")");
   if(ObjectCreate(0,objName,OBJ_ARROW,0,time,price))
     {
      ObjectSetInteger(0,objName,OBJPROP_ARROWCODE,arrawCode);
      ObjectSetInteger(0,objName,OBJPROP_COLOR,clr);
      if(clr==clrGreen)
         ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_TOP);
      if(clr==clrRed)
         ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_BOTTOM);
     }
   string candleName=objName+txt;
   if(ObjectCreate(0,candleName,OBJ_TEXT,0,time,price))
     {
      ObjectSetString(0,candleName,OBJPROP_TEXT," "+txt);
      ObjectSetInteger(0,candleName,OBJPROP_COLOR,clr);
     }
  }
//+------------------------------------------------------------------+
int getStar(double middleCandleRatio)
  {
   datetime time=iTime(_Symbol,PERIOD_CURRENT,1);
   double open=iOpen(_Symbol,PERIOD_CURRENT,1);
   double high=iHigh(_Symbol,PERIOD_CURRENT,1);
   double low=iLow(_Symbol,PERIOD_CURRENT,1);
   double close=iClose(_Symbol,PERIOD_CURRENT,1);
   double open2=iOpen(_Symbol,PERIOD_CURRENT,2);
   double high2=iHigh(_Symbol,PERIOD_CURRENT,2);
   double low2=iLow(_Symbol,PERIOD_CURRENT,2);
   double close2=iClose(_Symbol,PERIOD_CURRENT,2);
   double open3=iOpen(_Symbol,PERIOD_CURRENT,3);
   double high3=iHigh(_Symbol,PERIOD_CURRENT,3);
   double low3=iLow(_Symbol,PERIOD_CURRENT,3);
   double close3=iClose(_Symbol,PERIOD_CURRENT,3);
   double candleSize=high-low;
   double candleSize2=high2-low2;
   double candleSize3=high3-low3;
   if(open<close)
     {
      if(open3>close3)
        {
         if(candleSize2<candleSize*middleCandleRatio && candleSize2<candleSize3*middleCandleRatio)
           {
            createObj5(time,low,217, clrGreen,"Morning Star");
              {
               return 1;
              }
           }
        }
     }
   if(open>close)
     {
      if(open3<close3)
        {
         if(candleSize2<candleSize*middleCandleRatio && candleSize2<candleSize3*middleCandleRatio)
           {
            createObj5(time,high,218, clrRed,"Evening Star");
              {
               return -1;
              }
           }
        }
     }
   return 0;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void createObj5(datetime time, double price, int arrawCode, color clr, string txt)
  {
   string objName=" ";
   StringConcatenate(objName, "Signal@",time, "at",DoubleToString(price,_Digits),"(",arrawCode,")");
   if(ObjectCreate(0,objName,OBJ_ARROW,0,time,price))
     {
      ObjectSetInteger(0,objName,OBJPROP_ARROWCODE,arrawCode);
      ObjectSetInteger(0,objName,OBJPROP_COLOR,clr);
      if(clr==clrGreen)
         ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_TOP);
      if(clr==clrRed)
         ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_BOTTOM);
     }
   string candleName=objName+txt;
   if(ObjectCreate(0,candleName,OBJ_TEXT,0,time,price))
     {
      ObjectSetString(0,candleName,OBJPROP_TEXT," "+txt);
      ObjectSetInteger(0,candleName,OBJPROP_COLOR,clr);
     }
  }
//+------------------------------------------------------------------+
int getthreeInside()
  {
   datetime time=iTime(_Symbol,PERIOD_CURRENT,1);
   double open=iOpen(_Symbol,PERIOD_CURRENT,1);
   double high=iHigh(_Symbol,PERIOD_CURRENT,1);
   double low=iLow(_Symbol,PERIOD_CURRENT,1);
   double close=iClose(_Symbol,PERIOD_CURRENT,1);
   double open2=iOpen(_Symbol,PERIOD_CURRENT,2);
   double high2=iHigh(_Symbol,PERIOD_CURRENT,2);
   double low2=iLow(_Symbol,PERIOD_CURRENT,2);
   double close2=iClose(_Symbol,PERIOD_CURRENT,2);
   double open3=iOpen(_Symbol,PERIOD_CURRENT,3);
   double high3=iHigh(_Symbol,PERIOD_CURRENT,3);
   double low3=iLow(_Symbol,PERIOD_CURRENT,3);
   double close3=iClose(_Symbol,PERIOD_CURRENT,3);
   if(open3>close3)
     {
      if(open2<close2)
        {
         if(open2>low3&&close2<high3)
           {
            if(open<close&&open>open2&&open<close2)
              {
               if(close>high3)
                 {
                  createObj6(time,low,217, clrGreen,"3 Inside Up");
                    {
                     return 1;
                    }
                 }
              }
           }
        }
     }
   if(open3<close3)
     {
      if(open2>close2)
        {
         if(open2<high3&&close2>low3)
           {
            if(open>close&&open<open2&&open>close2)
              {
               if(close<low3)
                 {
                  createObj6(time,high,218, clrRed,"3 Inside Down");
                    {
                     return -1;
                    }
                 }
              }
           }
        }
     }
   return 0;
  }
void createObj6(datetime time, double price, int arrawCode, color clr, string txt)
  {
   string objName=" ";
   StringConcatenate(objName, "Signal@",time, "at",DoubleToString(price,_Digits),"(",arrawCode,")");
   if(ObjectCreate(0,objName,OBJ_ARROW,0,time,price))
     {
      ObjectSetInteger(0,objName,OBJPROP_ARROWCODE,arrawCode);
      ObjectSetInteger(0,objName,OBJPROP_COLOR,clr);
      if(clr==clrGreen)
         ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_TOP);
      if(clr==clrRed)
         ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_BOTTOM);
     }
   string candleName=objName+txt;
   if(ObjectCreate(0,candleName,OBJ_TEXT,0,time,price))
     {
      ObjectSetString(0,candleName,OBJPROP_TEXT," "+txt);
      ObjectSetInteger(0,candleName,OBJPROP_COLOR,clr);
     }
  }
//+------------------------------------------------------------------+
Evgeniy Ilin
Evgeniy Ilin | 18 мая 2023 в 16:42
FINANSE-BOND #:

Я так и сделал, объединил все в один советник. Но когда попробовал записать как Индикатор, в терминале всё равно загружается как Советник. Что-то нужно менять в Коде, но что именно я не знаю, не сильно разбираюсь. Ещё я заметил, что нужна его доработка в плане, что когда меняется Тайм Фрейм, на другой то сигнал остаётся на графике и уже на новом не соответствует бару на том же месте. По идее при смене нужно, чтобы удалялся или сохранялся только на том Тайм Фрейме где он был обнаружен. На всякий случай выставлю собраный мой Код, посмотрите что можно подправить или оптимизировать, я всего лишь скопировал со всех советников в один, но думаю там можно объявить некоторые переменные в начале, чтобы не повторяться в Коде несколько раз.   

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

FINANSE-BOND
FINANSE-BOND | 18 мая 2023 в 21:49

Я не докопался, я написал, что не силён в Коде поэтому и поделился своими выводами как пользователь, а также попросил немножко урезать что то в Коде что я не знаю где и как объявить некоторые переменные, которые повторяются. Также недавно смотрел видео, что пишут Советник на внешнем индикаторе. Поэтому я и говорил что если делать Индикатор то потом на него можно ссылаться в Советнике и брать от него данные. Может вы что то подправите если можете ?

FINANSE-BOND
FINANSE-BOND | 18 мая 2023 в 22:03
Если кому то, не будет лень прикрутите пожалуйста в Код Приказы на Покупку и продажу, раз уж это Советник.
Реализация фактора Януса в MQL5 Реализация фактора Януса в MQL5
Гэри Андерсон разработал метод анализа рынка, основанный на теории, которую он назвал фактором Януса. Теория описывает набор индикаторов, которые можно использовать для выявления тенденций и оценки рыночного риска. В этой статье мы реализуем эти инструменты в MQL5.
Теория категорий в MQL5 (Часть 5): Эквалайзеры Теория категорий в MQL5 (Часть 5): Эквалайзеры
Теория категорий представляет собой разнообразный и расширяющийся раздел математики, который лишь недавно начал освещаться в MQL5-сообществе. Эта серия статей призвана рассмотреть некоторые из ее концепций для создания открытой библиотеки и дальнейшему использованию этого замечательного раздела в создании торговых стратегий.
Нейросети — это просто (Часть 42): Прокрастинация модели, причины и методы решения Нейросети — это просто (Часть 42): Прокрастинация модели, причины и методы решения
Прокрастинация модели в контексте обучения с подкреплением может быть вызвана несколькими причинами, и решение этой проблемы требует принятия соответствующих мер. В статье рассмотрены некоторые из возможных причин прокрастинации модели и методы их преодоления.
Нейросети — это просто (Часть 41): Иерархические модели Нейросети — это просто (Часть 41): Иерархические модели
Статья описывает иерархические модели обучения, которые предлагают эффективный подход к решению сложных задач машинного обучения. Иерархические модели состоят из нескольких уровней, каждый из которых отвечает за различные аспекты задачи.