Drawing a rectangle

 

Hello, I need some help.

Like in the topic's title, I want to rectangles appear on the chart. Of course, I would like to learn how to code it in Meta Editor.

It looks a bit like "zone" than normal rectangle, cause they have to stretch until one of future bars will break it through.

Any form of help is welcome, thanks in advance.

Regards,

d.

 

Start by learning to code in MQL with examples.

There are many publications in the CodeBase, so search there for something similar to what you want, then study the code while referencing the MQL documentation.

Once you understand how it works, make a few minor changes to adapt its functionality. Repeat the process and gradually modify it until it does what you want.

 
djarturos:

Hello, I need some help.

Like in the topic's title, I want to rectangles appear on the chart. Of course, I would like to learn how to code it in Meta Editor.

These rectangles should start when, after 2 bars of one kind (e.g. 2 bear bars) 1 opposite (bull) bar will appear and after it, again 2 bear bars. And every single rectangle should start from OPEN and CLOSE point of the middle candle.

It looks a bit like "zone" than normal rectangle, cause they have to stretch until one of future bars will break it through.

Any form of help is welcome, thanks in advance.

Regards,

d.

Hi . 

Here is a starting example code to start from . 

#property copyright "Copyright 2099, The Clan of Marshmellow Eaters . Inc."
#property version   "1.00"
#property strict
/*
Let's start with the basics : You will need to build a function that tells you 
                              whether or not your candle pattern (2 same , 1 opposite , 2 same) is present in
                              a position on the chart

You already know this probably but imagine you are pointing at the righmost bar of the chart.
That is bar [0] . If you point one bar to the left (toward the past) you have bar[1] etc.
If a new bar opens (so the latest bar changes) that is again bar[0] so if you were to keep pointing
at the same bar as before you would be pointing at bar[2] now (it shifted one position to the left)
Why on earth does it matter ? In some cases it's helpful to see the "activity" of your code in the past
so , with that in mind let's create your function .
Let's do it the easy way first , or as they say in greece , the butcher's way (chop fast sell more)

You already know how functions work probably in case you don't :
we declare the type of the result followed by the name of the function and we enclose our parameters 
in parenthesis . so 
result_type name(parameters){}

We want to know if your pattern is present in the chart so the result type is a bool (true/false)

for the simple version , there will be no parameters 
so : 
*/
bool is_this_my_pattern_simple_version()
 {
 bool result=false;
 //as stated above imagine you are on bar [0] (which is the bar forming live)
 //bar[0] won't be part of your checks because you want fully formed bars
 //so the rightmost bar will be [1] and the leftmost will be [5] in your pattern
   //that means the first 2 leftmost bars (or the first 2 bars in the sequence of your pattern)
   //     are bars [5] and [4] 
   //lets deploy a check with [5] and [4] being bullish 
   //     bullish means the Close[of this bar] is > Open[of this bar]
   //check [5] and [4] then
       //condition a     +  condition b 
     if(Close[5]>Open[5] && Close[4]>Open[4])
       {
       //within the brackets of this if statement you do stuff when the above conditions are valid
         //you now have 5 and 4 , and they are bullish , you now need to see if 3 is bearish
           if(Close[3]<Open[3])//simple eh?
             {
             //you are getting used to this , what comes next : check [2] and [1] if they are bullish 
               if(Close[2]>Open[2] && Close[1]>Open[1])
                 {
                 //all your conditions are true that means the result is true
                   result=true;//done this will be returned to the place where your code called this function
                 }
             } 
       }
   //you can fill in the opposite senario of this check 
   
 return(result);
 }
