//-------------------------------------------------------------------
#property copyright "www,forex-tsd.com"
#property link      "www,forex-tsd.com"
//-------------------------------------------------------------------
#property indicator_separate_window
#property indicator_buffers 4
#property indicator_color1 LightSlateGray
#property indicator_color2 DodgerBlue
#property indicator_color3 SandyBrown
#property indicator_color4 SandyBrown
#property indicator_style1 STYLE_DOT
#property indicator_width2 2
#property indicator_width3 2
#property indicator_width4 2

extern int    period      = 14;
extern int    Level       = 25;
extern double Smooth      = 15;
extern int    AdaptPeriod = 14;

double ADX[],ADXLa[],ADXLb[],DI[];

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

int init()
{
   SetIndexBuffer(0,DI);
   SetIndexBuffer(1,ADX);
   SetIndexBuffer(2,ADXLa);
   SetIndexBuffer(3,ADXLb);
      SetLevelValue(0,0);
      SetLevelValue(1, Level);
      SetLevelValue(2,-Level);
   IndicatorShortName("ADXm stddev adaptive "+"("+period+","+DoubleToStr(Smooth,2)+","+DoubleToStr(AdaptPeriod,2)+")");
   return(0);
}

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

double work[][3];
#define zdh   0
#define zdl   1
#define slope 2

int start()
{
   int i,r,counted_bars = IndicatorCounted();
      if(counted_bars < 0) return(-1);
      if(counted_bars > 0) counted_bars--;
         int limit    = MathMin(Bars-counted_bars,Bars-1);
         if (ArrayRange(work,0)!=Bars) ArrayResize(work,Bars);

   //
   //
   //
   //
   //
   
   if (work[limit][slope]==-1) CleanPoint(limit,ADXLa,ADXLb);
   for (i=limit,r=Bars-i-1; i>=0; i--,r++)
   {
      if (i==Bars-1) { work[r][zdh] = 0; work[r][zdl] = 0; ADX[i] = 0; continue; }
         double dev = iStdDev(NULL,0,AdaptPeriod,0,MODE_SMA,PRICE_CLOSE,i);
         double avg = iSma(dev,AdaptPeriod,i,0);
            if (dev!=0) 
                   double tperiod = period*avg/dev;
            else          tperiod = period; 
            double alpha = 2.0/(tperiod+1);
      
         double hc = iSsm(High[i]   ,Smooth,i,0);
         double lc = iSsm(Low[i]    ,Smooth,i,1);
         double cp = iSsm(Close[i+1],Smooth,i,2);
         double hp = iSsm(High[i+1] ,Smooth,i,3);
         double lp = iSsm(Low[i+1]  ,Smooth,i,4);
         double dh = MathMax(hc-hp,0);
         double dl = MathMax(lp-lc,0);
         
      if(dh==dl) {dh=0; dl=0;} else if(dh<dl) dh=0; else if(dl<dh) dl=0;
      
         double tr   = MathMax(hc,cp)-MathMin(lc,cp);
         double dhk  = 0;
         double dlk  = 0;
      
      if(tr!=0) { dhk = 100.0*dh/tr; dlk = 100.0*dl/tr; }
      
         work[r][zdh] = work[r-1][zdh] + alpha*(dhk-work[r-1][zdh]);
         work[r][zdl] = work[r-1][zdl] + alpha*(dlk-work[r-1][zdl]);
         DI[i]        = work[r][zdh] - work[r][zdl];

            double div  = MathAbs(work[r][zdh] + work[r][zdl]);
            double temp = 0; if( div != 0.0)  temp = 100*DI[i]/div; 
      
         ADX[i]         = ADX[i+1]+alpha*(temp-ADX[i+1]);
         ADXLa[i]       = EMPTY_VALUE;
         ADXLb[i]       = EMPTY_VALUE;
         work[r][slope] = work[r-1][slope];
      
      if (ADX[i]>ADX[i+1]) work[r][slope] =  1;
      if (ADX[i]<ADX[i+1]) work[r][slope] = -1;
      if (work[r][slope]==-1) PlotPoint(i,ADXLa,ADXLb,ADX);
   }
   return(0);
}

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

