//+------------------------------------------------------------------+
//|                              Stochastic Chaikin's Volatility.mq4 |
//|                                                           Giaras |
//|                                    giampiero.raschetti@gmail.com |
//+------------------------------------------------------------------+
#property copyright "giaras"
#property link      "giampiero.raschetti@gmail.com"

#property indicator_separate_window
#property indicator_buffers 2
#property indicator_color1  clrBlue
#property indicator_color2  clrRed
#property strict

 
//---- input parameters
//
//

input int iPeriod    = 10;
input int maPeriod   = 10;
input int StocLength = 5;
input int WMALength  = 5;

double val[],sig[];
struct sGloStruct { double hhv,llv,alp;};
sGloStruct glo;


//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
{
   SetIndexBuffer(0, val,INDICATOR_DATA); SetIndexStyle(0, DRAW_LINE);
   SetIndexBuffer(1, sig,INDICATOR_DATA); SetIndexStyle(1, DRAW_LINE);
   
   _lwma.init(WMALength); 
   
   glo.alp = 2.0/(1.0+maPeriod);
   
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[])
{
   
   int i,r,limit=fmin(rates_total-prev_calculated+1,rates_total-1); 
  
   //
   //
   //
   
   struct sStoStruct {  double prc,raw,ema,cha; };
   static sStoStruct wrk[];
   static int        wrkSize = -1;
                 if (wrkSize<rates_total) wrkSize = ArrayResize(wrk,rates_total+500);
   
   //
   //
   //

   for(i=limit, r=rates_total-limit-1; i>=0; i--,r++)
   { 
      wrk[r].prc = high[i]-low[i];
      wrk[r].ema = (r>0) ? wrk[r-1].ema + glo.alp*(wrk[r].prc-wrk[r-1].ema) : wrk[r].prc; // ema of high low
      wrk[r].cha = (r>iPeriod) ? ((wrk[r].ema-wrk[r-iPeriod].ema)/wrk[r-iPeriod].ema) : wrk[r].prc; //chaikin
      glo.llv    = glo.hhv = wrk[r].cha;
      for(int k=1; k<StocLength && (r-k)>0; k++ ) // sto period
      {
         glo.llv = fmin(wrk[r-k].cha,glo.llv);
         glo.hhv = fmax(wrk[r-k].cha,glo.hhv);
      }
      wrk[r].raw = ((glo.hhv-glo.llv)!=0) ? 100.0*((wrk[r].cha-glo.llv)/(glo.hhv-glo.llv)) : 0;  // sto chaikin raw
      val[i]     = _lwma.calculate(wrk[r].raw,r,rates_total);
      sig[i]     = (r>0) ? val[i+1] : val[i];
    }   
return(rates_total);
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------

class CLwma
{
   private :
      struct sLwmaArrayStruct
      {
         double value;
         double wsumm;
         double vsumm;
      };
      sLwmaArrayStruct m_array[];
      int              m_arraySize;
      int              m_period;
      double           m_weight;
   public :
      CLwma() : m_period(1), m_weight(1), m_arraySize(-1) {                      return; }
     ~CLwma()                                              { ArrayFree(m_array); return; }
    
     //
     //
     //

     void init(int period) { m_period = (period>1) ? period : 1; }
     double calculate(double value, int i, int bars)
     {
        if (m_arraySize<bars) { m_arraySize=ArrayResize(m_array,bars+500); if (m_arraySize<bars) return(0); }

         //
         //
         //

         m_array[i].value=value;
         if (i>m_period)
         {
            m_array[i].wsumm = m_array[i-1].wsumm+value*m_period-m_array[i-1       ].vsumm;
            m_array[i].vsumm = m_array[i-1].vsumm+value         -m_array[i-m_period].value;
         }
         else
         {
            m_weight = m_array[i].wsumm = m_array[i].vsumm  = 0;
            for(int k=0, w=m_period; k<m_period && i>=k; k++,w--)
            {
                m_weight         += w;
                m_array[i].wsumm += m_array[i-k].value*(double)w;
                m_array[i].vsumm += m_array[i-k].value;
            }
          }
          return(m_array[i].wsumm/m_weight);
      }  
};
CLwma _lwma;
