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

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

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

РИСУНОК 1:

image taken from 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>
4b9b3361

Ответ 1

Кажется, эти шаблоны не полностью описаны, поэтому невозможно правильно их кодировать. Хорошо, давайте попробуем с шаблоном № 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;
}

Ответ 2

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

Тем не менее, я все же хотел бы предоставить некоторую "стартовую площадку" для всех, чтобы построить собственный распознаватель образов на 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.

Ответ 3

Во-первых, просмотрите и суммируйте ваши паттерны (вместо того, чтобы ссылаться на уроки YouTube), то есть ваша "Зона спроса 1" - это двойное поглощение. Если вы приложите некоторые усилия, люди могут быть готовы помочь вам.