Validating Candlestick Patterns

 

If in 200 visible bars of history, there are 10 bullish engulf pattern, and in these 10 patterns, 5 are those patterns where low of bullish engulf is broken by close of a bear candle

so how can I write a loop to show only those patterns where low is not broken by close of candlestick in the visible bars.

 
Rodger Sen:

If in 200 visible bars of history, there are 10 bullish engulf pattern, and in these 10 patterns, 5 are those patterns where low of bullish engulf is broken by close of a bear candle

so how can I write a loop to show only those patterns where low is not broken by close of candlestick in the visible bars.

you mean after bar2 at any point or within a range ? 

 
Lorentzos Roussos #:

you mean after bar2 at any point or within a range ? 

Lets say there are high and lows on visible chart, I am looking to check from left to right how many engulf in visible chart are those where low of those engulf is not broken by body. If engulf low broken by close of candle then it should not show arrow on it, it should only show arrow which engulf are not broken by candle close of price from engulf to last recent bar.

here is my code attempt

//+------------------------------------------------------------------+
//|                                                         test.mq5 |
//|                                       Rodger Sen, Copyright 2023 |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Rodger Sen, Copyright 2023"
#property link      "https://www.mql5.com/"
#property version   "1.00"
#property indicator_chart_window
#property indicator_plots 0

double engulf=0,engulf2=0;
int engulf_index = 0,engulf_index2=0;
int lvb,_fvb,_clb,fvb=-1,clb=-1,hix,lix;

string prefix = "fs_";
color clrBull = C'8,153,129';
color clrBear = C'242,54,69';
color clrNull = clrSnow;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---
   
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam) {
//---
   if (id==CHARTEVENT_CHART_CHANGE) {
      FindHighLow();
      FindEngulf();
   }
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void FindEngulf() {


   FindBullishEngulf(hix);

   ObjectsDeleteAll(0,-1,OBJ_ARROW);

   int r1=0,r2=0,r3=0,r4=0,r5=0,r6=0,r7=0,r8=0,r9=0,r10=0;
   double s1=0,s2=0,s3=0,s4=0,s5=0,s6=0,s7=0,s8=0,s9=0,s10=0;



   for(int i=engulf_index; i>lix; i--) {
      if(iClose(NULL,0,i)<engulf) {
         FindBullishEngulf(i);
         s1 =  iClose(NULL,0,i);
         r1=i;
         break;
      }
   }
   r1--;
   for(int i=r1; i>lix; i--) {
      if(iClose(NULL,0,i)<s1) {
         // ObjectDelete(0,"SnR");
         FindBullishEngulf(i);
         s2 =  iClose(NULL,0,i);
         r2=i;
         break;
      }
   }
   r2--;
   for(int i=r2; i>lix; i--) {
      if(iClose(NULL,0,i)<s2) {
         // ObjectDelete(0,"SnR");
         FindBullishEngulf(i);
         s3 =  iClose(NULL,0,i);
         r3=i;
         break;
      }
   }
   r3--;
   for(int i=r3; i>lix; i--) {
      if(iClose(NULL,0,i)<s3) {
         // ObjectDelete(0,"SnR");
         FindBullishEngulf(i);
         s4 =  iClose(NULL,0,i);
         r4=i;
         break;
      }
   }
   r4--;

   for(int i=r4; i>lix; i--) {
      if(iClose(NULL,0,i)<s3) {
         // ObjectDelete(0,"SnR");
         FindBullishEngulf(i);
         s5 =  iClose(NULL,0,i);
         r5=i;
         break;
      }
   }
   r5--;

   ChartRedraw();
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void FindBullishEngulf(int ii)  {
   for(int i=ii; i>1; i--) {
// Find Bullish SNR
      if(iOpen(NULL,0,i)>iClose(NULL,0,i) && iOpen(NULL,0,i-1)<iClose(NULL,0,i-1) && iClose(NULL,0,i-1)>iOpen(NULL,0,i)) {
         //if(iClose(NULL,0,i)<=rates[i].close) {
         ArrowCreate(0,"Bullish_Engulf",0,iTime(NULL,0,i-1),iLow(NULL,0,i-1),234,ANCHOR_TOP,clrDeepPink);
         //  } else ObjectsDeleteAll(0,-1,OBJ_ARROW);
         engulf = iClose(NULL,0,i);
         engulf_index=i;
         break;
      }
   }
}  
//+------------------------------------------------------------------+
//| Find HighLow on Visible Chart Window                             |
//+------------------------------------------------------------------+
void FindHighLow() {
   _fvb=(int)ChartGetInteger(ChartID(),CHART_FIRST_VISIBLE_BAR,0);
   _clb=(int)ChartGetInteger(ChartID(),CHART_WIDTH_IN_BARS,0);
   if (_fvb>0 &&(_fvb!=fvb||_clb!=clb)) {
      lvb=_fvb-(_clb-1);
      if (lvb<0) {
         lvb=0;
      }

      hix= iHighest(NULL,0,MODE_HIGH,(_fvb-lvb),lvb); // Highest Index of High
      lix= iLowest(NULL,0,MODE_LOW,(_fvb-lvb),lvb); // Highest Index of Low

      //Highest Lowest Bodies
      ArrowCreate(0,prefix+"H",0,iTime(NULL,0,hix),iHigh(NULL,0,hix),234,ANCHOR_BOTTOM,clrBear);
      ArrowCreate(0,prefix+"L",0,iTime(NULL,0,lix),iLow(NULL,0,lix),233,ANCHOR_TOP,clrBull);

      ChartRedraw(ChartID());
      fvb=_fvb;
      clb=_clb;
   }

}
//+------------------------------------------------------------------+
//| Create the arrow                                                 |
//+------------------------------------------------------------------+
bool ArrowCreate(const long              chart_ID=0,           // chart's ID
                 const string            name="Arrow",         // arrow name
                 const int               sub_window=0,         // subwindow index
                 datetime                time=0,               // anchor point time
                 double                  price=0,              // anchor point price
                 const uchar             arrow_code=252,       // arrow code
                 const ENUM_ARROW_ANCHOR anchor=ANCHOR_BOTTOM, // anchor point position
                 const color             clr=clrRed,           // arrow color
                 const ENUM_LINE_STYLE   style=STYLE_SOLID,    // border line style
                 const int               width=1,              // arrow size
                 const bool              back=false,           // in the background
                 const bool              selection=false,       // highlight to move
                 const bool              hidden=true,          // hidden in the object list
                 const long              z_order=0) {          // priority for mouse click
   ResetLastError();
   if(!ObjectCreate(chart_ID,name,OBJ_ARROW,sub_window,time,price)) {
      Print(__FUNCTION__,
            ": failed to create an arrow! Error code = ",GetLastError());
      return(false);
   }
   ObjectSetInteger(chart_ID,name,OBJPROP_ARROWCODE,arrow_code);
   ObjectSetInteger(chart_ID,name,OBJPROP_ANCHOR,anchor);
   ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);
   ObjectSetInteger(chart_ID,name,OBJPROP_STYLE,style);
   ObjectSetInteger(chart_ID,name,OBJPROP_WIDTH,width);
   ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back);
   ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection);
   ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection);
   ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden);
   ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order);


