Как написать код mql4 (EA), который помечает перечисленные свечные паттерны прямоугольниками

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

РИС 1:

изображение взято с https://imgur.com/a/fRoPzsm

Run code snippet

<blockquote class="imgur-embed-pub" lang="en" data-id="a/fRoPzsm"><a href="//imgur.com/a/fRoPzsm">Demand Zone 1</a></blockquote><script async src="//s.imgur.com/min/embed.js" charset="utf-8"></script>

РИС 2:

изображение взято с https://imgur.com/a/4E8KE1R

Выполнить фрагмент кода

<blockquote class="imgur-embed-pub" lang="en" data-id="a/4E8KE1R" data-context="false"><a href="//imgur.com/a/4E8KE1R">Demand Zone 2</a></blockquote><script async src="//s.imgur.com/min/embed.js" charset="utf-8"></script>

а также

РИС.3:

изображение взято с https://imgur.com/a/h6D6o6R

Выполнить фрагмент кода

<blockquote class="imgur-embed-pub" lang="en" data-id="a/h6D6o6R"><a href="//imgur.com/a/h6D6o6R">Hidden Demand Zone</a></blockquote><script async src="//s.imgur.com/min/embed.js" charset="utf-8"></script>

и соответствующие Зоны Предложения
и открытие отложенного ордера с установленными значениями Stop Loss и Take Profit в пунктах.

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

Вот объяснение паттернов свечей на связанных изображениях:

Зона спроса

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

Скрытая зона спроса

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

Полное объяснение доступно здесь как для зон спроса, так и для зон предложения.

Я знаю, что bullish и bearish свечей можно определить по


    if ( ( Open[1] - Close[1] ) > 0)
    {
      // candle is bearish
    }
    else
    {
      // candle is bullish
    }

Я был бы очень признателен за помощь.


person TopLeft    schedule 02.07.2019    source источник
comment
Итак, вы просите кого-нибудь написать вам код, чтобы найти эти шаблоны?   -  person Michel_T.    schedule 02.07.2019
comment
Мне нужна помощь в написании кода, чтобы найти закономерности   -  person TopLeft    schedule 02.07.2019
comment
SO не для предоставления кода. Если у вас есть конкретный вопрос, люди здесь будут рады помочь вам, но "сделай задание для меня" - это неправильная просьба, и я сомневаюсь, что кто-то сделает это за вас бесплатно.   -  person Michel_T.    schedule 02.07.2019
comment
Я понимаю это, но вот случай, когда я предоставил то, что я могу сделать, а именно кодировать бычьи и медвежьи свечи. Я просто помогаю с тем, как применять условия для распознавания шаблонов.   -  person TopLeft    schedule 02.07.2019
comment
Я здесь за наградой, но у награды довольно большой размах. 100 баллов недостаточно для усилий для этого. Так что, возможно, нет. Я уже делал распознаватель паттернов свечных палочек в MT4 на imgur.com/a/Kmumv8U (это идентифицирует паттерны в реальном времени на нескольких таймфреймах). Распознавание шаблона не должно быть трудным. Чтобы нарисовать эту коробку, нужно немного поработать. Я вернусь.   -  person Joseph Lee    schedule 05.07.2019
comment
@JosephLee Я не запускал награду, но, судя по ответу на мой вопрос, я считаю, что помимо множества людей, выигравших от решения, решение также принесет несколько голосов, может быть, больше, чем сама награда. Это только мое мнение, основанное на том немногом, что я здесь увидел.   -  person TopLeft    schedule 09.07.2019
comment
@JosephLee Я согласен с тем, что сказал TopLeft. Это правда, что награда, кажется, требует многого, но многое можно получить и от хорошего ответа. Кроме того, чтобы представить ситуацию в перспективе, я не задавал вопрос, но я отдал почти треть своей репутации за награду из-за моего интереса к решению.   -  person OnlyCodeMatters    schedule 10.07.2019


Ответы (2)


Похоже, что эти шаблоны описаны не полностью, поэтому их невозможно правильно закодировать. Хорошо, давайте попробуем с шаблоном № 1. Условия, используемые для паттерна (что кажется разумным на картинке):
1. проверка в начале нового бара (бар № 0).
2. бар 1 (который является баром № 3 в MQL4, если мы вычисляем 0 в качестве текущего) должен быть бычьим.
3. бар 2 (бар № 2) медвежий. (или N баров в случае паттерна № 2, N может быть 2 или более) 4. Бар 3 (бар № 1 в MT4) бычий.
5. его максимум = закрытие.
6. его максимум> максимум бара №3.

