//------------------------------------------------------------------
//
//------------------------------------------------------------------
#property indicator_chart_window
#property indicator_buffers 4
#property indicator_color1  LimeGreen
#property indicator_color2  PaleVioletRed
#property indicator_color3  LimeGreen
#property indicator_color4  PaleVioletRed
#property indicator_width3  3
#property indicator_width4  3

//
//
//
//
//

extern ENUM_TIMEFRAMES    TimeFrame = PERIOD_CURRENT;    // Time frame
extern int                HmaPeriod = 51;
extern ENUM_APPLIED_PRICE HmaPrice  = PRICE_CLOSE;

double hmahu[];
double hmahd[];
double hmahbu[];
double hmahbd[];
double hma[];
double trend[];
string indicatorFileName;
bool   returnBars;

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

int init()
{
   IndicatorBuffers(6);
   SetIndexBuffer(0,hmahu);  SetIndexStyle(0,DRAW_HISTOGRAM);
   SetIndexBuffer(1,hmahd);  SetIndexStyle(1,DRAW_HISTOGRAM);
   SetIndexBuffer(2,hmahbu); SetIndexStyle(2,DRAW_HISTOGRAM);
   SetIndexBuffer(3,hmahbd); SetIndexStyle(3,DRAW_HISTOGRAM);
   SetIndexBuffer(4,hma);
   SetIndexBuffer(5,trend);
       indicatorFileName = WindowExpertName();
       returnBars        = (TimeFrame==-99);
       TimeFrame         = MathMax(TimeFrame,_Period);
   return(0);
}
int deinit() { return(0); }

//
//
//
//
//

int start()
{
   int counted_bars  = IndicatorCounted(); 
      if(counted_bars<0) return(-1);
      if(counted_bars>0) counted_bars--;
          int limit = MathMin(Bars - counted_bars,Bars-1);
            if (returnBars) { hmahu[0] = limit+1; return(0); }
            if (TimeFrame != Period())
            {
               limit = (int)MathMax(limit,MathMin(Bars-1,iCustom(NULL,TimeFrame,indicatorFileName,-99,0,0)*TimeFrame/Period())); 
               for(int i=limit; i>=0; i--)
               {
                  int y = iBarShift(NULL,TimeFrame,Time[i]);
                     trend[i]  = iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,HmaPeriod,HmaPrice,5,y);
                     if (trend[i]== 1)
                     {
                        hmahu[i]  = High[i]; hmahd[i] = Low[i];
                        hmahbu[i] = MathMax(Open[i],Close[i]);
                        hmahbd[i] = MathMin(Open[i],Close[i]);
                     }               
                     if (trend[i]== -1)
                     {
                        hmahu[i]  = Low[i];
                        hmahd[i]  = High[i];
                        hmahbu[i] = MathMin(Open[i],Close[i]);
                        hmahbd[i] = MathMax(Open[i],Close[i]);
                     }               
               }
               return(0);
            }

   //
   //
   //
   //
   //

      for(i = limit; i >= 0; i--)
      {
         hma[i]   = iHull(iMA(NULL,0,1,0,MODE_SMA,HmaPrice,i),HmaPeriod,i);
         trend[i] = trend[i+1];
            if (hma[i]>hma[i+1]) trend[i] =  1;
            if (hma[i]<hma[i+1]) trend[i] = -1;
            if (trend[i]== 1)
            {
               hmahu[i]  = High[i]; hmahd[i] = Low[i];
               hmahbu[i] = MathMax(Open[i],Close[i]);
               hmahbd[i] = MathMin(Open[i],Close[i]);
            }               
            if (trend[i]== -1)
            {
               hmahu[i]  = Low[i];
               hmahd[i]  = High[i];
               hmahbu[i] = MathMin(Open[i],Close[i]);
               hmahbd[i] = MathMax(Open[i],Close[i]);
            }               
      }
      return(0);
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

double workHull[][2];
double iHull(double price, double period, int r, int instanceNo=0)
{
   if (ArrayRange(workHull,0)!= Bars) ArrayResize(workHull,Bars); r = Bars-r-1;

   //
   //
   //
   //
   //

      int HmaPeriod  = MathMax(period,2);
      int HalfPeriod = MathFloor(HmaPeriod/2);
      int HullPeriod = MathFloor(MathSqrt(HmaPeriod));
      double hma,hmw,weight; instanceNo *= 2;

         workHull[r][instanceNo] = price;

         //
         //
         //
         //
         //
               
         hmw = HalfPeriod; hma = hmw*price; 
            for(int k=1; k<HalfPeriod && (r-k)>=0; k++)
            {
               weight = HalfPeriod-k;
               hmw   += weight;
               hma   += weight*workHull[r-k][instanceNo];  
            }             
            workHull[r][instanceNo+1] = 2.0*hma/hmw;

         hmw = HmaPeriod; hma = hmw*price; 
            for(k=1; k<period && (r-k)>=0; k++)
            {
               weight = HmaPeriod-k;
               hmw   += weight;
               hma   += weight*workHull[r-k][instanceNo];
            }             
            workHull[r][instanceNo+1] -= hma/hmw;

         //
         //
         //
         //
         //
         
         hmw = HullPeriod; hma = hmw*workHull[r][instanceNo+1];
            for(k=1; k<HullPeriod && (r-k)>=0; k++)
            {
               weight = HullPeriod-k;
               hmw   += weight;
               hma   += weight*workHull[r-k][1+instanceNo];  
            }
   return(hma/hmw);
}