/*
Okay you have the function but what good is it if it only checks the last 5 candles right ?
You can easily fix that :
   -Is there a way to know how many bars are on the chart ? yes
   -And is your pattern of a fixed size ? yes
   -Does that mean that you can scan the entire chart at the beggining and find your patterns ? yes
You just need to add 3 things :
   1.the starting point (from the left or the right , it will be easier to demonstrate from the right so we'll keep it this way)
   2.a price return of the open and close of the middle bar because that's what you'll need 
     down the line
   3.the type of the pattern based on the edge bars alignment 
     lets say type 1 if the edge bars [5][4][2][1] are bullish
     and      type 2 if the edge bars [5][4][2][1] are bearish
The function becomes something like this then :
*/
bool is_this_my_pattern(int rightmost_bar_of_the_pattern,//the rightmost bar for the check (imagine this is bar[1] in the simple version)
                        double &open_result,//the open price result , the & means the variable we send here will be filled with the open price
                        double &close_result,//the close price result 
                        int &type_result)//the type result
{
 bool result=false;
 type_result=0;//you could have also made the function return a number and be 0 if there is no pattern
     //so if [1] were the rightmost bar of the pattern , then [5] and [4] would be [righmost bar +4] and [rightmost bar +3]
     //but why type all that , lets call the righmost bar of the pattern x
       int x=rightmost_bar_of_the_pattern;
       //so [5]=[x+4] [4]=[x+3]
     if(Close[x+4]>Open[x+4] && Close[x+3]>Open[x+3])
       {
           // [3]=[x+2] 
           if(Close[x+2]<Open[x+2])
             {
             //[2]=[x+1] [1]=[x]
               if(Close[x+1]>Open[x+1] && Close[x]>Open[x])
                 {
                 //all your conditions are true that means the result is true
                   result=true;
                   //but we also need to return the open and close prices of the middle bar [x+2]
                   //so
                     //the open result 
                       open_result=Open[x+2];
                     //the close result
                       close_result=Close[x+2];
                     //and type 1 because the edges are bullish 
                       type_result=1;
                     //now at the point we call this function 
                     //if the result is true then we know 
                     //our price variables got filled , like in McDonalds 
                     //the client pushes the paper cup under the vending machine , it fills up with Coke (or pepsi)
                     //no push , no coke
                 }
             } 
       }
   //you can fill in the opposite senario of this check 
   
 return(result);
}
/*
That is it for detecting the pattern , let's see how you use it 
You probably considered this already , will i be checking for 
a pattern at each tick all the time ? 
The answer is , of course not !
You need a timestamp that shows you which bar was the last to be checked 
or a "barstamp" 
It stores time so its of type datetime 
so :
*/
datetime barstamp=0;//and at first its zero because you have not checked anything 
/*
aand you need to keep count of the rectangles you design , that is an integer :
*/
int rectangles_total=0;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
  //Your program starts here 
  //You reset the barstamp 
    barstamp=0;
  //reset the total rectangles 
    rectangles_total=0;
  /* now for demonstration and for not raising any -further- confusion 
     we will check the past now.
     That would be checked inside the indicators tick code , or , the first call 
     of the tick function here , or , within a timer but that will complicate things.
     If your connection is good enough and your chart has enough past data it will 
     do for this example so 
     How do you check the past ? 
     First you need to know how many bars exist in the past. 
     That is very straight forward : */
     int total_bars=Bars;
   /* but theres a bit you need to learn before moving on ,
      if we have one bar on the chart , so total_bars=1 , that is bar[0]
      So the first bar is [0] 
      Similarly if there were 2 bars in the chart (total_bars=2) [1][0] <-- like this 
      the oldest bar you could access would be [1]
      That means the last bar (oldest bar) you can access is total_bars-1
      But there's more.
      You will be checking for a 5 bar long pattern 
      and will be sending the rightmost bar of each check each time 
      so the checks must start from total_bars-1-5 */
     //so
     int check_from=total_bars-1-5;
     //and you will check up until the latest fully formed bar which is [1]
     //this assumes the chart has data , you will learn more as you go for the required checks
     //for now 
     int check_until=1;
     /*
     you have the start and end positions of your check 
     now you need to start checking bars one by one and 
     put the functions you built to use 
     But , you also need to be designing rectangles.
     These rectangles will be numbered , but its good to name them in a similar way to identify them 
     along with their numbering .
     And since we don't want to flood the chart with remnants of rectangles from previous runs 
     we think of a "tag" our objects are going to have ,lets say "PATTERN_".
     We call the mass object deleter command that deletes all "PATTERN_" objects (so if you reload the program the previous ones will be erased) 
     */ 
     ObjectsDeleteAll(ChartID(),"PATTERN_");//The ChartID() of this chart , and , the object tag for mass deletion
     /*
     The loop : 
     what this does is move from the check_from to the check_until and 
     keep the checked index at each time in i . So i points to the rightmost 
     bar of your pattern in the loop . See what you did there ? 
     so : 
     */
     for(int i=check_from;i>=check_until;i--)
      {
      /* essentially : the rightmost CHART bar is [0] , so the leftmost CHART bar will be >[0] 
                       we want to move from the past to the present 
                       so from a high index of a bar to a low index of a bar 
                       so we need to decrease at each loop (hence i--)
                       so as long as i is bigger or equal than check_until we keep decreasing and executing
                       the code within the brackets
                       */
      /* recall the function you build earlier , you know it has to return 
         the open price the close price and wether or not it found anything 
         and the type of the pattern 
         We prepare the equivalents of the result parameters we'll send*/
      //the open price 
        double open_price=0.0;
      //the close price 
        double close_price=0.0;
      //the pattern type 1 for bullish edges 2 for bearish edges (when you code it ;))
        int pattern_type=0;
      //where is the bool ? , the bool will be used to control access to the "drawing" like this 
      //you ask the program to only execute the code if the function you request returns true
        if(is_this_my_pattern(i,open_price,close_price,pattern_type))
        {
        /*
        simple eh? 
        if you get within these brackets you have 
        the pattern type 
        an open price 
        and a close price at your disposal
        And in these brackets you can draw ! 
        so lets draw the rectangle , at first they will span the entire pattern , just for show.
        The x axis of the chart is time and the y axis of the chart is price 
        open and close prices are your y axis coordinates you need the x axis , so ,
        for this version of the code you need the first pattern time and the last pattern time .
        so :
        */
        datetime start_time=0;
        datetime end_time=0;
        /*
        okay , now recall the rightmost bar of your pattern sits at i so you assign that to...
        the end time correct 
        */
        end_time=Time[i];
        /*
        and your pattern is 5 bars wide , including i , so the leftmost bar will be at i+4 
        you assign that time to the start time 
        */
        start_time=Time[i+4];
        //you will be creating a new rectangle so you increase the count
        rectangles_total=rectangles_total+1;//or rectangles_total++;
          /*
          the rectangle will be named PATTERN_ and the number of the rectangle 
          so you turn the integer type to text with integer to string and you splice it 
          in the "PATTERN_"
          so you get PATTERN_1 PATTERN_2 etc
          */
          string the_rectangles_name="PATTERN_"+IntegerToString(rectangles_total);
        //and you create it 
          ObjectCreate(ChartID(),the_rectangles_name,OBJ_RECTANGLE,0,start_time,open_price,end_time,close_price);
        //awesome , how about some styling ? lets say if its type 1 its green if its type 2 its red
          //we need a color for that 
            color rectangle_color=clrGreen;//we set the color to green
            //and if the pattern type is 2 we change it to red !
            if(pattern_type==2){rectangle_color=clrRed;}
          //and of course we need to tell Meta trader that we want to paint this box so :
            ObjectSetInteger(ChartID(),the_rectangles_name,OBJPROP_BGCOLOR,rectangle_color);          
        }
      //update the last checked time 
        barstamp=Time[i];
      }
  return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
  /*
  Now the program is live , when do you check ???
  If you were to check the latest 5 bars (that are formed) your rightmost bar 
  would be at [1] right ? yes
  And in your initial checks ,the last rightmost bar you checked gave its time in barstamp.
  That means that if the time at [1] is bigger than the last time you checked , you have a new set of bars 
  that can be your pattern so : 
  */
  if(Time[1]>barstamp)
  {
  //first thing you do is store the new barstamp 
    barstamp=Time[1];
  //and then you do as you did in the past check , but send 1 instead of i
        //your result variables
        double open_price=0.0;
        double close_price=0.0;
        int pattern_type=0;
        //the call and check with 1 as the righmost bar instead of i
        if(is_this_my_pattern(1,open_price,close_price,pattern_type))
        {
        datetime start_time=Time[5];
        datetime end_time=Time[1];
        rectangles_total=rectangles_total+1;//or rectangles_total++;
        string the_rectangles_name="PATTERN_"+IntegerToString(rectangles_total);
        ObjectCreate(ChartID(),the_rectangles_name,OBJ_RECTANGLE,0,start_time,open_price,end_time,close_price);
        color rectangle_color=clrGreen;//we set the color to green
        if(pattern_type==2){rectangle_color=clrRed;}
        ObjectSetInteger(ChartID(),the_rectangles_name,OBJPROP_BGCOLOR,rectangle_color);          
        }    
  }
   
  }
 
