//+------------------------------------------------------------------+
//|                                        dynamic zone smoothed rsi |
//|                                                           mladen |
//+------------------------------------------------------------------+
#property copyright "mladen"
#property link      "mladenfx@gmail.com"

#property indicator_separate_window
#property indicator_buffers 3
#property indicator_color1  DeepSkyBlue
#property indicator_color2  LimeGreen
#property indicator_color3  Red
#property indicator_width1  2
#property indicator_minimum 0
#property indicator_maximum 100

//
//
//
//
//

extern int    RsiLength              = 9;
extern int    RsiPrice               = PRICE_CLOSE;
extern bool   RsiSmooth              = true;
extern int    FlPeriod               = 70;
extern double FlUp                   = 90;
extern double FlDown                 = 10;

//
//
//
//
//

double rsi[];
double bli[];
double sli[];
double prc[];
double buff[];

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

int init()
{
   IndicatorBuffers(5);
   SetIndexBuffer(0,rsi);
   SetIndexBuffer(1,bli);
   SetIndexBuffer(2,sli);
   SetIndexBuffer(3,prc);
   SetIndexBuffer(4,buff);

   //
   //
   //
   //
   //
   
   string PriceType;
      switch(RsiPrice)
      {
         case PRICE_CLOSE:    PriceType = "Close";    break;  // 0
         case PRICE_OPEN:     PriceType = "Open";     break;  // 1
         case PRICE_HIGH:     PriceType = "High";     break;  // 2
         case PRICE_LOW:      PriceType = "Low";      break;  // 3
         case PRICE_MEDIAN:   PriceType = "Median";   break;  // 4
         case PRICE_TYPICAL:  PriceType = "Typical";  break;  // 5
         case PRICE_WEIGHTED: PriceType = "Weighted"; break;  // 6
      }      

   //
   //
   //
   //
   //

   RsiLength = MathMax(RsiLength ,1);
   string addName = "";
      if (RsiSmooth) addName = "smoothed ";
   IndicatorShortName ("Quantile bands "+addName+"RSI ("+RsiLength+","+PriceType+","+FlPeriod+","+DoubleToStr(FlUp,3)+","+DoubleToStr(FlDown,3)+")");
   return(0);
}
int deinit()
{
   return(0);
}

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

int start()
{
   int counted_bars=IndicatorCounted();
   int i,limit;

   if(counted_bars<0) return(-1);
   if(counted_bars>0) counted_bars--;
         limit = MathMin(Bars-counted_bars,Bars-1);

   //
   //
   //
   //
   //
   //

   for(i=limit; i >= 0; i--)
   {
      prc[i] = iMA(NULL,0,1,0,MODE_SMA,RsiPrice,i);
      
      //
      //
      //
      //
      //
      
      if (i>=Bars-RsiLength) continue;

         //
         //
         //
         //
         //
         
         double cu = 0;
         double cd = 0;
         for (int k=0; k<RsiLength; k++)
            {
               double diff = prc[i+k]-prc[i+k+1];
                  if (diff > 0) cu += diff;
                  if (diff < 0) cd -= diff;
            }
         if ((cu+cd)!=0)
               buff[i] = 50.0*((cu-cd)/(cu+cd)+1.0);
         else  buff[i] = 0;
         if (RsiSmooth)
               rsi[i] = (buff[i] + 2.0*buff[i+1] + buff[i+2])/4.0;
         else  rsi[i] = (buff[i]);
         sli[i] = iQuantile(FlPeriod,FlUp  ,rsi,i);
         bli[i] = iQuantile(FlPeriod,FlDown,rsi,i);
   }
   return(0);
}

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

double workQuant[];
double iQuantile(int period, double qp, double& sourceArray[],int i)
{
   ArrayCopy(workQuant,sourceArray,0,i,period);
   ArraySort(workQuant);

   //
   //
   //
   //
   //
   
   double index = (period-1)*qp/100.00;
   int    ind   = (int)index;
   double delta = index - ind;
   if (ind == NormalizeDouble(index,5))
         return(            workQuant[ind]);
   else  return((1.0-delta)*workQuant[ind]+delta*workQuant[ind+1]);
}