// Smoothed HA direction: SMMA(OHLC) -> HA -> oriented extremes -> LWMA.
// Reimplementation of the default path described by fai_fx (2010-04-14).
#property strict
#property version "1.00"
#property indicator_separate_window
#property indicator_buffers 12
#property indicator_plots 1
#property indicator_type1 DRAW_COLOR_HISTOGRAM
#property indicator_color1 clrRed,clrWhite
#property indicator_width1 3
#property indicator_label1 "Smoothed HA direction"
#property indicator_minimum -0.05
#property indicator_maximum 1.05
input int InpSmoothingPeriod=6; // First smoothing: SMMA
input int InpDirectionPeriod=2; // Second smoothing: LWMA
input bool InpClosedOnly=true; // Hide forming bar
double Bar[],Color[],A[],B[],O[],H[],L[],C[],HAO[],HAC[],RawA[],RawB[];
int OnInit()
{
   if(InpSmoothingPeriod<1 || InpSmoothingPeriod>10000 ||
      InpDirectionPeriod<1 || InpDirectionPeriod>10000) return INIT_PARAMETERS_INCORRECT;
   SetIndexBuffer(0,Bar,INDICATOR_DATA);
   SetIndexBuffer(1,Color,INDICATOR_COLOR_INDEX);
   SetIndexBuffer(2,A,INDICATOR_CALCULATIONS);
   SetIndexBuffer(3,B,INDICATOR_CALCULATIONS);
   SetIndexBuffer(4,O,INDICATOR_CALCULATIONS);
   SetIndexBuffer(5,H,INDICATOR_CALCULATIONS);
   SetIndexBuffer(6,L,INDICATOR_CALCULATIONS);
   SetIndexBuffer(7,C,INDICATOR_CALCULATIONS);
   SetIndexBuffer(8,HAO,INDICATOR_CALCULATIONS);
   SetIndexBuffer(9,HAC,INDICATOR_CALCULATIONS);
   SetIndexBuffer(10,RawA,INDICATOR_CALCULATIONS);
   SetIndexBuffer(11,RawB,INDICATOR_CALCULATIONS);
   PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,InpSmoothingPeriod+InpDirectionPeriod-2);
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,EMPTY_VALUE);
   IndicatorSetInteger(INDICATOR_DIGITS,0);
   IndicatorSetString(INDICATOR_SHORTNAME,StringFormat("HA Direction SMMA(%d)/LWMA(%d)%s",
      InpSmoothingPeriod,InpDirectionPeriod,InpClosedOnly ? " closed" : " forming"));
   return INIT_SUCCEEDED;
}
int OnCalculate(const int total,const int previous,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[])
{
   ArraySetAsSeries(open,false); ArraySetAsSeries(high,false);
   ArraySetAsSeries(low,false); ArraySetAsSeries(close,false);
   const int p=InpSmoothingPeriod,q=InpDirectionPeriod,seed=p-1,begin=p+q-2;
   int start=(previous<=0 || previous>total) ? 0 : previous-1;
   for(int i=start;i<total && !IsStopped();i++)
   {
      Bar[i]=EMPTY_VALUE; Color[i]=0; A[i]=EMPTY_VALUE; B[i]=EMPTY_VALUE;
      if(i<seed) continue;
      if(i==seed)
      {
         O[i]=0; H[i]=0; L[i]=0; C[i]=0;
         for(int j=0;j<p;j++) { O[i]+=open[j]; H[i]+=high[j]; L[i]+=low[j]; C[i]+=close[j]; }
         O[i]/=p; H[i]/=p; L[i]/=p; C[i]/=p;
         HAO[i]=(O[i]+C[i])/2.0;
      }
      else
      {
         O[i]=(O[i-1]*(p-1)+open[i])/p; H[i]=(H[i-1]*(p-1)+high[i])/p;
         L[i]=(L[i-1]*(p-1)+low[i])/p; C[i]=(C[i-1]*(p-1)+close[i])/p;
         HAO[i]=(HAO[i-1]+HAC[i-1])/2.0;
      }
      HAC[i]=(O[i]+H[i]+L[i]+C[i])/4.0;
      double hh=MathMax(H[i],MathMax(HAO[i],HAC[i]));
      double ll=MathMin(L[i],MathMin(HAO[i],HAC[i]));
      RawA[i]=(HAO[i]<HAC[i]) ? ll : hh;
      RawB[i]=(HAO[i]<HAC[i]) ? hh : ll;
      if(i<begin) continue;
      double a=0,b=0;
      for(int j=0;j<q;j++) { a+=(q-j)*RawA[i-j]; b+=(q-j)*RawB[i-j]; }
      double weight=(double)q*(q+1)/2.0;
      A[i]=a/weight; B[i]=b/weight;
      // Equality follows the original red branch. Height conveys no strength.
      Color[i]=(A[i]<B[i]) ? 1 : 0;
      if(!InpClosedOnly || i<total-1) Bar[i]=1.0;
   }
   return total;
}