void CleanPoint(int i,double& first[],double& second[])
{
   if (i>=Bars-3) return;
   if ((second[i]  != EMPTY_VALUE) && (second[i+1] != EMPTY_VALUE))
        second[i+1] = EMPTY_VALUE;
   else
      if ((first[i] != EMPTY_VALUE) && (first[i+1] != EMPTY_VALUE) && (first[i+2] == EMPTY_VALUE))
          first[i+1] = EMPTY_VALUE;
}

void PlotPoint(int i,double& first[],double& second[],double& from[])
{
   if (i>=Bars-2) return;
   if (first[i+1] == EMPTY_VALUE)
      if (first[i+2] == EMPTY_VALUE) 
            { first[i]  = from[i];  first[i+1]  = from[i+1]; second[i] = EMPTY_VALUE; }
      else  { second[i] =  from[i]; second[i+1] = from[i+1]; first[i]  = EMPTY_VALUE; }
   else     { first[i]  = from[i];                           second[i] = EMPTY_VALUE; }
}

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

#define Pi 3.14159265358979323846264338327950288
double workSsm[][10];
#define _tprice 0
#define _ssm    1

double workSsmCoeffs[][4];
#define _period 0
#define _c1     1
#define _c2     2
#define _c3     3

//
//
//
//
//

double iSsm(double tprice, double tperiod, int i, int instanceNo=0)
{
   if (tperiod<=1) return(tprice); i = Bars-i-1;
   if (ArrayRange(workSsm,0) !=Bars)                 ArrayResize(workSsm,Bars);
   if (ArrayRange(workSsmCoeffs,0) < (instanceNo+1)) ArrayResize(workSsmCoeffs,instanceNo+1);
   if (workSsmCoeffs[instanceNo][_period] != tperiod)
   {
      workSsmCoeffs[instanceNo][_period] = tperiod;
      double a1 = MathExp(-1.414*Pi/tperiod);
      double b1 = 2.0*a1*MathCos(1.414*Pi/tperiod);
         workSsmCoeffs[instanceNo][_c2] = b1;
         workSsmCoeffs[instanceNo][_c3] = -a1*a1;
         workSsmCoeffs[instanceNo][_c1] = 1.0 - workSsmCoeffs[instanceNo][_c2] - workSsmCoeffs[instanceNo][_c3];
   }

   //
   //
   //
   //
   //

      int s = instanceNo*2;   
          workSsm[i][s+_tprice] = tprice;
          if (i>1)
              workSsm[i][s+_ssm]   = workSsmCoeffs[instanceNo][_c1]*(workSsm[i][s+_tprice]+workSsm[i-1][s+_tprice])/2.0 + 
                                     workSsmCoeffs[instanceNo][_c2]*workSsm[i-1][s+_ssm]                                + 
                                     workSsmCoeffs[instanceNo][_c3]*workSsm[i-2][s+_ssm]; 
         else workSsm[i][s+_ssm] = tprice;
   return(workSsm[i][s+_ssm]);
}

//
//
//
//
//

double workSma[][2];
double iSma(double price, int tperiod, int r, int instanceNo=0)
{
   if (ArrayRange(workSma,0)!= Bars) ArrayResize(workSma,Bars); instanceNo *= 2; r = Bars-r-1;

   //
   //
   //
   //
   //
      
   workSma[r][instanceNo] = price;
   if (r>=tperiod)
          workSma[r][instanceNo+1] = workSma[r-1][instanceNo+1]+(workSma[r][instanceNo]-workSma[r-tperiod][instanceNo])/tperiod;
   else { workSma[r][instanceNo+1] = 0; for(int k=0; k<tperiod && (r-k)>=0; k++) workSma[r][instanceNo+1] += workSma[r-k][instanceNo];  
          workSma[r][instanceNo+1] /= k; }
   return(workSma[r][instanceNo+1]);
}