//if(!ArrowCreate(0,InpName,0,date[d],price[p],32,InpAnchor,InpColor,
//                InpStyle,InpWidth,InpBack,InpSelection,InpHidden,InpZOrder)) {
//   return;
//}
   return(true);
}
  
//+------------------------------------------------------------------+
 
You can put them in memory as active engulfs , and , on each new bar you check and manage the active engulfs .
 
Lorentzos Roussos #:
You can put them in memory as active engulfs , and , on each new bar you check and manage the active engulfs .

What function to use to put in memory

 
Rodger Sen #:

What function to use to put in memory

you want an arrow if the breakout of the engulf is in the direction of the pattern ? 

 
Lorentzos Roussos #:

you want an arrow if the breakout of the engulf is in the direction of the pattern ? 

yes

 
Rodger Sen #:

yes

try this 

#property copyright "Discussion"
#property link      "https://www.mql5.com/en/forum/450830"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_plots   2
//--- plot Buy
#property indicator_label1  "Buy"
#property indicator_type1   DRAW_ARROW
#property indicator_color1  clrDeepSkyBlue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- plot Sell
#property indicator_label2  "Sell"
#property indicator_type2   DRAW_ARROW
#property indicator_color2  clrGold
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1
//--- indicator buffers
double         BuyBuffer[];
double         SellBuffer[];

//we create a structure for the engulf 
class anEngulf{
         //discovery time 
datetime discoveryTime;
datetime bar1Time,bar2Time;
double   top,bottom;
bool     active;
char     direction;//-1 bearish 1 bullish 0 nothing
         public:
         anEngulf(void){reset();}
        ~anEngulf(void){reset();}
    void reset(){
         discoveryTime=0;
         bar1Time=0;
         bar2Time=0;
         top=0.0;
         bottom=0.0;
         direction=0;
         active=false;
         }
    void setup_bullish(datetime _now,
                       datetime _bar1,
                       datetime _bar2,
                       double _top,
                       double _bottom){
         direction=1;
         top=_top;
         bottom=_bottom;
         bar1Time=_bar1;
         bar2Time=_bar2;
         discoveryTime=_now;
         active=true;
         }
    void setup_bearish(datetime _now,
                       datetime _bar1,
                       datetime _bar2,
                       double _top,
                       double _bottom){
         direction=-1;
         top=_top;
         bottom=_bottom;
         bar1Time=_bar1;
         bar2Time=_bar2;
         discoveryTime=_now;
         active=true;
         }  
    bool is_active(){return(active);}
    char maintain(double _close,datetime _now){
         if(_now>=discoveryTime){
           //bullish
             if(direction==1){
             if(_close>top){active=false;return(1);}
             if(_close<bottom){active=false;return(0);}
             }
           //bearish
             else if(direction==-1){
             if(_close<bottom){active=false;return(-1);}
             if(_close>top){active=false;return(0);}
             }
           }
         return(0);
         }  
};

