//+------------------------------------------------------------------+
//|        Adjustable Fractal Lines - Dual Timeframe Version         |
//|           Last Broken Only | With TF Labels & Arrows             |
//+------------------------------------------------------------------+
#property strict
#property indicator_chart_window
#property indicator_buffers 0

//---- General
extern int Maxbar = 2000;

//---- Fractal strength
extern int Fractal_Left_Bars  = 2;
extern int Fractal_Right_Bars = 2;

//---- Line settings
extern bool Line_to_Background = true;

//==================================================================
// TIMEFRAME 1 - M30 (TOP)
//==================================================================
extern ENUM_TIMEFRAMES TF1_Period           = PERIOD_M30;

extern color TF1_Up_Line_Color             = Red;
extern int   TF1_Up_Line_Width             = 1;
extern int   TF1_Up_Line_Style             = STYLE_SOLID;

extern color TF1_Down_Line_Color           = Blue;
extern int   TF1_Down_Line_Width           = 1;
extern int   TF1_Down_Line_Style           = STYLE_SOLID;

//---- TF1 Label (text)
extern int    TF1_Label_FontSize           = 12;
extern color  TF1_Label_Color              = White;

//---- TF1 Arrow
extern int    TF1_Arrow_Code               = 0;    // 0=auto; SYMBOL_ARROWUP=241, SYMBOL_ARROWDOWN=242
extern int    TF1_Arrow_Size               = 2;
extern color  TF1_Arrow_Color              = Yellow;

//==================================================================
// TIMEFRAME 2 - H1 (BELOW)
//==================================================================
extern ENUM_TIMEFRAMES TF2_Period           = PERIOD_H1;

extern color TF2_Up_Line_Color             = Tomato;
extern int   TF2_Up_Line_Width             = 1;
extern int   TF2_Up_Line_Style             = STYLE_DASH;

extern color TF2_Down_Line_Color           = DodgerBlue;
extern int   TF2_Down_Line_Width           = 1;
extern int   TF2_Down_Line_Style           = STYLE_DASH;

//---- TF2 Label (text)
extern int    TF2_Label_FontSize           = 12;
extern color  TF2_Label_Color              = White;

//---- TF2 Arrow
extern int    TF2_Arrow_Code               = 0;    // 0=auto; SYMBOL_ARROWUP=241, SYMBOL_ARROWDOWN=242
extern int    TF2_Arrow_Size               = 2;
extern color  TF2_Arrow_Color              = Yellow;

//+------------------------------------------------------------------+
//| Helper: timeframe integer to readable string                     |
//+------------------------------------------------------------------+
string TFtoStr(int tf)
{
   switch(tf)
   {
      case PERIOD_M1:  return("1M");
      case PERIOD_M5:  return("5M");
      case PERIOD_M15: return("15M");
      case PERIOD_M30: return("30M");
      case PERIOD_H1:  return("1H");
      case PERIOD_H4:  return("4H");
      case PERIOD_D1:  return("D1");
      case PERIOD_W1:  return("W1");
      case PERIOD_MN1: return("MN");
      default:         return("TF");
   }
}

//+------------------------------------------------------------------+
//| 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);
      if(StringFind(name,"FractalLabel_") == 0)
         ObjectDelete(name);
      if(StringFind(name,"FractalArrow_") == 0)
         ObjectDelete(name);
   }
   return(0);
}

//+------------------------------------------------------------------+
//| Upper Fractal (uses iHigh for any timeframe)                     |
//+------------------------------------------------------------------+
bool IsUpperFractalTF(int shift, int tf)
{
   if(shift < Fractal_Right_Bars) return(false);
   int totalBars = iBars(NULL, tf);
   if(shift + Fractal_Left_Bars >= totalBars) return(false);

   double price = iHigh(NULL, tf, shift);

   for(int i=1; i<=Fractal_Left_Bars; i++)
      if(iHigh(NULL, tf, shift+i) >= price) return(false);

   for(int i=1; i<=Fractal_Right_Bars; i++)
      if(iHigh(NULL, tf, shift-i) > price) return(false);

   return(true);
}

//+------------------------------------------------------------------+
//| Lower Fractal (uses iLow for any timeframe)                      |
//+------------------------------------------------------------------+
bool IsLowerFractalTF(int shift, int tf)
{
   if(shift < Fractal_Right_Bars) return(false);
   int totalBars = iBars(NULL, tf);
   if(shift + Fractal_Left_Bars >= totalBars) return(false);

   double price = iLow(NULL, tf, shift);

   for(int i=1; i<=Fractal_Left_Bars; i++)
      if(iLow(NULL, tf, shift+i) <= price) return(false);

   for(int i=1; i<=Fractal_Right_Bars; i++)
      if(iLow(NULL, tf, shift-i) < price) return(false);

   return(true);
}