enum EnmDir
 {
  LONG = 1,
  SHORT=-1,
  NONE = 0,
 };
int getCandleDirection(const int shift)
{
   const double open=iOpen(_Symbol,0,shift), close=iClose(_Symbol,0,shift);
   if(close-open>_Point/2.)
      return LONG;      //bullish
   if(open-close>_Point/2.)
      return SHORT;     //bearish
   return NONE;     //doji
}
bool isPattern1Detected(const EnmDir dir)
{
   if(dir==0)return(false);
   if(getCandleDirection(3)!=dir)
      return false; //rule#2
   if(getCandleDirection(2)+dir!=0)
      return false; //rule#3
   if(getCandleDirection(1)!=dir)
      return false; //rule#4
   if(dir>0)
   {
      if(iHigh(_Symbol,0,1)-iClose(_Symbol,0,1)>_Point/2.)
         return false;  //rule#5 for long
      if(iHigh(_Symbol,0,1)-iHigh(_Symbol,0,3)>_Point/2.)
         return true;   //rule#6 for long
      return false;     //if rule#6 is not hold
   }
   else
   {
      if(iClose(_Symbol,0,1)-iLow(_Symbol,0,1)>_Point/2.)
         return false;  //rule#5 for short
      if(iLow(_Symbol,0,3)-iLow(_Symbol,0,1)>_Point/2.)
         return true;   //rule#6 for short
      return false;     //if rule#6 is not hold
   }
}
bool isPattern2Detected(const EnmDir dir,const int numCandlesAgainst=1)
{
   if(dir==NONE)return(false);
   if(getCandleDirection(1)!=dir)
      return false; //rule#4
   for(int i=1;i<=numCandlesAgainst;i++)
   {
      if(getCandleDirection(1+i)!=dir)
         return(false); //rule#3 - checking that all numCandlesAgainst must be bearish
   }
   if(getCandleDirection(2+numCandlesAgainst)!=dir)
       return false; //rule#2
   if(dir>0)
   {
     if(iHigh(_Symbol,0,1)-iClose(_Symbol,0,1)>_Point/2.)
        return false;  //rule#5 for long
     if(iHigh(_Symbol,0,1)-iHigh(_Symbol,0,2+numCandlesAgainst)>_Point/2.)
        return true;   //rule#6 for long
     return false;     //if rule#6 is not hold
   }
   else
   {
     if(iClose(_Symbol,0,1)-iLow(_Symbol,0,1)>_Point/2.)
        return false;  //rule#5 for short
     if(iLow(_Symbol,0,2+numCandlesAgainst)-iLow(_Symbol,0,1)>_Point/2.)
        return true;   //rule#6 for short
     return false;     //if rule#6 is not hold
   }
}

Что еще вам нужно здесь? Обнаружить HL прямоугольника? То есть просто, правила понятны. Предположим, что они следующие: для LONG вверх = открытие бара № 2, вниз = минимум этого бара. Потом,

void detectRangeOfZone(double &top,double &bottom,const EnmDir dir)
{
    if(dir>0)
    {
        top=iOpen(_Symbol,0,2);
        bottom=iLow(_Symbol,0,2);
    }
    else if(dir<0)
    {
        top=iClose(_Symbol,0,2);
        bottom=iHigh(_Symbol,0,2);
    }
}

Вам нужно нарисовать прямоугольник? Хорошо, но как бы вы решили, когда пора перестать рисовать? Предположим, что N баров справа достаточно, и пока проигнорируем выходные (немного сложнее, если иметь в виду выходные, когда рынок закрыт).

bool drawRectangle(const int dir,const double top,const double bottom)
{
    const datetime starts=iTime(_Symbol,0,2), ends=starts+PeriodSeconds()*N_bars;//time of start and end of the rectangle
    const string name=prefix+"_"+(dir>0?"DEMAND":"SUPPLY")+"_"+TimeToString(starts);//name would be unique sinse we use time of start of the range. DO NOT FORGET about prefix - it should be declared globally, you would be able to delete all the objects with 'ObjectsDeleteAll()' function that accepts prefix in one of its implementations.

    if(!ObjectCreate(0,name,OBJ_RECTANGLE,0,0,0,0,0))
    {
        printf("%i %s: failed to create %s. error=%d",__LINE__,__FILE__,name,_LastError);
        return false;
    }
    ObjectSetInteger(0,name,OBJPROP_TIME1,starts);
    ObjectSetInteger(0,name,OBJPROP_TIME2,ends);
    ObjectSetDouble(0,name,OBJPROP_PRICE1,top);
    ObjectSetDouble(0,name,OBJPROP_PRICE2,bottom);
    //add color, width, filling color, access modifiers etc, example is here https://docs.mql4.com/ru/constants/objectconstants/enum_object/obj_rectangle
    return true;
}

