Generic question about methods of counting fractals.

 
Hi, 

I have been using fractals and finding them in the chart by counting  i-- or i++ and also if(fractal != 0) depending on which fractals I'm looking for.
Although this method works, it creates a lot littered and requires duplication in other code sometimes.  

I am rethinking my code and I'm curious if guru coders would put this all in an array first and then count. 

I could put all UPPER_MODE fractals in an array and all LOWER_MODE fractals in an array and count to that index instead. Instead of worrying about !=0 each time, I would put all !=0 items in the array only that way I know they are all actual values of fractals. 
What do you think ? 

Is this a reasonable thing to do ? OR is this not something the pros would do. 

Please advise
Thanks
 
Your goal is to connect the upper fractals to the lower fractals ?
 
Lorentzos Roussos #:
Your goal is to connect the upper fractals to the lower fractals ?

Hi, thanks for the response. 

No lines just finding a particular fractal at a point such as the fractal just before MACD crossed and putting a text object there.  Or the one just after with a text object.  Or even the subsequent one after that if I want. 
Marking text objects like A,B,C wave type of thing. 

My current code works but seems littered was hoping to shorten it and get rid of what seems like almost redundant functions with the smallest exceptions. 
I'll post the code when I get back to my trading desk. 

Thanks
 


 

Here is the code. As you noticed the A_low(),A_high,B_low,B_high functions all need some counting of histogram to a point. Then I have to select the !=0 fractal

bool A_high()
   {
      { 
      if(!histo())
         {
         ObjectSet ("B1",OBJPROP_BGCOLOR,clrBlack); //up fibo turns black
         val1=0;
         for (int i=histodowncount; val1==0; i++)
            {
            val1=iFractals(NULL, 0, MODE_UPPER, i);
            A = val1;
            if(A!=0)
               {
               atime=Time[i];
               Print(atime);
               ObjectSet("B6",OBJPROP_BGCOLOR,clrRed);
               ObjectSet("B16",OBJPROP_TIME1,atime);
               ObjectSet("B16",OBJPROP_PRICE1,A);
               ObjectSet("B16",OBJPROP_ANCHOR,ANCHOR_LOWER);
               ObjectSetString(0,"B16",OBJPROP_TOOLTIP,"A High = "+DoubleToStr(A,4));
               //A_close=Close[i];
               //Print(A, " A high Located at bar ",i," atime = ",atime);
               //Print("A close = ",A_close);
               return(true);
               }
             }
            }
            else ObjectSet("B6",OBJPROP_BGCOLOR,clrBlack);
        }
    return(false);                 
   }
So instead of the for loop where I need !=0 values to find fractals I thought maybe UPPER_MODE in an array and LOWER_MODE fractals in another arrray might help me to easier select fractals by index as needed instead of this littered functions I have now. I was curious if this was a thing and if it might be a preferred method that coders would regularly use ? 

Thanks
 

I see , you can create a generic fractal finder and then step it in by calling it as many times as you need to get the fractals you need .

The comments explain the processes 

#property strict

int OnInit()
  {
  //test lets find the 3 first fractals
    fractal_info fA,fB,fC;
    //1st , can be anywhere before bar 1
    bool foundA=find_a_fractal_before_this_bar(0,1,true,true,3,3,0,0,3,fA);
    //we send before 0 because its non inclusive of the bar before 
      //if a is found 
        if(foundA){
        Print("Found A");
        //we look for the bar using the result's time before the new search 
        int aI=iBarShift(_Symbol,_Period,fA.time,true); 
        bool foundB=find_a_fractal_before_this_bar(aI,aI+1,true,true,3,3,0,0,3,fB);
        //if b is found 
          if(foundB){
          Print("Found B");
          //we look for the bar again using the result's time 
            int bI=iBarShift(_Symbol,_Period,fB.time,true);
            bool foundC=find_a_fractal_before_this_bar(bI,bI+1,true,true,3,3,0,0,3,fC);
            //if c is found 
              if(foundC){
              Print("Found C");
              //lets display the fractals (note if the fractal is type both we are not checking for that in the display
                createMark(fA.time,fA.price,clrOrange,2,"FractalA");
                createMark(fB.time,fB.price,clrOrange,2,"FractalB");
                createMark(fC.time,fC.price,clrOrange,2,"FractalC");
              }
          }
          
        }
         
//---
   return(INIT_SUCCEEDED);
  }

