//------------------------------------------------------------------
#property copyright "mladen"
#property link      ""
//------------------------------------------------------------------
#property indicator_separate_window
#property indicator_buffers 4
#property indicator_color1  clrSilver
#property indicator_color2  clrLimeGreen
#property indicator_color3  clrOrange
#property indicator_color4  clrOrange
#property indicator_width2  2
#property indicator_width3  2
#property indicator_width4  2

//
//
//
//
//

extern ENUM_TIMEFRAMES    TimeFrame       = PERIOD_CURRENT;
extern int                RsiPeriod       = 14;
extern ENUM_APPLIED_PRICE RsiPrice        = PRICE_CLOSE;
extern int                AmaPeriod       = 10;
extern int                AmaNfast        = 2;
extern int                AmaNslow        = 30;
extern double             AmaGCoeff       = 2;
extern bool               Interpolate      = true;

//
//
//
//
//

double rsi[];
double kAMAbuffer[];
double kAMAbufferda[];
double kAMAbufferdb[];
double slope[];

string indicatorFileName;
bool   returnBars;

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

int init()
{
   IndicatorBuffers(5);
   SetIndexBuffer(0,rsi);
   SetIndexBuffer(1,kAMAbuffer);
   SetIndexBuffer(2,kAMAbufferda);
   SetIndexBuffer(3,kAMAbufferdb);
   SetIndexBuffer(4,slope);
   
   //
   //
   //
   //
   //
   
      indicatorFileName = WindowExpertName();
      returnBars        = TimeFrame==-99;
      TimeFrame         = MathMax(TimeFrame,_Period);
   
   IndicatorShortName(timeFrameToString(TimeFrame)+" Kaufman AMA of RSI ("+AmaPeriod+","+RsiPeriod+")");
   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);
         if (returnBars)  { kAMAbuffer[0] = limit+1; return(0); } 

   //
   //
   //
   //
   //
   
   if (TimeFrame == Period())
   {  
     if (slope[limit]==-1) CleanPoint(limit,kAMAbufferda,kAMAbufferdb);
     for(int i=limit; i>=0; i--)
     {
        rsi[i]          = iRSI(NULL,0,RsiPeriod,RsiPrice,i);
        kAMAbuffer[i]   = iKama(rsi[i],AmaPeriod,AmaNfast,AmaNslow,AmaGCoeff,i);
        kAMAbufferda[i] = EMPTY_VALUE;
        kAMAbufferdb[i] = EMPTY_VALUE;
        slope[i]        = slope[i+1];
           if (kAMAbuffer[i]>kAMAbuffer[i+1]) slope[i] =  1;
           if (kAMAbuffer[i]<kAMAbuffer[i+1]) slope[i] = -1;
           if (slope[i]==-1) PlotPoint(i,kAMAbufferda,kAMAbufferdb,kAMAbuffer);
     }      
     return(0);
   }
   
   //
   //
   //
   //
   //
   
    limit = MathMax(limit,MathMin(Bars-1,iCustom(NULL,TimeFrame,indicatorFileName,-99,0,0)*TimeFrame/Period()));
    if (slope[limit]==-1) CleanPoint(limit,kAMAbufferda,kAMAbufferdb);
    for(i=limit; i >= 0; i--)  
    {
       int y = iBarShift(NULL,TimeFrame,Time[i]);
          rsi[i]          = iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,RsiPeriod,RsiPrice,AmaPeriod,AmaNfast,AmaNslow,AmaGCoeff,0,y);
          kAMAbuffer[i]   = iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,RsiPeriod,RsiPrice,AmaPeriod,AmaNfast,AmaNslow,AmaGCoeff,1,y);
          slope[i]        = iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,RsiPeriod,RsiPrice,AmaPeriod,AmaNfast,AmaNslow,AmaGCoeff,4,y);
          kAMAbufferda[i] = EMPTY_VALUE;
          kAMAbufferdb[i] = EMPTY_VALUE;
         
          //
          //
          //
          //
          //
      
          if (!Interpolate || y==iBarShift(NULL,TimeFrame,Time[i-1])) continue;

          //
          //
          //
          //
          //

          datetime time = iTime(NULL,TimeFrame,y);
             for(int n = 1; i+n < Bars && Time[i+n] >= time; n++) continue;
             for(int x = 1; x < n; x++) 
             {
                rsi[i+x]        = rsi[i]        + (rsi[i+n]        - rsi[i]       ) * x/n;
                kAMAbuffer[i+x] = kAMAbuffer[i] + (kAMAbuffer[i+n] - kAMAbuffer[i]) * x/n;
             }               
   }
   for (i=limit;i>=0;i--)  if (slope[i]==-1) PlotPoint(i,kAMAbufferda,kAMAbufferdb,kAMAbuffer);  
   return(0);
}
  
//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//

double  kWork[][3];
#define _kprice 0
#define _kdiff  1
#define _kama   2

double iKama(double tprice, int period, double gFast, double gSlow, double gCoeff, int i, int instanceNo=0)
{
   if (ArrayRange(kWork,0)!=Bars) ArrayResize(kWork,Bars); int r = Bars-i-1; instanceNo*=3; kWork[r][instanceNo+_kprice] = tprice;
   if (r < period) { kWork[r][instanceNo+_kama] = tprice; kWork[r][instanceNo+_kdiff] = 0; return(kWork[r][instanceNo+_kama]); }
   
   //
   //
   //
   //
   //
   
   double efratio = 1.00;
   double fastend = (2.0 /(gFast + 1));
   double slowend = (2.0 /(gSlow + 1));
   double smooth;
   double signal;
   double noise = 0;
          signal                      = MathAbs(kWork[r][instanceNo+_kprice]-kWork[r-period][instanceNo+_kprice]);
          kWork[r][instanceNo+_kdiff] = MathAbs(kWork[r][instanceNo+_kprice]-kWork[r-1][instanceNo+_kprice]);
          for (int k=0;k<period;k++)
                  noise += kWork[r-k][instanceNo+_kdiff];

          //
          //
          //
          //
          //

          if (noise != 0) efratio = signal/noise;
                          smooth                     = MathPow(efratio*(fastend-slowend)+slowend,gCoeff);
                          kWork[r][instanceNo+_kama] = kWork[r-1][instanceNo+_kama] + smooth*(kWork[r][instanceNo+_kprice]-kWork[r-1][instanceNo+_kama]);
   return(kWork[r][instanceNo+_kama]);
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

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; }
}

//+-------------------------------------------------------------------
//|                                                                  
//+-------------------------------------------------------------------
//
//
//
//
//

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("");
}