вот основной блок, не забудьте добавить новую проверку бара, иначе инструмент будет проверять наличие объектов каждый тик, что является пустой тратой времени. префикс строки=""; // добавляем уникальный префикс для всех ваших объектов const int N_bars = 15; //15 баров в этом примере

void OnDeinit(const int reason){ObjectsDeleteAll(0,prefix);}
void OnTick()
{
    if(!isNewBar())
        return;     //not necessary but waste of time to check every second

    const bool pattern1Up=isPattern1Detected(1), pattern1Dn=isPattern1Detected(-1);
    if(pattern1Up)
    {
        double top,bottom;
        detectRangeOfZone(top,bottom,1);
        drawRectangle(1,top,bottom);
        PlacePendingOrder(1,top,bottom);
    }
    if(pattern1Dn)
    {
        double top,bottom;
        detectRangeOfZone(top,bottom,-1);
        drawRectangle(-1,top,bottom);
        PlacePendingOrder(-1,top,bottom);
    }
}

int PlacePendingOrder(const EnmDir dir,const double oop,const double suggestedSl)
{
   const double lot=0.10;                  //FOR EXAMPLE, PUT YOUR DATA HERE
   const string comment="example for SOF";
   const int magicNumber=123456789;

   int cmd=dir>0 ? OP_BUY : OP_SELL;
   double price=(dir>0 ? Ask : Bid), spread=(Ask-Bid);
   if(dir*(oop-price)>spread)
      cmd+=(OP_BUYSTOP-OP_BUY);
   else if(dir*(price-oop)>spread)
      cmd+=(OP_BUYLIMIT-OP_BUY);

   int attempt=0, ATTEMPTS=5, SLEEP=25, SLIPPAGE=10, result=-1, error=-1;
   while(attempt<ATTEMPTS)
     {
      attempt++;
      RefreshRates();
      if(cmd<=OP_SELL)
        {
         price=dir>0 ? Ask : Bid;
         result=OrderSend(_Symbol,cmd,lot,price,SLIPPAGE,0,0,comment,magicNumber);
        }
      else
        {
         result=OrderSend(_Symbol,cmd,lot,oop,SLIPPAGE,0,0,comment,magicNumber);
        }
      if(result>0)
         break;
      error=_LastError;
      Sleep(SLEEP);
    }
  if(result>0)
    {
     if(OrderSelect(result,SELECT_BY_TICKET))
       {
        price=OrderOpenPrice();
        if(!OrderModify(result,price,suggestedSl,0,OrderExpiration()))
           printf("%i %s: failed to modify %d. error=%d",__LINE__,__FILE__,result,_LastError);
           //tp is zero, sl is suggested SL, put yours when needed
       }
     return result;
    }
    printf("%i %s: failed to place %s at %.5f. error=%d",__LINE__,__FILE__,EnumToString((ENUM_ORDER_TYPE)cmd),(cmd>OP_SELL ? oop : price),error);
    return -1;
}
person Daniel Kniaz    schedule 06.07.2019
comment
Спасибо за ответ. Я попытался объяснить Зоны Спроса, но, думаю, у меня это не очень хорошо получилось. Это основная причина, по которой я включил ссылку на YouTube. Первые несколько минут подробно объясняют шаблон, но только для того, чтобы выделить несколько вещей, о которых вы спрашивали. Изображение 1 и 2 в вопросе относятся к одному и тому же шаблону. Как правило, паттерн начинается как минимум с одной бычьей свечи, за которой следует как минимум одна медвежья свеча, за которой следует одна бычья свеча с более высоким максимумом, чем начальные бычьи свечи. 1/3 - person TopLeft; 09.07.2019
comment
Итак, нас интересует последняя медвежья свеча в группе медвежьих свечей. Она открыта и минимум составляет зону спроса. Скрытая зона спроса представлена ​​бычьей свечой в группе, состоящей как минимум из двух бычьих свечей, максимум которых выше максимума предыдущей свечи, а минимум ниже минимума предыдущей свечи. Открытие и минимум образуют скрытую зону спроса. Думаю, показывать прямоугольник для N_bars нормально. Я был бы очень признателен, если бы вы могли включить полный пример, включающий установку отложенного ордера с SL и TP при распознавании паттерна. 2/3 - person TopLeft; 09.07.2019
comment
Поиск паттерна в более общих случаях, когда он содержит более одной медвежьей свечи, кажется, является основным недостающим в вашем решении, и условие 5, как вы заявили, не требуется. 3/3 - person TopLeft; 09.07.2019
comment
@DanielKniaz, чтобы получить награду за этот вопрос, вы упускаете несколько вещей, более общий распознаватель образов, основанный на изображениях выше. Я посмотрел первые несколько минут видео, как рекомендовал TopLeft, и они хорошо описаны. Также отсутствует проверенный код с примером отложенного ордера. - person OnlyCodeMatters; 10.07.2019
comment
@OnlyCodeMatters, все шаблоны разные. Хорошо, шаблон № 1 и шаблон № 2 похожи, и я добавил код о том, как реализовать № 2 (очень похож на № 1). Для № 3 - он отличается от № 1 или № 2, и его будет довольно легко закодировать после того, как вы или ТС проверите и поймете все шаги, сделанные для распознавания шаблона № 1. Добавлен пример отложенного ордера, код скомпилируется после того, как вы реализуете функцию isNewBar() (статья на MQL5.com или любая другая реализация, или скрыть этот блок). - person Daniel Kniaz; 11.07.2019
comment
@DanielKniaz Я добавил этот код, как вы просили, а также увеличил количество баров с 15 до 100, но прямоугольники не не показывают, даже в явных случаях, которые я признал. - person TopLeft; 12.07.2019
comment
@DanielKniaz Давно меня здесь не было, я только что вспомнил, что создал награду :). Я не смог проверить код, который вы написали, и не успею, пока не закончится награда. Но с первого взгляда и исходя из приложенных вами усилий, я думаю, ваш ответ наиболее близок к желаемому решению. - person OnlyCodeMatters; 12.07.2019
comment
@TopLeft код установки цвета и т. д. для объекта, вероятно, даже не компилируется. Покажите полный код. isNewBar() взят из MT5, хотя кажется, что он должен работать и в MT4. - person Daniel Kniaz; 12.07.2019
comment
@OnlyCodeMatters, спасибо! Я думаю, что шаблон № 3 является самым простым, поэтому все, кто заинтересован, могут кодировать его, если у него есть время и интерес. - person Daniel Kniaz; 12.07.2019
comment
@DanielKniaz Вот полный код. Я получил isNewBar() от forexfactory, и было заявлено, что он должен работать как для mql4, так и для mql5. - person TopLeft; 13.07.2019
comment
@TopLeft прежде всего нужно знать, нужно ли вам правило № 5. кажется, это тот, который сокращает большинство настроек. Также нужно подумать, что если open=low для зоны предложения в паттерне №1 (аналогично close=high), если они совпадают, вы не видите прямоугольник, потому что он имеет ширину 0 тиков, возможно, имеет смысл добавить какое-то ограничение для таких небольшие зоны и не торгуйте (по крайней мере, в этой зоне невозможно установить стоп-лосс) - person Daniel Kniaz; 13.07.2019
comment
Правило № 5 @DanielKniaz не кажется необходимым, поэтому я его прокомментировал. Тем не менее прямоугольники не рисуются. Если open=low для зоны предложения, она не должна рисоваться. - person TopLeft; 15.07.2019
comment
А можно пример показать? Я проверил, и это работает на моем конце - person Daniel Kniaz; 16.07.2019
comment
@DanielKniaz Спасибо. Только что понял, что он показывает прямоугольники. Я думал, что он покажет шаблоны в прошлом, когда я прокручиваю назад на основе N_bars, поэтому я думал, что это не работает. Как я могу получить шаблоны в прошлом, чтобы показать? - person TopLeft; 17.07.2019
comment
@TopLeft есть функция isPattern1Detected(), которая по умолчанию принимает параметр 1. он закодирован таким образом, что вы можете ввести свой номер, который является номером последнего бара паттерна. Также вам нужно будет добавить параметр в detectRangeZone() и, вероятно, лучше, если он будет таким же, как и в другой функции. замените 2 на shift+1 в этой функции после добавления int shift; добавьте начало и конец времени в drawRectangle(), используя ту же логику - person Daniel Kniaz; 17.07.2019
comment
@DanielKniaz Я не совсем понял ваше объяснение того, как показать паттерны в более ранних свечах. isPattern1Detected() принимает параметр перечисления, который равен -1, 0 или 1, поэтому, скажем, я хочу, чтобы прямоугольники отображались всякий раз, когда обнаруживается паттерн за последнюю неделю/месяц/50 свечей, мне нужно настроить перечисление или что-то в этом роде. - person TopLeft; 20.07.2019
comment
@TopLeft Нет, я говорил о сдвиге, по умолчанию он равен 1, но вы можете вызвать любой другой бар или группу баров. И вам нужно будет вызвать LONG, а затем SHORT, нет необходимости обновлять перечисление, если это не имеет смысла. - person Daniel Kniaz; 22.07.2019
comment
@DanielKniaz Помимо внесения изменений в drawRectangle(), если я вас хорошо понимаю, я должен заменить 1 в getCandleDirection(1) и if(iHigh(_Symbol,0,1)-iHigh(_Symbol,0,3)>_Point/2.) и так далее в isPattern1Detected(). Надеюсь, мы на одной волне. Я не хочу менять шаблон, я просто хочу видеть предыдущие вхождения, когда я прокручиваю назад во времени, немного похоже на индикатор SupDem. - person TopLeft; 22.07.2019
comment
@TopLeft вам нужна функция isPattern1Detected(const EnmDir dir,const int shift) и detectRangeOfZone(double &top,double &bottom,const EnmDir dir,const int shift), где shift заменяется номером свечи, по умолчанию это 1 (поэтому 2 заменяется на 1+shift и т. д.). - person Daniel Kniaz; 24.07.2019

