//+------------------------------------------------------------------+
//|                                          Hull Suite by InSilico  |
//|                              Converted from TradingView PineScript |
//+------------------------------------------------------------------+
#property copyright "Converted to MQL5"
#property link      ""
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 3
#property indicator_plots   1

//--- plot Hull MA
#property indicator_label1  "Hull MA"
#property indicator_type1   DRAW_COLOR_LINE
#property indicator_color1  clrLime,clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  3

//--- input parameters
input int                   length=55;              // Length (55 for swing entry, 180-200 for floating S/R)
input double                lengthMult=1.0;         // Length multiplier
input ENUM_APPLIED_PRICE    appliedPrice=PRICE_CLOSE; // Source
input string                modeSwitch="Hma";       // Hull Variation (Hma, Thma, Ehma)
input bool                  useHtf=false;           // Show Hull MA from higher timeframe?
input ENUM_TIMEFRAMES       htf=PERIOD_H4;          // Higher timeframe
input bool                  switchColor=true;       // Color Hull according to trend?
input bool                  candleCol=false;        // Color candles based on Hull's Trend?
input int                   lineWidth=3;            // Line Width

//--- indicator buffers
double         HullBuffer[];      // Hull MA values
double         ColorBuffer[];     // Color index (0=green, 1=red)
double         TempBuffer[];      // Temporary calculation buffer

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
   //--- indicator buffers mapping
   SetIndexBuffer(0, HullBuffer, INDICATOR_DATA);
   SetIndexBuffer(1, ColorBuffer, INDICATOR_COLOR_INDEX);
   SetIndexBuffer(2, TempBuffer, INDICATOR_CALCULATIONS);
   
   //--- Set arrays as series (index 0 = current bar, newest data)
   ArraySetAsSeries(HullBuffer, true);
   ArraySetAsSeries(ColorBuffer, true);
   ArraySetAsSeries(TempBuffer, true);
   
   //--- set line width
   PlotIndexSetInteger(0, PLOT_LINE_WIDTH, lineWidth);
   
   //--- set color indices
   PlotIndexSetInteger(0, PLOT_COLOR_INDEXES, 2);
   PlotIndexSetInteger(0, PLOT_LINE_COLOR, 0, clrLime);    // Index 0 = Green (Uptrend)
   PlotIndexSetInteger(0, PLOT_LINE_COLOR, 1, clrRed);     // Index 1 = Red (Downtrend)
   
   //--- set indicator name
   IndicatorSetString(INDICATOR_SHORTNAME, "Hull Suite by Insilico , converted by Piyush for ForexStation");
   
   //--- set precision
   IndicatorSetInteger(INDICATOR_DIGITS, _Digits);
   
   //--- set drawing begin
   PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, length);
   
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
{
   //--- Set input arrays as series
   ArraySetAsSeries(close, true);
   ArraySetAsSeries(time, true);
   
   int limit;
   if(prev_calculated == 0)
   {
      limit = rates_total - length - 3;
      //--- Clear buffers
      ArrayInitialize(HullBuffer, 0);
      ArrayInitialize(ColorBuffer, 0);
   }
   else
   {
      limit = rates_total - prev_calculated;
      //--- Recalculate last 3 bars for smooth updates
      limit += 3;
   }
   
   //--- main loop - now 0 is current bar
   for(int i = 0; i < limit && i < rates_total; i++)
   {
      int len = (int)(length * lengthMult);
      
      //--- Calculate Hull MA
      double hull;
      if(useHtf)
      {
         hull = GetHullHTF(i, time, len, close);
      }
      else
      {
         hull = CalculateHull(i, close, rates_total, len);
      }
      
      HullBuffer[i] = hull;
   }
   
   //--- Second loop to determine colors after all Hull values are calculated
   for(int i = 0; i < limit && i < rates_total; i++)
   {
      //--- Determine color based on trend
      // Compare current Hull with Hull 2 bars ago (like TradingView version)
      if(switchColor)
      {
         if(i + 2 < rates_total && HullBuffer[i + 2] != 0)
         {
            // Uptrend: Current Hull > Hull[2]
            // Downtrend: Current Hull < Hull[2]
            if(HullBuffer[i] > HullBuffer[i + 2])
            {
               ColorBuffer[i] = 0;  // Green (Uptrend)
            }
            else
            {
               ColorBuffer[i] = 1;  // Red (Downtrend)
            }
         }
         else
         {
            // For first 2 bars, use comparison with previous bar
            if(i + 1 < rates_total && HullBuffer[i + 1] != 0)
            {
               if(HullBuffer[i] > HullBuffer[i + 1])
                  ColorBuffer[i] = 0;  // Green
               else
                  ColorBuffer[i] = 1;  // Red
            }
            else
            {
               ColorBuffer[i] = 0;  // Default green
            }
         }
      }
      else
      {
         ColorBuffer[i] = 0;  // Default green if color switch is off
      }
   }
   
   //--- Candle coloring (optional)
   if(candleCol && switchColor && rates_total > 0)
   {
      if(ColorBuffer[0] == 0)  // Current bar uptrend
      {
         ChartSetInteger(0, CHART_COLOR_CANDLE_BULL, clrLime);
         ChartSetInteger(0, CHART_COLOR_CHART_UP, clrLime);
      }
      else  // Current bar downtrend
      {
         ChartSetInteger(0, CHART_COLOR_CANDLE_BEAR, clrRed);
         ChartSetInteger(0, CHART_COLOR_CHART_DOWN, clrRed);
      }
   }
   
   return(rates_total);
}