//+------------------------------------------------------------------+
//| Upper Fractal (original — chart timeframe, kept untouched)       |
//+------------------------------------------------------------------+
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 (original — chart timeframe, kept untouched)       |
//+------------------------------------------------------------------+
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);
}

//+------------------------------------------------------------------+
//| Find best (most recently broken) fractal for a given TF          |
//| Returns true if found; populates out_ params                     |
//+------------------------------------------------------------------+
bool FindBestFractal(int tf,
                     int maxBars,
                     int &out_StartBar,
                     int &out_StopBar,
                     double &out_Level,
                     bool &out_IsUp)
{
   int   bestStartBar = -1;
   int   bestStopBar  = 999999;
   double bestLevel   = 0;
   bool  bestIsUp     = false;

   int totalBars = iBars(NULL, tf);
   if(maxBars > totalBars - 10) maxBars = totalBars - 10;

   int stopBar;

   // --- Upper fractals ---
   for(int i=Fractal_Left_Bars; i<maxBars-Fractal_Right_Bars; i++)
   {
      if(!IsUpperFractalTF(i, tf)) continue;

      double level = iHigh(NULL, tf, i);
      stopBar = -1;

      for(int c=i; c>1; c--)
      {
         double o  = iOpen (NULL,tf,c);
         double cl = iClose(NULL,tf,c);
         double o1 = iOpen (NULL,tf,c-1);
         double c1 = iClose(NULL,tf,c-1);

         if((o < level && cl > level)||(o > level && cl < level)){stopBar=c;break;}
         if(o<=level && cl<=level && o1>=level && c1>=level){stopBar=c;break;}
         if(o>=level && cl>=level && o1<=level && c1<=level){stopBar=c;break;}
      }

      if(stopBar >= 0 && stopBar < bestStopBar)
      {
         bestStopBar  = stopBar;
         bestStartBar = i;
         bestLevel    = level;
         bestIsUp     = true;
      }
   }

   // --- Lower fractals ---
   for(int i=Fractal_Left_Bars; i<maxBars-Fractal_Right_Bars; i++)
   {
      if(!IsLowerFractalTF(i, tf)) continue;

      double level = iLow(NULL, tf, i);
      stopBar = -1;

      for(int c=i; c>1; c--)
      {
         double o  = iOpen (NULL,tf,c);
         double cl = iClose(NULL,tf,c);
         double o1 = iOpen (NULL,tf,c-1);
         double c1 = iClose(NULL,tf,c-1);

         if((o < level && cl > level)||(o > level && cl < level)){stopBar=c;break;}
         if(o<=level && cl<=level && o1>=level && c1>=level){stopBar=c;break;}
         if(o>=level && cl>=level && o1<=level && c1<=level){stopBar=c;break;}
      }

      if(stopBar >= 0 && stopBar < bestStopBar)
      {
         bestStopBar  = stopBar;
         bestStartBar = i;
         bestLevel    = level;
         bestIsUp     = false;
      }
   }

   if(bestStartBar < 0) return(false);

   out_StartBar = bestStartBar;
   out_StopBar  = bestStopBar;
   out_Level    = bestLevel;
   out_IsUp     = bestIsUp;
   return(true);
}

//+------------------------------------------------------------------+
//| START                                                            |
//+------------------------------------------------------------------+
int start()
{

   int maxBars = Maxbar;
   if(maxBars > Bars-10) maxBars = Bars-10;

   //==============================================================
   // PROCESS EACH TIMEFRAME
   //==============================================================
   ProcessTimeframe(
      1, TF1_Period, maxBars,
      TF1_Up_Line_Color,   TF1_Up_Line_Width,   TF1_Up_Line_Style,
      TF1_Down_Line_Color, TF1_Down_Line_Width, TF1_Down_Line_Style,
      TF1_Label_FontSize, TF1_Label_Color,
      TF1_Arrow_Code, TF1_Arrow_Size, TF1_Arrow_Color
   );

   ProcessTimeframe(
      2, TF2_Period, maxBars,
      TF2_Up_Line_Color,   TF2_Up_Line_Width,   TF2_Up_Line_Style,
      TF2_Down_Line_Color, TF2_Down_Line_Width, TF2_Down_Line_Style,
      TF2_Label_FontSize, TF2_Label_Color,
      TF2_Arrow_Code, TF2_Arrow_Size, TF2_Arrow_Color
   );

   return(0);
}

