//------------------------------------------------------------------
#property copyright "mladen"
#property link      "www.forex-station.com"
#property link      "mladenfx@gmail.com"
//------------------------------------------------------------------
#property indicator_separate_window
#property indicator_buffers 5
#property indicator_color5  Silver
#property indicator_width1  2
#property indicator_width2  1
#property indicator_width3  2
#property indicator_width4  1
#property indicator_width5  3
#property strict

//
//
//
//
//

extern ENUM_TIMEFRAMES TimeFrame       = PERIOD_CURRENT; // Time frame to use
extern int             CCIPeriod       = 50;             // CCI period
extern int             StochPeriod     = 30;             // Stochastic period
extern int             StochSlowing    =  3;             // Stochastic slowing (smoothing)
extern ENUM_STO_PRICE  StochPrice      =  0;             // Stochastic price
extern double          OverSold        = -100;           // Over-sold level
extern double          OverBought      =  100;           // Over-bought level
extern color           OverSoldColor   = clrLimeGreen;   // Over-sold color
extern color           OverBoughtColor = clrDarkOrange;  // Over-bought color
extern bool            Interpolate     = true;           // Interpolate in multi time frame mode?

double cci[],cciUpa[],cciUpb[],cciDna[],cciDnb[],prices[],trend[],slope[],count[];
string indicatorFileName;
#define _mtfCall(_buff,_ind) iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,CCIPeriod,StochPeriod,StochSlowing,StochPrice,OverSold,OverBought,OverSoldColor,OverBoughtColor,_buff,_ind)

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

int init()
{
   IndicatorBuffers(9);
      SetIndexBuffer(0,cciUpa); SetIndexStyle(0,DRAW_HISTOGRAM,EMPTY,EMPTY,OverSoldColor);
      SetIndexBuffer(1,cciUpb); SetIndexStyle(1,DRAW_HISTOGRAM,EMPTY,EMPTY,OverSoldColor);
      SetIndexBuffer(2,cciDna); SetIndexStyle(2,DRAW_HISTOGRAM,EMPTY,EMPTY,OverBoughtColor);
      SetIndexBuffer(3,cciDnb); SetIndexStyle(3,DRAW_HISTOGRAM,EMPTY,EMPTY,OverBoughtColor);
      SetIndexBuffer(4,cci);
      SetIndexBuffer(5,prices);
      SetIndexBuffer(6,trend);
      SetIndexBuffer(7,slope);
      SetIndexBuffer(8,count);
         SetLevelValue(0,OverBought);
         SetLevelValue(1,OverSold);
         
         //
         //
         //
         //
         //
         
         indicatorFileName = WindowExpertName();
         TimeFrame         = MathMax(TimeFrame,_Period);
   IndicatorShortName(timeFrameToString(TimeFrame)+" CCI of stochastic ("+(string)CCIPeriod+","+(string)StochPeriod+","+(string)StochSlowing+")");
   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); count[0] = limit;
            if (TimeFrame!=_Period)
            {
               limit = (int)MathMax(limit,MathMin(Bars-1,_mtfCall(8,0)*TimeFrame/_Period));
               for(int i=limit; i>=0; i--)
               {
                  int y = iBarShift(NULL,TimeFrame,Time[i]);
                     cci[i]    = _mtfCall(4,y);
                     trend[i]  = _mtfCall(6,y);
                     slope[i]  = _mtfCall(7,y);
                     cciUpa[i] = EMPTY_VALUE;
                     cciUpb[i] = EMPTY_VALUE;
                     cciDna[i] = EMPTY_VALUE;
                     cciDnb[i] = EMPTY_VALUE;
                  
                     //
                     //
                     //
                     //
                     //
                  
                     if (!Interpolate || (i>0 && y==iBarShift(NULL,TimeFrame,Time[i-1]))) continue;
                        #define _interpolate(buff) buff[i+k] = buff[i]+(buff[i+n]-buff[i])*k/n
                           int n,k; datetime time = iTime(NULL,TimeFrame,y);
                              for(n = 1; (i+n)<Bars && Time[i+n] >= time; n++) continue;	
                              for(k = 1; k<n && (i+n)<Bars && (i+k)<Bars; k++) _interpolate(cci);
               }
               for(int i=limit; i>=0; i--)
               {
                  if (trend[i]== 1) if (slope[i]== 1) cciUpa[i] = cci[i]; else  cciUpb[i] = cci[i];
                  if (trend[i]==-1) if (slope[i]==-1) cciDna[i] = cci[i]; else  cciDnb[i] = cci[i];
               }      
               return(0);
            }               

   //
   //
   //
   //
   //

      for(int i=limit; i>=0; i--)
      {
         prices[i]  = iStochastic(NULL,0,StochPeriod,1,StochSlowing,MODE_SMA,StochPrice,MODE_MAIN,i);
         double avg = 0; for(int k=0; k<CCIPeriod && (i+k)<Bars; k++) avg +=         prices[i+k];      avg /= CCIPeriod;
         double dev = 0; for(int k=0; k<CCIPeriod && (i+k)<Bars; k++) dev += MathAbs(prices[i+k]-avg); dev /= CCIPeriod;
         
            //
            //
            //
            //
            //
         
            cci[i]    = (dev!=0) ? (prices[i]-avg)/(0.015*dev) : 0;
            cciUpa[i] = EMPTY_VALUE;
            cciUpb[i] = EMPTY_VALUE;
            cciDna[i] = EMPTY_VALUE;
            cciDnb[i] = EMPTY_VALUE;
            trend[i]  = (cci[i]>OverBought) ? 1 : (cci[i]<OverSold) ? -1 : 0;
            slope[i]  = (i<Bars-1) ? (cci[i]>cci[i+1]) ? 1 : (cci[i]<cci[i+1]) ? -1 : slope[i+1] : 0;
               if (trend[i]== 1) if (slope[i]== 1) cciUpa[i] = cci[i]; else  cciUpb[i] = cci[i];
               if (trend[i]==-1) if (slope[i]==-1) cciDna[i] = cci[i]; else  cciDnb[i] = cci[i];
      }
      return(0);
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//

string sTfTable[] = {"M1","M5","M15","M30","H1","H4","D1","W1","MN"};
int    iTfTable[] = {1,5,15,30,60,240,1440,10080,43200};

string timeFrameToString(int tf)
{
   for (int i=ArraySize(iTfTable)-1; i>=0; i--) 
         if (tf==iTfTable[i]) return(sTfTable[i]);
                              return("");
}