//+------------------------------------------------------------------+
//| Calculate Hull MA based on mode                                  |
//+------------------------------------------------------------------+
double CalculateHull(int shift, const double &price[], int total, int len)
{
   if(shift + len >= total)
      return 0;
   
   double hull = 0;
   
   if(modeSwitch == "Hma")
   {
      //--- HMA = WMA(2*WMA(src, len/2) - WMA(src, len), sqrt(len))
      int sqrtLen = (int)MathSqrt(len);
      double tempArray[];
      ArrayResize(tempArray, sqrtLen);
      
      for(int i = 0; i < sqrtLen; i++)
      {
         if(shift + i < total)
         {
            double w1 = CalculateWMA(shift + i, price, total, len / 2);
            double w2 = CalculateWMA(shift + i, price, total, len);
            tempArray[i] = 2 * w1 - w2;
         }
      }
      
      hull = CalculateWMAFromArray(0, tempArray, sqrtLen);
   }
   else if(modeSwitch == "Ehma")
   {
      //--- EHMA = EMA(2*EMA(src, len/2) - EMA(src, len), sqrt(len))
      int sqrtLen = (int)MathSqrt(len);
      double tempArray[];
      ArrayResize(tempArray, sqrtLen);
      
      for(int i = 0; i < sqrtLen; i++)
      {
         if(shift + i < total)
         {
            double e1 = CalculateEMA(shift + i, price, total, len / 2);
            double e2 = CalculateEMA(shift + i, price, total, len);
            tempArray[i] = 2 * e1 - e2;
         }
      }
      
      hull = CalculateEMAFromArray(0, tempArray, sqrtLen);
   }
   else if(modeSwitch == "Thma")
   {
      //--- THMA = WMA(WMA(src,len/3)*3 - WMA(src, len/2) - WMA(src, len), len)
      double tempArray[];
      ArrayResize(tempArray, len);
      
      for(int i = 0; i < len; i++)
      {
         if(shift + i < total)
         {
            double w1 = CalculateWMA(shift + i, price, total, len / 3);
            double w2 = CalculateWMA(shift + i, price, total, len / 2);
            double w3 = CalculateWMA(shift + i, price, total, len);
            tempArray[i] = w1 * 3 - w2 - w3;
         }
      }
      
      hull = CalculateWMAFromArray(0, tempArray, len);
   }
   
   return hull;
}

//+------------------------------------------------------------------+
//| Calculate WMA                                                     |
//+------------------------------------------------------------------+
double CalculateWMA(int shift, const double &price[], int total, int period)
{
   if(shift + period >= total)
      return 0;
   
   double sum = 0;
   double weight = 0;
   
   for(int i = 0; i < period; i++)
   {
      if(shift + i < total)
      {
         sum += price[shift + i] * (period - i);
         weight += (period - i);
      }
   }
   
   if(weight != 0)
      return sum / weight;
   else
      return 0;
}

//+------------------------------------------------------------------+
//| Calculate WMA from array                                         |
//+------------------------------------------------------------------+
double CalculateWMAFromArray(int shift, const double &array[], int period)
{
   double sum = 0;
   double weight = 0;
   
   for(int i = 0; i < period && i < ArraySize(array); i++)
   {
      sum += array[shift + i] * (period - i);
      weight += (period - i);
   }
   
   if(weight != 0)
      return sum / weight;
   else
      return 0;
}

//+------------------------------------------------------------------+
//| Calculate EMA                                                     |
//+------------------------------------------------------------------+
double CalculateEMA(int shift, const double &price[], int total, int period)
{
   if(shift + period >= total)
      return 0;
      
   double alpha = 2.0 / (period + 1.0);
   double ema = price[shift + period - 1];
   
   for(int i = period - 2; i >= 0; i--)
   {
      if(shift + i < total)
         ema = alpha * price[shift + i] + (1 - alpha) * ema;
   }
   
   return ema;
}

//+------------------------------------------------------------------+
//| Calculate EMA from array                                         |
//+------------------------------------------------------------------+
double CalculateEMAFromArray(int shift, const double &array[], int period)
{
   if(period >= ArraySize(array))
      return array[shift];
      
   double alpha = 2.0 / (period + 1.0);
   double ema = array[period - 1];
   
   for(int i = period - 2; i >= 0; i--)
   {
      ema = alpha * array[i] + (1 - alpha) * ema;
   }
   
   return ema;
}

//+------------------------------------------------------------------+
//| Get Hull from higher timeframe                                   |
//+------------------------------------------------------------------+
double GetHullHTF(int shift, const datetime &time[], int len, const double &close[])
{
   double closeHTF[];
   int copied = CopyClose(_Symbol, htf, time[shift], len * 3, closeHTF);
   
   if(copied > 0)
   {
      ArraySetAsSeries(closeHTF, true);
      return CalculateHull(0, closeHTF, copied, len);
   }
   
   return 0;
}
//+------------------------------------------------------------------+
