//+------------------------------------------------------------------+
//|                                                JMA z - score.mq4 |
//|                                    from Mladen Rakic mt5 version |
//+------------------------------------------------------------------+
#property copyright "www.forex-station.com"
#property indicator_separate_window
#property indicator_maximum 20
#property indicator_minimum -1
#property indicator_buffers 3
#property indicator_color1  Lime
#property indicator_color2  Red
#property indicator_color3  DarkSlateGray
#property indicator_width1  2
#property indicator_width2  2
#property indicator_width3  2

input int             inpPeriod = 50;
 double          inpPhase  = 0;
 ENUM_MA_METHOD  ma_mode   = MODE_EMA;
input double          MA_period = 10;

double B0[],B1[],B2[],val[],B4[],B5[],B6[];

int init(){
   IndicatorBuffers(7);
   SetIndexBuffer(0,B0); SetIndexStyle(0,DRAW_HISTOGRAM);
   SetIndexBuffer(1,B1); SetIndexStyle(1,DRAW_HISTOGRAM);
   SetIndexBuffer(2,B2); SetIndexStyle(2,DRAW_HISTOGRAM);
   SetIndexBuffer(3,val);
   SetIndexBuffer(4,B4);
   SetIndexBuffer(5,B5);
   SetIndexBuffer(6,B6);
   IndicatorShortName(NULL);
   IndicatorDigits(0);

return(0);
}

int start(){int i,limit=Bars-IndicatorCounted()-1;

    for(i=limit;i>=0;i--){val[i]=iSmooth(Close[i],i);}

    for(i=limit;i>=0;i--){B6[i]=iMA(NULL,0,MA_period,0,ma_mode,PRICE_CLOSE,i);}
    for(i=limit;i>=0;i--){B5[i]=iMAOnArray(B6,0,MA_period,0,ma_mode,i);}
    for(i=limit;i>=0;i--){B4[i]=iMAOnArray(B5,0,MA_period,0,ma_mode,i);

    if(val[i+1]<val[i] && B4[i+1]<B4[i]){B0[i]=-1;          B1[i]=EMPTY_VALUE; B2[i]=EMPTY_VALUE;}else
    if(val[i+1]>val[i] && B4[i+1]>B4[i]){B0[i]=EMPTY_VALUE; B1[i]=-1;          B2[i]=EMPTY_VALUE;}else
                                        {B0[i]=EMPTY_VALUE; B1[i]=EMPTY_VALUE; B2[i]=-1;}}
 return(0);
}

#define _smoothInstances     1
#define _smoothInstancesSize 10
double  _smthWork[][_smoothInstances*_smoothInstancesSize];
#define bsmax  5
#define bsmin  6
#define volty  7
#define vsum   8
#define avolty 9
double iSmooth(double price, int r)
{
   double length=inpPeriod; double phase=inpPhase;
   int bars=Bars; int instanceNo=0;
   if (ArrayRange(_smthWork,0)!=bars) ArrayResize(_smthWork,bars); instanceNo*=_smoothInstancesSize; r = bars-r-1;
   if (price==EMPTY_VALUE) price=0;

   if (r==0 || length<=1){ int k=0; for(; k<volty; k++) _smthWork[0][instanceNo+k]=price; for(; k<_smoothInstancesSize; k++) _smthWork[0][instanceNo+k]=0; return(price); }

      double len1   = fmax(log(sqrt(0.5*(length-1)))/log(2.0)+2.0,0);
      double pow1   = fmax(len1-2.0,0.5);
      double del1   = price - _smthWork[r-1][instanceNo+bsmax],absDel1 = fabs(del1);
      double del2   = price - _smthWork[r-1][instanceNo+bsmin],absDel2 = fabs(del2);
      int    forBar = (int)fmin(r,10);

         _smthWork[r][instanceNo+volty]  = (absDel1 > absDel2) ? absDel1 : (absDel1 < absDel2) ? absDel2 : 0;
         _smthWork[r][instanceNo+vsum]   = _smthWork[r-1][instanceNo+vsum] + (_smthWork[r][instanceNo+volty]-_smthWork[r-forBar][instanceNo+volty])*0.1;
         _smthWork[r][instanceNo+avolty] = _smthWork[r-1][instanceNo+avolty]+(2.0/(fmax(4.0*length,30)+1.0))*(_smthWork[r][instanceNo+vsum]-_smthWork[r-1][instanceNo+avolty]);

         double dVolty    = (_smthWork[r][instanceNo+avolty]>0) ? _smthWork[r][instanceNo+volty]/_smthWork[r][instanceNo+avolty] : 0;
         double dVoltyTmp = pow(len1,1.0/pow1);
         if (dVolty > dVoltyTmp) dVolty = dVoltyTmp;
         if (dVolty < 1.0)       dVolty = 1.0;

         double pow2 = pow(dVolty, pow1);
         double len2 = sqrt(0.5*(length-1))*len1;
         double Kv   = pow(len2/(len2+1),sqrt(pow2));

            _smthWork[r][instanceNo+bsmax] = (del1>0) ? price : price - Kv*del1;
            _smthWork[r][instanceNo+bsmin] = (del2<0) ? price : price - Kv*del2;

      double corr  = fmax(fmin(phase,100),-100)/100.0 + 1.5;
      double beta  = 0.45*(length-1)/(0.45*(length-1)+2);
      double alpha = pow(beta,pow2);

         _smthWork[r][instanceNo+0] = price + alpha*(_smthWork[r-1][instanceNo+0]-price);
         _smthWork[r][instanceNo+1] = (price - _smthWork[r][instanceNo+0])*(1-beta) + beta*_smthWork[r-1][instanceNo+1];
         _smthWork[r][instanceNo+2] = (_smthWork[r][instanceNo+0]   + corr*_smthWork[r][instanceNo+1]);
         _smthWork[r][instanceNo+3] = (_smthWork[r][instanceNo+2]   - _smthWork[r-1][instanceNo+4])*((1-alpha)*(1-alpha)) + (alpha*alpha)*_smthWork[r-1][instanceNo+3];
         _smthWork[r][instanceNo+4] = (_smthWork[r-1][instanceNo+4] + _smthWork[r][instanceNo+3]);
  return(_smthWork[r][instanceNo+4]);
}