enum type_of_fractal{
fractal_void=0,//nothing
fractal_high=1,//high
fractal_low=2,//low
fractal_both=3//both (also known as headache)
};
struct fractal_info{
bool            valid;
datetime        time;
int             bar_index;//trust this only at the time of return ! If the asset changes bar when the result is returned this bar index is no longer valid! 
type_of_fractal type;
double          price,opposite_price;
double          price2,opposite_price2;//for headache fractals
                fractal_info(void){reset();}
               ~fractal_info(void){reset();}
           void reset(){
                time=0;
                type=fractal_void;
                price=0.0;//redundant
                price2=0.0;//
                opposite_price=0.0;
                opposite_price2=0.0;
                bar_index=-1;
                valid=false;
                }
           void set(datetime _time,type_of_fractal _type,double _price1,double _opposite_price1,double _price2,double _opposite_price2,int _i){
                valid=true;
                time=_time;
                type=_type;
                price=_price1;
                price2=_price2;
                opposite_price=_opposite_price1;
                opposite_price2=_opposite_price2;
                bar_index=_i;
                }
           void set(datetime _time,type_of_fractal _type,double _price,double _opposite_price,int _i){
                set(_time,_type,_price,_opposite_price,0.0,0.0,_i);
                }
          
                 
};

bool find_a_fractal_before_this_bar(int before_this_bar,//you want the fractal to be before this bar index 
                                    int latest_closed_bar_or_simulation_of,//the latest CLOSED bar , live or in simulation (its important to maintain symmetry past-future)
                                    bool allow_highs,//look for highs ?
                                    bool allow_lows,//look for lows ?
                                    int left_bars,//bars to the left of the fractal
                                    int right_bars,//bars to the right of the fractal
                                    int min_left_side,//minimum accepted left side size , OR , 0
                                    int min_right_side,//minimum accepted right side size , OR , 0 
                                    int max_equals,//max equal price skips
                                    fractal_info &result//we will send the results there
                                    ){
/*
fractals are ridiculously simple 
you want highs of bars to the left and highs of bars to the right of a bar to be below the high
for an up fractal 
and the opposite 
The only concern is the right bars you need to check.
  So if we were at bar [0] in live execution
  and we need to find fractals with 2 left bars and 2 right bars 
  the last right bar can be up to recent as bar [1] 
  So the first eligible bar for being a fractal is 
  Last Closed Bar + Right Bars , so [1+2] bar [3] (we add because mt4 has 0 to the right in the index of bars)
So latest closed bar or simulation of becomes the limit of our search to the right side 
we just need to remember that whichever bar we are testing in the past we are supposedly at the open price and open time
of that bar (in the simulation) so the most recent available bar (if said bar is X) would be X+1.
Before this bar and latest closed bar can be equal no issue there .
*/
//so , reset the result 
bool found=false;
result.reset();
//start searching 
  //lets declare the bar indexes in a simpler manner 
    //the "before this bar" turns to b
      int b=before_this_bar;
    //the "latest" turns to x
      int x=latest_closed_bar_or_simulation_of;
    //the bar to start from 
      int from=0;
      //so we need the first candidate to be up to x and before b non including b
      //If 1st candidate is at b+1 then 
        from=b+1; 
        //it must also have its last right side bar up to x
          if((x+right_bars)>from){from=x+right_bars;}
      //also if we reach the bars limit we must stop
        int bar_limit=Bars-2;
      //loop into bars 
        for(int i=from;i<=bar_limit;i++)
        {
        int equal_skips=0;
        bool eligible_high=false,eligible_low=false;
        //test high  
        if(allow_highs){
          eligible_high=true;
          double price=High[i];
          //keep tabs on the sides size 
            double max_right_side_size=0.0,max_left_side_size=0.0;
          //secondary loop into the bars surrounding our fractal candidate
          int test_from=i-right_bars;
          int test_to=i+left_bars;
          int test_nav=test_from;
          while(eligible_high&&test_nav<=test_to){
          //if this is not the same bar as i
            if(test_nav!=i){
            //if we are on the right side - accept only lower than i's high price
              if(test_nav<i)
                {
                if(High[test_nav]>=price){eligible_high=false;}
                //we check for the max distance to the right 
                  if((price-High[test_nav])>max_right_side_size){max_right_side_size=price-High[test_nav];}
                } 
            //if we are on the left side 
              else if(test_nav>i){
              //we can accept equals here up to the max allowed
                     if(High[test_nav]>price||(High[test_nav]==price&&equal_skips>=max_equals)){eligible_high=false;}
                else if(High[test_nav]==price&&equal_skips<max_equals){
                     //on equals we need to count the skip
                       equal_skips++;
                     //and extend the search area to the left 
                       test_to++;
                     }
              //we check for the max distance to the left
                if((price-High[test_nav])>max_left_side_size){max_left_side_size=price-High[test_nav];}                    
              }
            }
          //increase the test bar 
          test_nav++;
          } 
          //if eligible high , test the side sizes 
            if(eligible_high){
            if(min_left_side>0&&((int)(max_left_side_size/_Point))<min_left_side){eligible_high=false;}
            if(min_right_side>0&&((int)(max_right_side_size/_Point))<min_right_side){eligible_high=false;}
            }
        }//test high ends here
        //test low   
        if(allow_lows){
          eligible_low=true;
          double price=Low[i];
          //keep tabs on the sides size 
            double max_right_side_size=0.0,max_left_side_size=0.0;
          //secondary loop into the bars surrounding our fractal candidate
          int test_from=i-right_bars;
          int test_to=i+left_bars;
          int test_nav=test_from;
          while(eligible_low&&test_nav<=test_to){
          //if this is not the same bar as i
            if(test_nav!=i){
            //if we are on the right side - accept only higher than i's low price 
              if(test_nav<i)
                {
                if(Low[test_nav]<=price){eligible_low=false;}
                //we check for the max distance to the right 
                  if((Low[test_nav]-price)>max_right_side_size){max_right_side_size=Low[test_nav]-price;}
                } 
            //if we are on the left side 
              else if(test_nav>i){
              //we can accept equals here up to the max allowed
                     if(Low[test_nav]<price||(Low[test_nav]==price&&equal_skips>=max_equals)){eligible_low=false;}
                else if(Low[test_nav]==price&&equal_skips<max_equals){
                     //on equals we need to count the skip
                       equal_skips++;
                     //and extend the search area to the left 
                       test_to++;
                     }
              //we check for the max distance to the left
                if((Low[test_nav]-price)>max_left_side_size){max_left_side_size=Low[test_nav]-price;}                    
              }
            }
          //increase the test bar 
          test_nav++;
          } 
          //if eligible low , test the side sizes 
            if(eligible_low){
            if(min_left_side>0&&((int)(max_left_side_size/_Point))<min_left_side){eligible_low=false;}
            if(min_right_side>0&&((int)(max_right_side_size/_Point))<min_right_side){eligible_low=false;}
            }
        }//test low ends here        
        //if eligible high or eligible low bounce 
          if(eligible_high||eligible_low){
          if(eligible_high&&!eligible_low){
          result.set(Time[i],fractal_high,High[i],Low[i],i);
          }
          else if(eligible_high&&eligible_low){
          result.set(Time[i],fractal_both,High[i],Low[i],Low[i],High[i],i);//the high price is price 1 in both
          }
          else if(!eligible_high&&eligible_low){
          result.set(Time[i],fractal_low,Low[i],High[i],i);
          }
          found=true;
          break;
          }
        }
      //loop into bars ends here 
return(found);
}

void createMark(datetime time,double price,color clr,int width,string name){
ObjectCreate(ChartID(),name,OBJ_ARROW,0,time,price);
ObjectSetInteger(ChartID(),name,OBJPROP_COLOR,clr);
ObjectSetInteger(ChartID(),name,OBJPROP_WIDTH,width);
}