Lorentzos Roussos #:

Hi . 

Here is a starting example code to start from . 

Thank you very much! I will read it carefully and try to create something. 
 
Okay, here is the code after little changes.
#property copyright "Copyright 2099, The Clan of Marshmellow Eaters . Inc."
#property version   "1.00"
#property strict

bool myown_pattern(int rightmost_bar_of_the_pattern,
                        double &open_result,
                        double &close_result,
                        int &type_result)
{
 bool result=false;
 type_result=0;
       int x=rightmost_bar_of_the_pattern;
       //so [5]=[x+4] [4]=[x+3]
     if(Close[x+4]>Open[x+4] && Close[x+3]>Open[x+3])
       {
           // [3]=[x+2] 
           if(Close[x+2]<Open[x+2])
             {
             //[2]=[x+1] [1]=[x]
               if(Close[x+1]>Open[x+1] && Close[x]>Open[x])
                 {
                   result=true; 
                       open_result=Open[x+2];
                       close_result=Close[x+2]; 
                       type_result=1;
                 }
             } 
       }
       
       if(Close[x+4]<Open[x+4] && Close[x+3]<Open[x+3])
       {
           // [3]=[x+2] 
           if(Close[x+2]>Open[x+2])
             {
             //[2]=[x+1] [1]=[x]
               if(Close[x+1]<Open[x+1] && Close[x]<Open[x])
                 {
                   result=true;
                       open_result=Open[x+2];
                       close_result=Close[x+2];
                       type_result=2;
                 }
             } 
       } 
   
 return(result);
}

