14
votes

I am quite new to writing mql4 code and would be grateful if I could get some help drawing rectangles when the following candlestick patterns occur:

FIG1:

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>

FIG2:

image taken from https://imgur.com/a/4E8KE1R

Run code snippet

<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>

and

FIG3:

image taken from https://imgur.com/a/h6D6o6R

Run code snippet

<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>

and respective Supply Zones
and opening a pending order with specified pips Stop Loss and Take Profit.

Pardon me for not including the images directly. I don't I have enough upvotes to do that.

Here is an explanation of the candlestick patterns in the linked images:

Demand Zone

The general candlestick pattern (Demand Zone) occurs when at least two or more consecutive bullish candles (with the last bullish candle high being the high of the time period) are followed by one or more bearish candles whose high and low are lower than the last bullish candle. Then finally followed by a bullish candle that forms the new high. The rectangle area which is the Demand Zone is taken from the Open to the Low of the last last bearish candle.

Hidden Demand Zone

When a series of consecutive bullish candles has a candle with its low, lower than the previous candle and its High coinciding with its Close, then the Hidden Demand Zone is taken from the low to the open of the bullish candle.

The full explanation is available here for both demand and supply zones.

I am aware that bullish and bearish candles can be determined by


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

I would really appreciate some help.

2
So you asking someone to write you code to find those patterns?Michel_T.
I need help with writing code to find the patternsTopLeft
SO is not for providing code. If you have an exact question, the people here will happy to help you, but 'do the task for me' - it's a wrong request and I doubt that anyone will do this for you for free.Michel_T.
@JosephLee I didn't start the bounty but looking from the response to my question I believe apart from a lot of people benefitting from the solution, the solution would also generate several upvotes, maybe more than the bounty itself. That's just my opinion based on the little I've seen here.TopLeft
@JosephLee I agree with what TopLeft said. It's true that the bounty seems to require a lot, but a lot can also be gained from a good answer. Also to put things in perspective, I didn't ask the question but I've given close to a third of my reputation for the bounty because of my interest in a solution.OnlyCodeMatters

2 Answers

1
votes

Seems these patterns are not fully described, so it is not possible to code them correctly. Ok, let us try with pattern#1. The conditions used for pattern(what seems reasonable from the picture):
1. check at start of the new bar(bar#0).
2. bar 1(which is bar#3 in MQL4 if we compute 0 as the current) must be bullish.
3. bar 2(bar#2) is bearish. (or N bars in case of pattern#2, N can be 2 or more) 4. bar 3(bar#1 in MT4) is bullish.
5. its high=close.
6. its high>high of bar#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
   }
}

What else you need here? To detect HL of the rectangle? That is simple, is rules are clear. Let us assume they are: for LONG, up=Open of bar#2, down=low of that bar. Then,

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);
    }
}

Do you need to draw a rectangle? Ok but how would you decide what is the time to stop drawing? Let us assume N bars to the right is enough, and let us ignore weekends for now(a bit more complicated if keeping in mind weekends when the market is closed).

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;
}

here is the main block, do not forget to add a new bar check, otherwise the tool would check for objects every tick which is waste of time. string prefix=""; //add some unique prefix for all your objects const int N_bars = 15; //15 bars in this example

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;
}
1
votes

I'm late :'( Work kept me from StackOverflow :'( Anyway, I won't be able to provide a full program as per the Bounty, nor can I provide the full code to solve this Demand Zone question.

However, I still would like to provide some "starting ground" for everyone to build their own Pattern Recognizer on MT4 (MQL4).

To keep the text short, I've recorded a YouTube video to describe it. https://youtu.be/WSiyY52QyBI

Anyway, here are the codes:

//+------------------------------------------------------------------+
//|                                                   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() ...
}
//+------------------------------------------------------------------+

More importantly, is the clsBar.mqh. Note that this is an "include file", and should be located in the include folder. Include file helps us to make our program less clutter, and help us to be able to write re-usable codes. Very useful when writing OOP classes.

clsBar.mqh: Download (OneDrive) https://1drv.ms/u/s!AoLFy6fRYNsvjTU-xSzAADCwGjPQ

Unfortunately, the file is too large to be included in this post. So I have to upload it the OneDrive.