//+------------------------------------------------------------------+
//|                              Jim Sloman's natural moving average |
//|                                                      ocn nma.mq4 |
//|                                                           mladen |
//+------------------------------------------------------------------+
#property copyright "mladen"
#property link      "mladenfx@gmail.com"

#property indicator_chart_window
#property indicator_buffers 1
#property indicator_color1  clrDeepSkyBlue
#property indicator_width1  2

//
//
//
//
//

extern int                NMA_Period  = 40;
extern ENUM_APPLIED_PRICE NMA_Price   = PRICE_CLOSE;
extern int                TEMA_Period = 10;

double nma[];

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

int init()
{
   SetIndexBuffer(0,nma);
      TEMA_Period = MathMax(TEMA_Period,1);
      NMA_Period  = MathMax(NMA_Period ,1);
           
   IndicatorShortName ("NMA ("+NMA_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);

   for(int i=limit; i >= 0; i--) nma[i] = iNma(iMA(NULL,0,1,0,MODE_SMA,NMA_Price,i),NMA_Period,TEMA_Period,i);
   return(0);
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

#define _nmaInstances 1
#define _nmaPrice     3
#define _nmaMom       4
#define _nmaValue     5
double workNma[][_nmaInstances*6];

double iNma(double price, int period, int temaperiod, int i, int instanceNo=0)
{
   if (period<=1) return(price);
   if (ArrayRange(workNma,0)!=Bars) ArrayResize(workNma,Bars); i = Bars-i-1; instanceNo*=6;

   //
   //
   //
   //
   //

   double alpha = 2.0 /(1.0 + temaperiod);
   if (i < 1)
   {
      workNma[i][instanceNo+_nmaPrice] = price;
      workNma[i][instanceNo+_nmaValue] = price;
      workNma[i][instanceNo+_nmaMom]   = 0;
      workNma[i][instanceNo+0]         = price;
      workNma[i][instanceNo+1]         = price;
      workNma[i][instanceNo+2]         = price;
   }
   else
   {
      workNma[i][instanceNo+0]         = workNma[i-1][instanceNo+0]+alpha*(price                   -workNma[i-1][instanceNo+0]);
      workNma[i][instanceNo+1]         = workNma[i-1][instanceNo+1]+alpha*(workNma[i][instanceNo+0]-workNma[i-1][instanceNo+1]);
      workNma[i][instanceNo+2]         = workNma[i-1][instanceNo+2]+alpha*(workNma[i][instanceNo+1]-workNma[i-1][instanceNo+2]);
      workNma[i][instanceNo+_nmaPrice] = 3*workNma[i][instanceNo+0] - 3*workNma[i][instanceNo+1] + workNma[i][instanceNo+2];
      workNma[i][instanceNo+_nmaMom]   = workNma[i][instanceNo+_nmaPrice]-workNma[i-1][instanceNo+_nmaPrice];
         
      //
      //
      //
      //
      //
   
      double momRatio = 0.00;
      double sumMomen = 0.00;
      double ratio    = 0.00;
      
      for (int k = 0; k<period && (i-k)>=0; k++)
      {
         sumMomen += MathAbs(workNma[i-k][instanceNo+_nmaMom]);
         momRatio +=         workNma[i-k][instanceNo+_nmaMom]*(MathSqrt(k+1)-MathSqrt(k));
      }
      if (sumMomen != 0) ratio = MathAbs(momRatio)/sumMomen;
      workNma[i][instanceNo+_nmaValue] =  workNma[i-1][instanceNo+_nmaValue]+ratio*(price-workNma[i-1][instanceNo+_nmaValue]);
   }         
   return(workNma[i][instanceNo+_nmaValue]);
}