datetime barstamp=0;
int rectangles_total=0;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
    barstamp=0;
    rectangles_total=0;
     int total_bars=Bars;
     int check_from=total_bars-1-5; 
     int check_until=1;
     ObjectsDeleteAll(ChartID(),"PATTERN_");
     for(int i=check_from;i>=check_until;i--)
      {
        double open_price=0.0;
      //the close price 
        double close_price=0.0;
        int pattern_type=0;
        if(myown_pattern(i,open_price,close_price,pattern_type))
        {
        datetime start_time=0;
        datetime end_time=0;
        end_time=Time[i];
        start_time=Time[i+4];
        rectangles_total=rectangles_total+1;
          string the_rectangles_name="PATTERN_"+IntegerToString(rectangles_total);
          ObjectCreate(ChartID(),the_rectangles_name,OBJ_RECTANGLE,0,start_time,open_price,end_time,close_price); 
            color rectangle_color=clrGreen;
            if(pattern_type==2){rectangle_color=clrRed;}
            ObjectSetInteger(ChartID(),the_rectangles_name,OBJPROP_COLOR,rectangle_color);          
        }
        barstamp=Time[i];
      }
  return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {

  if(Time[1]>barstamp)
  {

    barstamp=Time[1];

        double open_price=0.0;
        double close_price=0.0;
        int pattern_type=0;
        
        if(myown_pattern(1,open_price,close_price,pattern_type))
        {
        datetime start_time=Time[5];
        datetime end_time=Time[1];
        rectangles_total=rectangles_total+1;
        string the_rectangles_name="PATTERN_"+IntegerToString(rectangles_total);
        ObjectCreate(ChartID(),the_rectangles_name,OBJ_RECTANGLE,0,start_time,open_price,end_time,close_price);
        color rectangle_color=clrGreen;
        if(pattern_type==2){rectangle_color=clrRed;}
        ObjectSetInteger(ChartID(),the_rectangles_name,OBJPROP_COLOR,rectangle_color);          
        }    
  }
   
  }
It shows rectangles but they don't start from middle bar and of course they end on rightmost bar on the chart only.
 
djarturos #:
Okay, here is the code after little changes. It shows rectangles but they don't start from middle bar and of course they end on rightmost bar on the chart only.

Awesome 

 

Here is the next step , there are some gaps it wont work immediately but you'll find them :) cheers .

#property copyright "Copyright 2099, The Clan of Marshmellow Eaters . Inc."
#property version   "1.00"
#property strict