//and a rack of engulfs , or a shelf :P

struct engulfShelf{
anEngulf engulfs[];//this is our collection
         engulfShelf(void){reset();}
        ~engulfShelf(void){reset();}
    void reset(){
         ArrayFree(engulfs);
         } 
    char read_bars(double b1Open,
                   double b1Close,
                   datetime b1Time,
                   double b2Open,
                   double b2Close,
                   datetime b2Time,
                   double b3Close,
                   datetime b3Time_now){
         //bullish 
           if(b2Close>b2Open){
             if(b1Close<b1Open){
               if(b2Close>b1Open){
                 if(b2Open<b1Close){
                   //add engulfing 
                     int ix=add_engulf();
                     engulfs[ix].setup_bullish(b3Time_now,b1Time,b2Time,b2Close,b2Open);
                   }
                 }
               }
             }
         //bearish 
           if(b2Close<b2Open){
             if(b1Close>b1Open){
               if(b2Close<b1Open){
                 if(b2Open>b1Close){
                   //add engulfing 
                     int ix=add_engulf();
                     engulfs[ix].setup_bearish(b3Time_now,b1Time,b2Time,b2Open,b2Close);
                   }
                 }
               }
             }  
         //0 no signal
         //1 only buy
         //-1 only sell
         //2 both   
           char signal=0;
           for(int i=0;i<ArraySize(engulfs);i++){
           char local_signal=engulfs[i].maintain(b3Close,b3Time_now);
           if(local_signal!=0){
             if(signal==0){signal=local_signal;}
             else if(signal==1){
                    if(local_signal==-1){signal=2;}
                    }
             else if(signal==-1){
                    if(local_signal==1){signal=2;}
                    }
             }
           }
           int from=ArraySize(engulfs)-1;
           for(int i=from;i>=0;i--){
           if(!engulfs[i].is_active()){
             remove(i);
             }
           }
         return(signal);
         }
     int add_engulf(){
         int ns=ArraySize(engulfs)+1;
         ArrayResize(engulfs,ns,0);
         return(ns-1);
         }
     int remove(int ix){
         int ns=ArraySize(engulfs)-1;
         engulfs[ix]=engulfs[ns];
         ArrayResize(engulfs,ns,0);
         return(ns);
         }
};

engulfShelf E;

int OnInit()
  {
  E.reset();
//--- indicator buffers mapping
   SetIndexBuffer(0,BuyBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,SellBuffer,INDICATOR_DATA);
//--- setting a code from the Wingdings charset as the property of PLOT_ARROW
   PlotIndexSetInteger(0,PLOT_ARROW,233);
   PlotIndexSetInteger(1,PLOT_ARROW,234);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---
  int from=prev_calculated;
  int to=rates_total-2;
  if(from==0){from=3;}
  for(int i=from;i<=to;i++){
  char signal=E.read_bars(open[i-2],close[i-2],time[i-2],open[i-1],close[i-1],time[i-1],close[i],time[i]);
  if(signal==1){
    BuyBuffer[i]=close[i];
    }
  else if(signal==-1){
    SellBuffer[i]=close[i];
    }
  else if(signal==2){
    BuyBuffer[i]=close[i];
    SellBuffer[i]=close[i];
    }
  } 
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
 
Lorentzos Roussos #:

try this 

Thanks I will study this.

 
Rodger Sen #:

Thanks I will study this.

No problem . 

Be careful as sometimes the arrow you see comes from an engulfing pattern that is not neccesserrilly immediately preceding the signal bar.

This is where you do ninja stuff and add information popups on hovering , shapes colors etc ,
 

instead of using iClose and iOpen you can use the "open" and "close" buffers which are in the OnCalculate  function signature


You can make a function that passes in the index (if you make a for loop inside OnCalculate)


EDIT-  I see that is what Lorentzos has done

Lorentzos Roussos
Lorentzos Roussos
  • 2023.07.17
  • www.mql5.com
Trader's profile