//+------------------------------------------------------------------+
//|          Adjustable Fractal Lines - Last Broken Only             |
//|                     Clean & Lightweight Version                  |
//+------------------------------------------------------------------+
#property strict
#property indicator_chart_window
#property indicator_buffers 0

//---- Inputs
extern int Maxbar = 2000;

//---- Adjustable fractal strength
extern int Fractal_Left_Bars  = 2;
extern int Fractal_Right_Bars = 2;

//---- Line settings
extern bool Extend_Line_to_Background = true;

extern color Up_Fractal_Line_Color    = Red;
extern int   Up_Fractal_Line_Width    = 1;
extern int   Up_Fractal_Line_Style    = STYLE_SOLID;

extern color Down_Fractal_Line_Color  = Blue;
extern int   Down_Fractal_Line_Width  = 1;
extern int   Down_Fractal_Line_Style  = STYLE_SOLID;

//+------------------------------------------------------------------+
//| INIT                                                             |
//+------------------------------------------------------------------+
int init()
{
   return(0);
}

//+------------------------------------------------------------------+
//| DEINIT                                                           |
//+------------------------------------------------------------------+
int deinit()
{
   for(int i=ObjectsTotal()-1; i>=0; i--)
   {
      string name = ObjectName(i);

      if(StringFind(name,"FractalLine_") == 0)
         ObjectDelete(name);
   }

   return(0);
}

//+------------------------------------------------------------------+
//| Upper Fractal                                                    |
//+------------------------------------------------------------------+
bool IsUpperFractal(int shift)
{
   if(shift < Fractal_Right_Bars)
      return(false);

   if(shift + Fractal_Left_Bars >= Bars)
      return(false);

   double price = High[shift];

   for(int i=1; i<=Fractal_Left_Bars; i++)
   {
      if(High[shift+i] >= price)
         return(false);
   }

   for(int i=1; i<=Fractal_Right_Bars; i++)
   {
      if(High[shift-i] > price)
         return(false);
   }

   return(true);
}

//+------------------------------------------------------------------+
//| Lower Fractal                                                    |
//+------------------------------------------------------------------+
bool IsLowerFractal(int shift)
{
   if(shift < Fractal_Right_Bars)
      return(false);

   if(shift + Fractal_Left_Bars >= Bars)
      return(false);

   double price = Low[shift];

   for(int i=1; i<=Fractal_Left_Bars; i++)
   {
      if(Low[shift+i] <= price)
         return(false);
   }

   for(int i=1; i<=Fractal_Right_Bars; i++)
   {
      if(Low[shift-i] < price)
         return(false);
   }

   return(true);
}

//+------------------------------------------------------------------+
//| START                                                            |
//+------------------------------------------------------------------+
int start()
{
   deinit();

   int maxBars = Maxbar;

   if(maxBars > Bars-10)
      maxBars = Bars-10;

   int bestStartBar = -1;
   int bestStopBar  = 999999;
   double bestLevel = 0;

   color bestColor = clrNONE;
   int bestWidth = 1;
   int bestStyle = STYLE_SOLID;
   string bestName = "";

   int stopBar;

   //========================================================
   // UPPER FRACTALS
   //========================================================
   for(int i=Fractal_Left_Bars;
       i<maxBars-Fractal_Right_Bars;
       i++)
   {
      if(!IsUpperFractal(i))
         continue;

      double level = High[i];

      stopBar = -1;

      for(int c=i; c>0; c--)
      {
         if((Open[c] < level && Close[c] > level) ||
            (Open[c] > level && Close[c] < level))
         {
            stopBar = c;
            break;
         }

         if(Open[c] <= level && Close[c] <= level &&
            Open[c-1] >= level && Close[c-1] >= level)
         {
            stopBar = c;
            break;
         }

         if(Open[c] >= level && Close[c] >= level &&
            Open[c-1] <= level && Close[c-1] <= level)
         {
            stopBar = c;
            break;
         }
      }

      if(stopBar >= 0 && stopBar < bestStopBar)
      {
         bestStopBar  = stopBar;
         bestStartBar = i;
         bestLevel    = level;
         bestColor    = Up_Fractal_Line_Color;
         bestWidth    = Up_Fractal_Line_Width;
         bestStyle    = Up_Fractal_Line_Style;
         bestName     = "UP";
      }
   }

   //========================================================
   // LOWER FRACTALS
   //========================================================
   for(int i=Fractal_Left_Bars;
       i<maxBars-Fractal_Right_Bars;
       i++)
   {
      if(!IsLowerFractal(i))
         continue;

      double level = Low[i];

      stopBar = -1;

      for(int c=i; c>0; c--)
      {
         if((Open[c] < level && Close[c] > level) ||
            (Open[c] > level && Close[c] < level))
         {
            stopBar = c;
            break;
         }

         if(Open[c] <= level && Close[c] <= level &&
            Open[c-1] >= level && Close[c-1] >= level)
         {
            stopBar = c;
            break;
         }

         if(Open[c] >= level && Close[c] >= level &&
            Open[c-1] <= level && Close[c-1] <= level)
         {
            stopBar = c;
            break;
         }
      }

      if(stopBar >= 0 && stopBar < bestStopBar)
      {
         bestStopBar  = stopBar;
         bestStartBar = i;
         bestLevel    = level;
         bestColor    = Down_Fractal_Line_Color;
         bestWidth    = Down_Fractal_Line_Width;
         bestStyle    = Down_Fractal_Line_Style;
         bestName     = "DN";
      }
   }

   //========================================================
   // DRAW ONLY THE MOST RECENTLY BROKEN FRACTAL
   //========================================================
   if(bestStartBar >= 0)
   {
      DrawLine(
         bestName,
         bestStartBar,
         bestStopBar,
         bestLevel,
         bestColor,
         bestWidth,
         bestStyle
      );
   }

   return(0);
}

//+------------------------------------------------------------------+
//| DRAW LINE                                                        |
//+------------------------------------------------------------------+
void DrawLine(string name,
              int startBar,
              int endBar,
              double price,
              color col,
              int width,
              int style)
{
   string objName = "FractalLine_" + name;

   if(ObjectFind(objName) >= 0)
      ObjectDelete(objName);

   ObjectCreate(objName,
                OBJ_TREND,
                0,
                Time[startBar], price,
                Time[endBar], price);

   ObjectSet(objName,OBJPROP_RAY,false);
   ObjectSet(objName,OBJPROP_COLOR,col);
   ObjectSet(objName,OBJPROP_WIDTH,width);
   ObjectSet(objName,OBJPROP_STYLE,style);
   ObjectSet(objName,OBJPROP_BACK,Extend_Line_to_Background);
}
//+------------------------------------------------------------------+