/*
Before you turn this to an indicator you can add the checks required to 
allow your rectangles to extend until they are breached
To do this you will need a list , so first let's take a quick look at that 
Lets say you have 3 people Mike John and Pamela , you are at the door of a room
and you need to log who is in the room at all times .
At first you need the "room" . If you know your "room" can hold up to 5 guests then
you can declare it like that (with 5 positions) 
*/
string guests[5];
/*
this means you can log up to 5 guests , and this is an array 
But what if you don't know how many people are coming and your room has a lot of space ? 
Then you use a dynamic array . so your guest list would look like this 
*/
string more_guests[];
/*
[] brackets to denote a "list" and no number to denote its dynamic and its size will change
So let's assume Pamela shows up , you will need to :
1.get the current size of your list
2.increase it by 1
3.add Pamela to the new slot 
4.you can then return the index of Pamela in the list , or the new size of the list
! like with bars if you have 1 person in your list that person will be in position [0] 
  so the last person in your list is [persons_total-1]
your add function looks like this , straight forward commands luckily.
*/
int add_to_guests(string name_of_new_guest,//the name of the new guest 
                  string &list_to_add_them_into[]){//and the list you want them to be added in ! (so you can reuse it)
int new_size_of_list=ArraySize(list_to_add_them_into);//get the size of the list you want to add them to
    new_size_of_list++;//increase by one 
ArrayResize(list_to_add_them_into,new_size_of_list,0);//expand the list
list_to_add_them_into[new_size_of_list-1]=name_of_new_guest;//and add them to the new position (-1 from total)
//and return the index you added them into to the caller 
return(new_size_of_list-1);    
}
/* piece of cake 
Now what if you want to find someone in the list ?
*/
int find_in_list(string find_who,//the person (or attribute) of what you are looking for
                 string &list_to_lookup[]){//the list you want to check for whether or not they are in 
int found_in=-1;//we reset the found index , so if the caller receives -1 they know nothing was found
//and you simply loop into the list until you hit a match 
  for(int i=0;i<ArraySize(list_to_lookup);i++){
  //easy right ? go into list_to_lookup elements , the index is i and ...
    if(list_to_lookup[i]==find_who){//if the name in the list matches the name we want 
    //we set the found index 
      found_in=i;//as i which is the current index in the loop that matched 
      //and we exit the loop
        break;
    }
  }
//and finally we send what we found , or did not find , to the caller
return(found_in);
}
/* lastly , you may want to remove from a list 
   you will receive an index to remove in the list 
   so :
   1.you get the size of the list 
   2.you reduce it by 1 but don't resize the list yet
   3.you move whatever is in the last position of the list to the position
     you want to remove (overwriting it)
   4.you apply the list size reduction 
   and voilla , you erased an entry from the list
*/
int remove_from_list(int remove_which_index,//the index to be removed 
                     string &the_list[]){//the list
//get the size of the list and reduce by 1
  int new_size=ArraySize(the_list)-1;
//flip the last and the removed positions 
  the_list[remove_which_index]=the_list[new_size];//this is actually the last position which would be total-1 anyway but we have not resized the list yet so it applies to the previous size
//resize the list , caution here you might hit zero size ! so 
  if(new_size>0){//if the new size is > zero
  ArrayResize(the_list,new_size,0);//resize the list
  }
  else{//otherwise free the list
  ArrayFree(the_list);
  }
//and return the new size to the caller 
return(new_size);
}
/* now you can also mix and match 
lets say you want to find a person and delete it 
*/
void search_and_destroy(string for_whom,string &in_list[]){
//you call your finder here 
  int found_in=find_in_list(for_whom,in_list);
  //you send the parameters and receive the result in "found_in" 
  //if its -1 it means that person is not in the list but if not it means they are 
  //hence the following check
    if(found_in!=-1){//if its not -1
    //call the removal function because you now know the index !
      remove_from_list(found_in,in_list);//you don't need the result of that operation
    //and done with lists 
    }
}
/*
So , back to the point .
You need to store your rectangles so that you know :
    a.when they are breached
    b.where they are breached 
    c.display them properly 
therefore you need to store :
    their open and close prices
    their start time 
    their end time 
    their type (1,2)
That means you need 5 lists of the following types :
*/
double open_prices[];
double close_prices[];
datetime start_times[];
datetime end_times[];//no pun
int types[];
/*
but also , thinking ahead you realise you also need to remember which object is 
 "tethered" to what entry so 
*/
string object_tethers[];
/*
and all these lists will 
-work in parallel 
-be maintained 
-contain only the rectangles that are still in play 
So are we going to create functions for each type ?
Nope , we'll jump straight into the deep and create 
your own custom object .
You have an "item" that can be characterized (or identified) by these 5 traits :
 -open price
 -close price
 -start time
 -end time
 -type
 -tethered object
You can declare that , and its functions 
So lets call that "item" a pattern rectangle and add the features 
*/
struct a_pattern_rectangle{
double open_price;
double close_price;
datetime start_time;
datetime end_time;
int type;
string tether;
       /*
       this means you now have your own data type 
       So the same way you would initialize a text variable like so :
       string my_text="michael";
       you will now be able to initialize a pattern rectangle like so :
       a_pattern_rectangle box;
       same thing 
       type variable_name
       you can also decide what the default values are goind to be 
       whenever a variable of "your type" is spawned.
       This is called a constructor . 
       You don't need it currently but it would look like this : 
       */
       a_pattern_rectangle(void){
       open_price=0.0;
       close_price=0.0;
       start_time=0;
       end_time=0;
       type=0;
       tether=NULL;
       }
       /*
       so whenever you created a_pattern_rectangle , it would have these features as defaults 
       But its not required yet so , what would you need ? a set function that changes
       all the features at once , for when you first create your rectangles so : 
       of type void because you don't return anything to the caller 
       */
  void set(double _new_open_price,//the new open price 
           double _new_close_price,//the new close price
           datetime _new_start_time,//the new start time 
           datetime _new_end_time,//the new end time 
           int _new_type,//the type of the pattern
           string _new_tether){//and the new object tether name 
       //and you just pass them into your item 
       open_price=_new_open_price;
       close_price=_new_close_price;
       start_time=_new_start_time;
       end_time=_new_end_time;
       type=_new_type;
       tether=_new_tether;
       //so handy eh ? all in one call 
       }
       /*
       Let's take a pause then , we have your new variable type 
       it has all the features we need 
       we can set all its parameters at once okay .. but 
       we also need to update its end_time , if it is not breached yet.
       Can't it be done by simple passing it in the end_time ? yes 
       but we want something more complete .See we stored the object tether
       so what if you send the new end time and it automatically 
       updates the object too ? neat right ? so : 
       */
  void update_end(datetime _new_end_time){//just the new end time , that is all you need
       //pass it in 
         end_time=_new_end_time;
       //you know the object name ! so update its second time !
         ObjectSetInteger(ChartID(),tether,OBJPROP_TIME2,end_time);
       //done
       }
       /* almost there , what else would be handy if it were """automated""" ?
          how about the check for whether or not the pattern is broken ?
          Well what would we need to send in order to check , given we don't know 
          what type of pattern it is and we'd like to accomodate both types ?
          we can send the high and the low of a bar , these are the edge prices 
          of a bar , and , if we are checking a pattern it means it has not been
          breached yet (its rectangle) so it works for us . 
          And we also require the time why ? to know where to end the rectangle 
          But remember that we can remove from lists too because we are super coders so 
          what if we also return whether or not (true/false) a removal is required from 
          the list this rectangle will be on ? That would be mega handy right ? so : 
       */
  bool check_me(double _high_of_bar,//the high price of a bar 
                double _low_of_bar,//the low price of a bar 
                datetime _time_of_bar){//the time of a bar 
       bool remove_me=false;//we set the removal flag to false 
       /*
       Now what ? 
       We know the prices of the box , and its type 
       type 1 is when the edges are bullish 
       so if type of the pattern (of the rectangle item) is 1
       */
       if(type==1)
         {
         //then we will kill this box if the price goes below the top price 
         //but which price is the top price ? 
           double top_price=MathMax(open_price,close_price);
         //next , which price are we comparing with ? 
         //we are above the box so we use the low 
           //so if the low breaks below the top price we kill the box , easy stuff right ?
             if(_low_of_bar<top_price){//you could also say <= top price 
             remove_me=true;//light up the removal flag
             //set the new end time by using the handy function we built above 
               update_end(_time_of_bar);
             //and that means the rectangle display has been updated 
             }
         }
       //similarly if the box is type 2 bearish edges 
       else if(type==2)
         {
         //you'll do the rest in here ;)      
         }
       /*
       at this point we are done with the variable type 
       all else will be taken care of on the list of these items 
       */      
       return(remove_me);
       }
};
/*
Now we could go ahead and create another object which has these objects inside and manages them 
but for simplicity sake we will just replicate the list management functions but with the new 
order type so first we will need a permanent list of your variable type :
*/
a_pattern_rectangle myBoxes[];//and its a dynamic list 
//what comes first ? adding to the list 
//similarly as above but we send the feature of the box in the add call , instead of the one name which was the only feature in the guests example
//so : 
int add_a_box(a_pattern_rectangle &box_list[],//first the boxes list we are going to add the box to 
              double _new_open_price,//then the features , this resembles the set function above 
              double _new_close_price,
              datetime _new_start_time,
              datetime _new_end_time,
              int _new_type,
              string _new_tether){
//this is the easy one i'll let you do it ;) 
return(-1);
}
//we wont need to find any boxes in this program , luckily ... :P 
//but we will remove so :
int remove_box(a_pattern_rectangle &from_this_box_list[],//the box list to remove the box from
               int box_position_to_remove){//the position of the box we want to remove
               //just like in the example then 
//get the size of the list and reduce by 1
  int new_size=ArraySize(from_this_box_list)-1;
//flip the last and the removed positions 
  from_this_box_list[box_position_to_remove]=from_this_box_list[new_size];//this is actually the last position which would be total-1 anyway but we have not resized the list yet so it applies to the previous size
//resize the list , caution here you might hit zero size ! so 
  if(new_size>0){//if the new size is > zero
  ArrayResize(from_this_box_list,new_size,0);//resize the list
  }
  else{//otherwise free the list
  ArrayFree(from_this_box_list);
  }
//and return the new size to the caller 
return(new_size); 
}
//and finally we will need to manage the list of the boxes 
/*
so when will we manage the list ? 
On each new bar , including the bars of the past 
So again what data points are we going to need ?
the high , low and time of the recently formed bar 
so here goes :
*/
void manage_boxes(a_pattern_rectangle &of_this_list[],//right ? the list of the boxes to manage
                  double _bar_high,//the high of the recently formed bar 
                  double _bar_low,//the low of the recently formed bar 
                  datetime _bar_time){//and the time of the recently formed bar
/*
we will be removing boxes so we will check from the bottom to the top 
so that we don't skip a check after a removal (You can think why that is)

*/
//set the loop start then , recall that items start from [0] and not [1] so they end at [total_items-1] 
//that is our start 
  int from=ArraySize(of_this_list)-1;//the size of this list -1 , which is the last item 
  //and we will loop until we hit 0 (the first item) reducing the position checked at each step
    for(int i=from;i>=0;i--)
    {
    //what do we do now ? call the check and receive whether or not we need to remove the box from the list 
      bool remove_this=of_this_list[i].check_me(_bar_high,_bar_low,_bar_time);
      //should we remove this ?
        if(remove_this)
          {
          //and we know its index , its i , so remove i from the list ,kidsplay  
            remove_box(of_this_list,i);
            //the box is removed from the list 
            //it's display is updated automatically 
            //and done ... that's it 
            //notice how the more work we do on the foundation 
            //the less and cleaner the code looks at the top
          }
    }
}

