//------------------------------------------------------------------
#property copyright "mladen"
#property link      "mladenfx@gmail.com"
//------------------------------------------------------------------

#property indicator_separate_window
#property indicator_buffers 4
#property indicator_color1  LimeGreen
#property indicator_color2  Orange
#property indicator_color3  Orange
#property indicator_color4  Gold
#property indicator_width1  2
#property indicator_width2  2
#property indicator_width3  2
#property indicator_style4  STYLE_DOT
#property indicator_minimum 0
#property indicator_maximum 100

//
//
//
//
//

extern int    StochasticLength        = 32;
extern int    SmoothEMA               =  9;
extern int    SignalEMA               =  5;
extern int    CCIPeriod               = 14;
extern int    CCIPrice                = PRICE_TYPICAL;
extern bool   ChangeOnDirectionChange = true;

//
//
//
//
//

double dssBuffer[];
double ddaBuffer[];
double ddbBuffer[];
double sigBuffer[];
double trend[];

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

int init()
{
   IndicatorBuffers(5);
   SetIndexBuffer(0,dssBuffer);
   SetIndexBuffer(1,ddaBuffer);
   SetIndexBuffer(2,ddbBuffer);
   SetIndexBuffer(3,sigBuffer);
   SetIndexBuffer(4,trend);
      StochasticLength = MathMax(1,StochasticLength);
      SignalEMA        = MathMax(0,SignalEMA);
      SmoothEMA        = MathMax(0,SmoothEMA);
         if (SignalEMA<1) ChangeOnDirectionChange=true;

   //
   //
   //
   //
   //

   IndicatorShortName("DSS of CCI ("+StochasticLength+","+SmoothEMA+","+SignalEMA+")");
   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);

   //
   //
   //
   //
   //
   
      double alpha = 2.0 / (1.0+SignalEMA);
      if (trend[limit]==-1) CleanPoint(limit,ddaBuffer,ddbBuffer);
   	for(int i = limit; i >= 0; i--)
      {
            double rClose = iCCI(NULL,0,CCIPeriod,CCIPrice,i);
            dssBuffer[i] = iDss(rClose,rClose,rClose,StochasticLength,SmoothEMA,i);
            ddaBuffer[i] = EMPTY_VALUE;   
            ddbBuffer[i] = EMPTY_VALUE;   
            sigBuffer[i] = sigBuffer[i+1]+alpha*(dssBuffer[i]-sigBuffer[i+1]);
            trend[i]     = trend[i+1];

               if (ChangeOnDirectionChange)
                  {
                     if (dssBuffer[i]>dssBuffer[i+1]) trend[i] =  1;
                     if (dssBuffer[i]<dssBuffer[i+1]) trend[i] = -1;
                  }
               else
                  {
                     if (dssBuffer[i]>sigBuffer[i+1]) trend[i] =  1;
                     if (dssBuffer[i]<sigBuffer[i+1]) trend[i] = -1;
                  }               
               if (trend[i]==-1) PlotPoint(i,ddaBuffer,ddbBuffer,dssBuffer);                  
      }
   return(0);           
}

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

double workDss[][5];
#define _plow  0
#define _phigh 1
#define _st1   2
#define _ss1   3
#define _dss   4

double iDss(double pClose, double pHigh, double pLow, int period, int smoothPeriod, int i, int instanceNo=0)
{
   if (ArrayRange(workDss,0)!=Bars) ArrayResize(workDss,Bars); i = Bars-i-1; instanceNo*=5;

   //
   //
   //
   //
   //
   
         double alpha = 2.0 / (1.0+smoothPeriod);
            workDss[i][instanceNo+_phigh] = pHigh;
            workDss[i][instanceNo+_plow]  = pLow;
               double min   = workDss[i][instanceNo+_plow];
               double max   = workDss[i][instanceNo+_phigh];

      
         for (int k=1; k<period && (i-k)>=0; k++)
         {
            min = MathMin(min,workDss[i-k][instanceNo+_plow] );
            max = MathMax(max,workDss[i-k][instanceNo+_phigh]);
         }
         workDss[i][instanceNo+_st1] = 0; if (min!=max) workDss[i][instanceNo+_st1] = 100*(pClose-min)/(max-min);
         
         //
         //
         //
         //
         //
         
         if (i==0)
         {
               workDss[i][instanceNo+_ss1] = workDss[i][instanceNo+_st1];
               workDss[i][instanceNo+_dss] = workDss[i][instanceNo+_st1];
         }            
         else
         {
            workDss[i][instanceNo+_ss1] = workDss[i-1][instanceNo+_ss1]+alpha*(workDss[i][instanceNo+_st1]-workDss[i-1][instanceNo+_ss1]);
               min = workDss[i][instanceNo+_ss1];
               max = workDss[i][instanceNo+_ss1];
               for (k=1; k<period && (i-k)>=0; k++)
               {
                  min = MathMin(min,workDss[i-k][instanceNo+_ss1]);
                  max = MathMax(max,workDss[i-k][instanceNo+_ss1]);
               }
               double stoch = 0; if (min!=max) stoch = 100*(workDss[i][instanceNo+_ss1]-min)/(max-min);
               workDss[i][instanceNo+_dss] = workDss[i-1][instanceNo+_dss]+alpha*(stoch-workDss[i-1][instanceNo+_dss]);
         }            
            
      //
      //
      //
      //
      //
            
   return(workDss[i][instanceNo+_dss]);
}

//+-------------------------------------------------------------------
//|                                                                  
//+-------------------------------------------------------------------
//
//
//
//
//

void CleanPoint(int i,double& first[],double& second[])
{
   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 (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;
      }
}