Я опоздал :'( Работа удержала меня от StackOverflow :'( В любом случае, я не смогу предоставить полную программу в соответствии с Bounty, а также не могу предоставить полный код для решения этого вопроса о зоне спроса.

Тем не менее, я все же хотел бы предоставить каждому «отправную точку» для создания собственного распознавателя паттернов на MT4 (MQL4).

Чтобы текст был кратким, я записал видео на YouTube, чтобы описать его. https://youtu.be/WSiyY52QyBI

В любом случае, вот коды:

//+------------------------------------------------------------------+
//|                                                   SO56854700.mq4 |
//|                 Copyright 2019, Joseph Lee, TELEGRAM JosephLee74 |
//|               https://stackoverflow.com/users/1245195/joseph-lee |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, Joseph Lee, TELEGRAM JosephLee74"
#property link      "https://stackoverflow.com/users/1245195/joseph-lee"
#property version   "1.00"
#property strict

#include <clsBar.mqh>
#include <stderror.mqh> 
#include <stdlib.mqh> 

//==========================================================================

//-------------------------------------------------------------------
// System Variables
//-------------------------------------------------------------------
double  viPipsToPrice               = 0.0001;
double  viPipsToPoint               = 1;
string  vsDisplay                   = "";

//-------------------------------------------------------------------

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit() {
    ObjectsDeleteAll(); Comment("");
    // Caclulate PipsToPrice & PipsToPoints (old sytle, but works)
    if((Digits == 2) || (Digits == 3)) {viPipsToPrice=0.01;}
    if((Digits == 3) || (Digits == 5)) {viPipsToPoint=10;}

    return(INIT_SUCCEEDED);
}


//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
    ObjectsDeleteAll();
    return(0);
}