bool myown_pattern(int rightmost_bar_of_the_pattern,
                        double &open_result,
                        double &close_result,
                        int &type_result)
{
 bool result=false;
 type_result=0;
       int x=rightmost_bar_of_the_pattern;
       //so [5]=[x+4] [4]=[x+3]
     if(Close[x+4]>Open[x+4] && Close[x+3]>Open[x+3])
       {
           // [3]=[x+2] 
           if(Close[x+2]<Open[x+2])
             {
             //[2]=[x+1] [1]=[x]
               if(Close[x+1]>Open[x+1] && Close[x]>Open[x])
                 {
                   result=true; 
                       open_result=Open[x+2];
                       close_result=Close[x+2]; 
                       type_result=1;
                 }
             } 
       }
       
       if(Close[x+4]<Open[x+4] && Close[x+3]<Open[x+3])
       {
           // [3]=[x+2] 
           if(Close[x+2]>Open[x+2])
             {
             //[2]=[x+1] [1]=[x]
               if(Close[x+1]<Open[x+1] && Close[x]<Open[x])
                 {
                   result=true;
                       open_result=Open[x+2];
                       close_result=Close[x+2];
                       type_result=2;
                 }
             } 
       } 
   
 return(result);
}

datetime barstamp=0;
int rectangles_total=0;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
    barstamp=0;
    rectangles_total=0;
     int total_bars=Bars;
     int check_from=total_bars-1-5; 
     int check_until=1;
     ObjectsDeleteAll(ChartID(),"PATTERN_");
     for(int i=check_from;i>=check_until;i--)
      {
      //we run a lil check on our boxes list 
        manage_boxes(myBoxes,High[i],Low[i],Time[i]);//we send the data of the recently formed bar
        double open_price=0.0;
      //the close price 
        double close_price=0.0;
        int pattern_type=0;
        if(myown_pattern(i,open_price,close_price,pattern_type))
        {
        datetime start_time=0;
        datetime end_time=0;
        end_time=Time[i];//the end time is i , and it will expand later
        start_time=Time[i+2];//the start time is the middle bar so i+2
        rectangles_total=rectangles_total+1;
          string the_rectangles_name="PATTERN_"+IntegerToString(rectangles_total);
          ObjectCreate(ChartID(),the_rectangles_name,OBJ_RECTANGLE,0,start_time,open_price,end_time,close_price); 
            color rectangle_color=clrGreen;
            if(pattern_type==2){rectangle_color=clrRed;}
            ObjectSetInteger(ChartID(),the_rectangles_name,OBJPROP_COLOR,rectangle_color);          
        //the addition here is we create a new object in our list 
          /*
          we send all the parameters we just found and we log it in our list so that 
          we can check it later on 
          */
          add_a_box(myBoxes,open_price,close_price,start_time,end_time,pattern_type,the_rectangles_name);
        }
        barstamp=Time[i];
      }
  return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {

  if(Time[1]>barstamp)
  {

    barstamp=Time[1];

        double open_price=0.0;
        double close_price=0.0;
        int pattern_type=0;
        
        if(myown_pattern(1,open_price,close_price,pattern_type))
        {
        datetime start_time=Time[5];
        datetime end_time=Time[1];
        rectangles_total=rectangles_total+1;
        string the_rectangles_name="PATTERN_"+IntegerToString(rectangles_total);
        ObjectCreate(ChartID(),the_rectangles_name,OBJ_RECTANGLE,0,start_time,open_price,end_time,close_price);
        color rectangle_color=clrGreen;
        if(pattern_type==2){rectangle_color=clrRed;}
        ObjectSetInteger(ChartID(),the_rectangles_name,OBJPROP_COLOR,rectangle_color);          
        }    
  }
   
  }

 