//+------------------------------------------------------------------+
//| Process one timeframe: find fractal, draw line + label + arrow   |
//+------------------------------------------------------------------+
void ProcessTimeframe(int    tfIndex,
                      int    tf,
                      int    maxBars,
                      color  upLineColor,   int upLineWidth,   int upLineStyle,
                      color  dnLineColor,   int dnLineWidth,   int dnLineStyle,
                      int    labelFontSize, color labelColor,
                      int    arrowCode,     int arrowSize,     color arrowColor)
{
   string suffix = "TF" + IntegerToString(tfIndex);

   int    bestStart;
   int    bestStop;
   double bestLevel;
   bool   isUp;

   if(!FindBestFractal(tf, maxBars, bestStart, bestStop, bestLevel, isUp))
      return;

   // --- Line ---
   color  lineColor = isUp ? upLineColor : dnLineColor;
   int    lineWidth = isUp ? upLineWidth : dnLineWidth;
   int    lineStyle = isUp ? upLineStyle : dnLineStyle;
   string dir       = isUp ? "UP" : "DN";

   DrawLine(suffix + "_" + dir, bestStart, bestStop, bestLevel,
            lineColor, lineWidth, lineStyle, tf);

   // --- Draw text with UP/DOWN ---
   string tfStr = TFtoStr(tf);
   string direction = isUp ? " UP" : " DOWN";
   DrawTextAtPrice(suffix, tfStr + direction, labelFontSize, labelColor);
}

//+------------------------------------------------------------------+
//| DRAW LINE  (original logic kept, adapted for multi-TF times)     |
//+------------------------------------------------------------------+
void DrawLine(string name,
              int    startBar,
              int    endBar,
              double price,
              color  col,
              int    width,
              int    style,
              int    tf)
{
   string objName = "FractalLine_" + name;

   // Convert TF bar indices → chart datetime
   datetime t1 = iTime(NULL, tf, startBar);
   datetime t2 = iTime(NULL, tf, endBar);

   if(ObjectFind(objName) == -1)
      ObjectCreate(objName, OBJ_TREND, 0, t1, price, t2, price);
   ObjectSetDouble(0,objName,OBJPROP_PRICE,0,price);
   ObjectSetDouble(0,objName,OBJPROP_PRICE,1,price);
   ObjectSetInteger(0,objName,OBJPROP_TIME,0,t1);
   ObjectSetInteger(0,objName,OBJPROP_TIME,1,t2);
   ObjectSet(objName, OBJPROP_RAY,   false);
   ObjectSet(objName, OBJPROP_COLOR, col);
   ObjectSet(objName, OBJPROP_WIDTH, width);
   ObjectSet(objName, OBJPROP_STYLE, style);
   ObjectSet(objName, OBJPROP_BACK,  Line_to_Background);
}

//+------------------------------------------------------------------+
//| DRAW TEXT  (OBJ_LABEL — at top right corner)                     |
//+------------------------------------------------------------------+
void DrawTextAtPrice(string suffix,
                     string text,
                     int    fontSize,
                     color  col)
{
   string objName = "FractalLabel_" + suffix;

   // Position at top right corner of the chart
   int xPos = 10;  // 10 pixels from right edge
   int yPos = 10;  // 10 pixels from top edge
   
   // For TF1 (30M), position higher; for TF2 (1H), position lower
   if(suffix == "TF1")
      yPos = 12;
   else if(suffix == "TF2")
      yPos = 37;
   
   if(ObjectFind(objName) == -1)
      ObjectCreate(objName, OBJ_LABEL, 0, 0, 0);
   else
   {
      // Update existing
      ObjectSet(objName, OBJPROP_XDISTANCE, xPos);
      ObjectSet(objName, OBJPROP_YDISTANCE, yPos);
      ObjectSet(objName, OBJPROP_CORNER, CORNER_RIGHT_UPPER);
      ObjectSetText(objName, text, fontSize, "Arial Bold", col);
      ObjectSet(objName, OBJPROP_BACK, false);
      return;
   }
   
   ObjectSet(objName, OBJPROP_XDISTANCE, xPos);
   ObjectSet(objName, OBJPROP_YDISTANCE, yPos);
   ObjectSet(objName, OBJPROP_CORNER, CORNER_RIGHT_UPPER);
   ObjectSetText(objName, text, fontSize, "Arial Bold", col);
   ObjectSet(objName, OBJPROP_BACK, false);
}
//+------------------------------------------------------------------+