//+------------------------------------------------------------------+
//|                                             MainRS_Indicator.mq4 |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
// Version V3 is to fix and group fractal pt value with min 50pips distance

#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property description "Indicator to show Main Support and Resisitance Level"
#property strict
#property indicator_chart_window
/*
#property indicator_buffers 1
#property indicator_color1 Blue
#property indicator_color2 Red
*/
#define Confirm_Level 3
#define Up_Fractal   1
#define Down_Fractal  2
#define Combined_Up   4
#define Combined_Down  5
enum timeframe_display_option
   {
    Current = 0,
    PeriodM5 =5,
    PeriodM15 =15,
    PeriodM30 =30,
    PeriodH1 =60,
    PeriodH4 =240,
    PeriodD1 =1440,
    PeriodW1 =10080,
   };


double ExtMapBuffer1[];

extern int Show_Level_Limit = 15;         //Max Level to be display on chart
extern timeframe_display_option Level_of_TimeFrame=Current; //Option to display which timeframe level on chart
extern double          sensitvity = 15;     // Min distance between each RS level,input in pips values

double fractal;

//++++ These are adjusted for 5 digit brokers.
   int     pips2points;    // slippage  3 pips    3=points    30=points
   double  pips2dbl;       // Stoploss 15 pips    0.0015      0.00150
   int     Digitspips;    // DoubleToStr(dbl/pips2dbl, Digits.pips)
   
   string indId ="SR_"; 
   double FractalMode[];
   datetime FractalTime[];
   //-----------------------------------------------------------------
   //----------variable use inside function
   double Level; // level object value, use to reduce duplicate level
   string status;// level object mode, use to reduce duplicate level
   int mode;     // level object mode status
   color mark = clrRed;                 

   //--------------------------------------------------
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
//---- indicators
   
   SetIndexStyle(0,DRAW_NONE);
   SetIndexArrow(0,251);  //buffer 0 draw line not symbol
   SetIndexBuffer(0,ExtMapBuffer1);
   SetIndexEmptyValue(0,0.0);
 //  if(Level_of_TimeFrame!=0) // display current timeframe level if no specific timeframe choosen
 //  {Level_of_TimeFrame=Period();}
  
  
                                            
     if (Digits % 2 == 1)
     {      // DE30=1/JPY=3/EURUSD=5 forum.mql4.com/43064#515262
                pips2dbl    = Point*10; 
                pips2points = 10;   
                Digitspips = 1;
     } 
     else 
     {   pips2dbl    = Point;    
         pips2points =  1;   
         Digitspips = 0; 
     }
 
   
   sensitvity = sensitvity * pips2dbl;
   //Comment("Display Level distance = " + PriceToStr(sensitvity));


    return(0);

  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
  {
   DeleteAllObjects();
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
  {
   int counted_bars=IndicatorCounted();
   if(counted_bars > 0)       //---- the last calculated bar will be recalculated   
      counted_bars--;
   int limit = Bars - counted_bars-1;
   int show_line_count = 0;
   int thisbar=0;
 
   ArrayInitialize(FractalMode,0.0);
   ArrayResize(FractalMode,ArraySize(FractalMode)+limit);
   ArrayInitialize(FractalTime,0.0);
   ArrayResize(FractalTime,ArraySize(FractalTime)+limit);
//-------------------------------------------------------------------------------------------------  
//---- store fractal point to array   
//-------------------------------------------------------------------------------------------------  
   for(int i = Bars; i>0; i--)
   {
   fractal = iFractals(NULL, Level_of_TimeFrame, MODE_UPPER, i);
      if(fractal != 0)
     {   
      ExtMapBuffer1[i] = fractal;
      FractalMode[i] = Up_Fractal;
     }
   fractal = iFractals(NULL, Level_of_TimeFrame, MODE_LOWER, i);
       if(fractal != 0)
      {
      ExtMapBuffer1[i] = fractal;
      FractalMode[i] = Down_Fractal;

      }
   }      
//---------------------------------------------------------------------------------------------
//Display level
//---------------------------------------------------------------------------------------------    
   show_line_count=0;
    for (int b = 0; b<Bars; b++)
         {
         int find=0;
        
         if (ExtMapBuffer1[b]!=0 && show_line_count <Show_Level_Limit)
               {     
                        for (int i = ObjectsTotal() - 1;  i >= 0;  i--)//compare any duplicated price
                           {
                              string name = ObjectName(i);
                              if(StringSubstr(name, 0, StringLen(indId)) == indId) 
                                 {
                                 double old_price = ObjectGetDouble(0,name,OBJPROP_PRICE);
                                 double diff= MathAbs(old_price-ExtMapBuffer1[b]);
                                 CompareObjectValues( name, ExtMapBuffer1[b], FractalMode[b], mark);
                                       if (diff<sensitvity)
                                             {
                                              ObjectDelete(name);
                                              if(mode==3)break;
                                             }
                                 } 
                                 
                                             
                           }
                        for (int i = ObjectsTotal() - 1;  i >= 0;  i--)//find total created object
                           {   
                              string name = ObjectName(i);
                              if(StringSubstr(name, 0, StringLen(indId)) == indId) 
                              find++;
                           }          
                        if(find==0)
                        {
                                 if(FractalMode[b]==1)
                                    status="Up";
                                 if(FractalMode[b]==2)
                                    status="Down";
                               HLine("SR_"+status+ "#" +show_line_count +" = " +PriceToStr(ExtMapBuffer1[b])+ "  " + status ,ExtMapBuffer1[b], mark); 
                               show_line_count+1; 
                        }
                        if(find!=0)
                        {     if(mode==3)
                              mark=clrBlue;
                              if(mode!=3)
                              mark=clrRed;
                              show_line_count=find;
                              show_line_count++;
                              
                              HLine("SR_"+ status +"#" +show_line_count +" = " +PriceToStr(Level)+ "  " + mode ,Level, mark);  
                        }
              } 
              
          }
         
    
  //ChartRedraw(0);  
return(0);
   } 
void HLine(string name, double P0, color clr)
      {
          #define WINDOW_MAIN 0
    /**/  if (ObjectMove( name, 0, Time[0], P0 )){}
            else if(!ObjectCreate( name, OBJ_HLINE, WINDOW_MAIN, Time[0], P0 ))
                    Alert("ObjectCreate(",name,",HLINE) failed: ", GetLastError() );
          if (!ObjectSet(name, OBJPROP_COLOR, clr )) // Allow color change
                  Alert("ObjectSet(", name, ",Color) [1] failed: ", GetLastError() );
          if (!ObjectSetText(name, PriceToStr(P0), 10))
                     Alert("ObjectSetText(",name,") [1] failed: ", GetLastError());
}
void DeleteAllObjects()
{
   // Delete all objects created by the indicator
   for (int i = ObjectsTotal() - 1;  i >= 0;  i--)
   {
      string name = ObjectName(i);
      
      if (StringSubstr(name, 0, StringLen(indId)) == indId)
         ObjectDelete(name);
   }
}
 
string  PriceToStr(double p)
   {
    string pFrc = DoubleToStr(p, Digits);       
    if(Digitspips==0) 
      return(pFrc);
    string pPip = DoubleToStr(p, Digits-1);
    if (pPip+"0" == pFrc)       
      return(pPip);           
      return(pFrc);          
   }
int InitializeAll()
  {
   ArrayInitialize(ExtMapBuffer1,0.0);
   ArrayInitialize(FractalMode,0.0);
   ArrayInitialize(FractalTime,0.0);
//--- first counting position
   return(1);
  }  
//---------------------------------------------------------------------------------------------  
double Price(double Old, double New, int result)//1 return larger value, 2 return smaller value
   { 
   double value=0;
   if(result==1)
   value=MathMax(Old,New);
   if(result==2)
   value=MathMin(Old,New);
   return(value);
   }
//---------------------------------------------------------------------------------------------   
void CompareObjectValues(string name, double BufferValue, double BufferMode,color mark)// return new object valuse and mode status, BufferValue= ExtMapBuffer1[b], BufferMode= FractalMode[b]
 {                                                        //compare buffer new line with existing level line to reduce duplicate
   double old_price = ObjectGetDouble(0,name,OBJPROP_PRICE);
   double difference = MathAbs(old_price-BufferValue);
   int cases = status(name); // mode status of existing level
   
   
   
   
                   
                        if (StringSubstr(name, 0, StringLen(indId)) == indId)
                           {
                             
                             if (difference<=sensitvity)
                                 {
                                    if((BufferMode==1 && cases==1)   )
                                    {
                                    Level=BufferValue;
                                    if(old_price>BufferValue)
                                    Level=old_price;
                                    //Level = Price(old_price,BufferValue,2);
                                    status = "Combined_UP";
                                    mode=4;
                                    }
                                    if((BufferMode==1 && cases==4))
                                    {
                                    Level=BufferValue;
                                    if(old_price<BufferValue)
                                    Level=old_price;
                                    //Level = old_price;
                                    status = "Combined_UP";
                                    mode=4;
                                    }
                                    if((BufferMode==2 && cases==2))
                                    {
                                    Level=BufferValue;
                                    if(old_price<BufferValue)
                                    Level=old_price;
                                    //Level = Price(old_price,BufferValue,1);
                                    status = "Combined_Down";
                                    mode=5;
                                    }
                                    if(BufferMode==2 &&  cases==5)
                                    {
                                    Level=BufferValue;
                                    if(old_price<BufferValue)
                                    Level=old_price;
                                    //Level = old_price;
                                    status = "Combined_Down";
                                    mode=5;
                                    }
                                    if((BufferMode==1 && cases==2) ||(BufferMode==2 && cases==1))//retrace tested level, use lower value
                                    {
                                    Level = old_price;//Price(old_price,BufferValue,2);
                                    status = "Confirm_Level";
                                    mode=3;
                                    }
                                    if((BufferMode==1 && cases==5)|| (BufferMode==1 && cases==3))
                                    {
                                    Level = old_price;
                                    status = "Confirm_Level";
                                    mode=3;
                                    }
                                    if((BufferMode==2 && cases==4 )|| (BufferMode==2 && cases==3 ))
                                    {
                                    Level = old_price;
                                    status = "Confirm_Level";
                                   mode=3;
                                    }


                                  }
                               if (difference>sensitvity)
                                    {
                                       if(BufferMode==1)
                                       {
                                       Level = BufferValue;
                                       status = "Up";
                                       mode =1;
                                       }
                                       if(BufferMode==2)
                                       {
                                       Level = BufferValue;
                                       status = "Down";
                                       mode =2;
                                       }
                                    } 
                             }
 }    
 
 
 //------------------------------------------------------------------
 //return the mode status in existing level on chart
 int status(string name)
 {
    int cases = 0;
                                    if(StringSubstr(name, 3, 2) == "Up")
                                    cases=1;
                                    if(StringSubstr(name, 3, 4) == "Down")
                                    cases=2;
                                    if(StringSubstr(name, 3, 11) == "Combined_UP")
                                    cases=4;
                                    if(StringSubstr(name, 3, 13) == "Combined_Down")
                                    cases=5;
                                    if(StringSubstr(name, 3, 13) == "Confirm_Level")
                                    cases=3;
    return(cases);

 }                                   