Lorentzos Roussos #:

Here is the next step , there are some gaps it wont work immediately but you'll find them :) cheers .

Okay, thanks , challenge accepted:)
 
djarturos #:
Okay, thanks , challenge accepted:)

Awesome ++


 
For that moment it looks like:
#property copyright "Copyright 2099, The Clan of Marshmellow Eaters . Inc."
#property version   "1.00"
#property strict

string guests[5];
string more_guests[];

int add_to_guests(string name_of_new_guest,
                  string &list_to_add_them_into[]){
int new_size_of_list=ArraySize(list_to_add_them_into);
    new_size_of_list++; 
ArrayResize(list_to_add_them_into,new_size_of_list,0);
list_to_add_them_into[new_size_of_list-1]=name_of_new_guest;
return(new_size_of_list-1);    
}

int find_in_list(string find_who,
                 string &list_to_lookup[]){ 
int found_in=-1;
  for(int i=0;i<ArraySize(list_to_lookup);i++){
    if(list_to_lookup[i]==find_who){
      found_in=i;
        break;
    }
  }
return(found_in);
}

int remove_from_list(int remove_which_index,
                     string &the_list[]){
  int new_size=ArraySize(the_list)-1;
  the_list[remove_which_index]=the_list[new_size];
  if(new_size>0){
  ArrayResize(the_list,new_size,0);
  }
  else{
  ArrayFree(the_list);
  }
return(new_size);
}

void search_and_destroy(string for_whom,string &in_list[]){
  int found_in=find_in_list(for_whom,in_list);
    if(found_in!=-1){
      remove_from_list(found_in,in_list);
    }
}

double open_prices[];
double close_prices[];
datetime start_times[];
datetime end_times[];
int types[];

string object_tethers[];
struct a_pattern_rectangle{
double open_price;
double close_price;
datetime start_time;
datetime end_time;
int type;
string tether;

       a_pattern_rectangle(void){
       open_price=0.0;
       close_price=0.0;
       start_time=0;
       end_time=0;
       type=0;
       tether=NULL;
       }

  void set(double _new_open_price,
           double _new_close_price,
           datetime _new_start_time,
           datetime _new_end_time, 
           int _new_type,
           string _new_tether){
       open_price=_new_open_price;
       close_price=_new_close_price;
       start_time=_new_start_time;
       end_time=_new_end_time;
       type=_new_type;
       tether=_new_tether;
       }