//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick() {
    if(!isNewBar())
        return;

    clsCandlestickPattern   voPatterns[];
    clsPatternRecognizer        voRec(Symbol(), true), PERIOD_CURRENT, 0);
    voRec.sbRecognizePatterns(voPatterns);
    for(...
       Display the content with Comment() ...
}
//+------------------------------------------------------------------+

Что еще более важно, это clsBar.mqh. Обратите внимание, что это «включаемый файл», и он должен находиться в папке включаемых файлов. Включение файла помогает нам сделать нашу программу менее загроможденной и помогает нам писать повторно используемые коды. Очень полезно при написании классов ООП.

clsBar.mqh: скачать (OneDrive) https://1drv.ms/u/s!AoLFy6fRYNsvjTU-xSzAADCwGjPQ

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

person Joseph Lee    schedule 11.07.2019
comment
@JospehLee clsBar.mqh кажется, что это действительно сделает все намного проще. Я поместил файл во включение, как вы просили, и попытался запустить предоставленный вами пример только с clsCandlestickPattern voPatterns[]; в OnTick(), но я получил несколько ошибок fniGetLargerOf, fniGetSmallerOf и fniGetPricePerPip. Я был бы очень рад, если бы вы могли привести полный пример, например, начертить две горизонтальные линии на открытии и закрытии медвежьей свечи, когда распознан медвежий паттерн поглощения. Это действительно помогло бы понять, как следует использовать clsBar.mqh. - person TopLeft; 22.07.2019
comment
Я также пытался использовать clsBar.mqh и столкнулся с похожей проблемой. - person TenOutOfTen; 25.07.2019