  void update_end(datetime _new_end_time){
         end_time=_new_end_time;
         ObjectSetInteger(ChartID(),tether,OBJPROP_TIME2,end_time);
       //done
       }
       
  bool check_me(double _high_of_bar,
                double _low_of_bar,
                datetime _time_of_bar){
       bool remove_me=false;

       if(type==1)
         {
           double top_price=MathMax(open_price,close_price);
             if(_low_of_bar<top_price){
             remove_me=true; 
               update_end(_time_of_bar);
             }
         }

       else if(type==2)
         {     
         }     
       return(remove_me);
       }
};

a_pattern_rectangle myBoxes[];

int add_a_box(a_pattern_rectangle &box_list[], 
              double _new_open_price, 
              double _new_close_price,
              datetime _new_start_time,
              datetime _new_end_time,
              int _new_type,
              string _new_tether){
return(-1);
}

int remove_box(a_pattern_rectangle &from_this_box_list[],
               int box_position_to_remove){

  int new_size=ArraySize(from_this_box_list)-1;

  if(new_size>0){
  ArrayResize(from_this_box_list,new_size,0);
  }
  else{
  ArrayFree(from_this_box_list);
  }
return(new_size); 
}

void manage_boxes(a_pattern_rectangle &of_this_list[],
                  double _bar_high, 
                  double _bar_low,
                  datetime _bar_time){

  int from=ArraySize(of_this_list)-1;
    for(int i=from;i>=0;i--)
    { 
      bool remove_this=of_this_list[i].check_me(_bar_high,_bar_low,_bar_time);
        if(remove_this)
          {  
          }
    }
}

bool myown_pattern(int rightmost_bar_of_the_pattern,
                        double &open_result,
                        double &close_result,
                        int &type_result)
{
 bool result=false;
 type_result=0;
       int x=rightmost_bar_of_the_pattern;
     if(Close[x+4]>Open[x+4] && Close[x+3]>Open[x+3])
       { 
           if(Close[x+2]<Open[x+2])
             {
               if(Close[x+1]>Open[x+1] && Close[x]>Open[x])
                 {
                   result=true; 
                       open_result=Open[x+2];
                       close_result=Close[x+2]; 
                       type_result=1;
                 }
             } 
       }
       
       if(Close[x+4]<Open[x+4] && Close[x+3]<Open[x+3])
       {
           if(Close[x+2]>Open[x+2])
             {
               if(Close[x+1]<Open[x+1] && Close[x]<Open[x])
                 {
                   result=true;
                       open_result=Open[x+2];
                       close_result=Close[x+2];
                       type_result=2;
                 }
             } 
       } 
   
 return(result);
}

datetime barstamp=0;
int rectangles_total=0;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
    barstamp=0;
    rectangles_total=0;
     int total_bars=Bars;
     int check_from=total_bars-1-5; 
     int check_until=1;
     ObjectsDeleteAll(ChartID(),"PATTERN_");
     for(int i=check_from;i>=check_until;i--)
      { 
        manage_boxes(myBoxes,High[i],Low[i],Time[i]);
        double open_price=0.0; 
        double close_price=0.0;
        int pattern_type=0;
        if(myown_pattern(i,open_price,close_price,pattern_type))
        {
        datetime start_time=0;
        datetime end_time=0;
        end_time=Time[i];
        start_time=Time[i+2];
        rectangles_total=rectangles_total+1;
          string the_rectangles_name="PATTERN_"+IntegerToString(rectangles_total);
          ObjectCreate(ChartID(),the_rectangles_name,OBJ_RECTANGLE,0,start_time,open_price,end_time,close_price); 
            color rectangle_color=clrGreen;
            if(pattern_type==2){rectangle_color=clrRed;}
            ObjectSetInteger(ChartID(),the_rectangles_name,OBJPROP_COLOR,rectangle_color);          
          add_a_box(myBoxes,open_price,close_price,start_time,end_time,pattern_type,the_rectangles_name);
        }
        barstamp=Time[i];
      }
  return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {

  if(Time[1]>barstamp)
  {

    barstamp=Time[1];

        double open_price=0.0;
        double close_price=0.0;
        int pattern_type=0;
        
        if(myown_pattern(1,open_price,close_price,pattern_type))
        {
        datetime start_time=Time[5];
        datetime end_time=Time[1];
        rectangles_total=rectangles_total+1;
        string the_rectangles_name="PATTERN_"+IntegerToString(rectangles_total);
        ObjectCreate(ChartID(),the_rectangles_name,OBJ_RECTANGLE,0,start_time,open_price,end_time,close_price);
        color rectangle_color=clrGreen;
        if(pattern_type==2){rectangle_color=clrRed;}
        ObjectSetInteger(ChartID(),the_rectangles_name,OBJPROP_COLOR,rectangle_color);          
        }    
  }
   
  }
 
Nice but what did you add ?  😂 😂
Reason: