//+------------------------------------------------------------------
#property copyright "www.forex-tsd.com"
#property link      "www.forex-tsd.com"
//+------------------------------------------------------------------
#property indicator_separate_window
#property indicator_buffers 2
#property indicator_color1  clrDeepSkyBlue
#property indicator_color2  clrRed
#property indicator_width1  1
#property indicator_style2  STYLE_DOT
#property indicator_minimum 0
#property indicator_maximum 100
#property strict

//AHTF Timeframe template copy and paste start11
enum enTimeFrames
{
   tf_cu  = PERIOD_CURRENT, // Current time frame
   tf_m1  = PERIOD_M1,      // 1 minute
   tf_m5  = PERIOD_M5,      // 5 minutes
   tf_m15 = PERIOD_M15,     // 15 minutes
   tf_m30 = PERIOD_M30,     // 30 minutes
   tf_h1  = PERIOD_H1,      // 1 hour
   tf_h4  = PERIOD_H4,      // 4 hours
   tf_d1  = PERIOD_D1,      // Daily
   tf_w1  = PERIOD_W1,      // Weekly
   tf_mn1 = PERIOD_MN1,     // Monthly
   tf_n1  = -1,             // First higher time frame
   tf_n2  = -2,             // Second higher time frame
   tf_n3  = -3,             // Third higher time frame
   tf_n4  = -4              // Fourth higher time frame
};
//AHTF Timeframe template copy and paste end11

//AHTF Timeframe template copy and paste start12
extern enTimeFrames       TimeFrame      = tf_cu;          // Time frame
//AHTF Timeframe template copy and paste end12

extern int                RsqPeriod      = 6;              // R-squared period
extern ENUM_APPLIED_PRICE RsqPrice       = PRICE_CLOSE;    // Price  
extern int                RsqAverage     = 5;              // R-squared average period
extern ENUM_MA_METHOD     RsqAverageMode = MODE_LWMA;      // R-squared average method
extern bool               Interpolate    = true;           // Interpolate in multi time frame mode?

double rsq[], rsqavg[];
string indicatorFileName;
bool   returnBars;
//+------------------------------------------------------------------------------------------------------------------+
int init()
{
   SetIndexBuffer(0,rsq);
   SetIndexLabel (0, " R-Squared (" + (string)RsqPeriod + ")");
   SetIndexBuffer(1, rsqavg);
   SetIndexLabel (1, " MA (" + (string)RsqAverage + ")");
   
      //
      //
      //
      //
      //
      
         indicatorFileName = WindowExpertName();
         returnBars        = TimeFrame==-99;

//AHTF Timeframe template copy and paste start13
   TimeFrame         = (enTimeFrames)timeFrameValue(TimeFrame);
//AHTF Timeframe template copy and paste end13

      IndicatorShortName(timeFrameToString(TimeFrame)+ " R-Squared (" + (string)RsqPeriod + ")");
   return(0);
}
//+------------------------------------------------------------------------------------------------------------------+
//AHTF Timeframe template copy and paste start14
int timeFrameValue(int _tf)
{
   int add  = (_tf>=0) ? 0 : MathAbs(_tf);
   if (add != 0) _tf = _Period;
   int size = ArraySize(iTfTable); 
      int i =0; for (;i<size; i++) if (iTfTable[i]==_tf) break;
                                   if (i==size) return(_Period);
                                                return(iTfTable[(int)MathMin(i+add,size-1)]);
}
//AHTF Timeframe template copy and paste end14
//+------------------------------------------------------------------------------------------------------------------+
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) { rsq[0] = MathMin(limit+1,Bars-1); return(0); }
   
   //
   //
   //
   //
   //
   
   if (TimeFrame == _Period)
   {
      for(int i=limit; i>=0; i--) rsq[i]    = iRsq(iMA(NULL,0,1,0,MODE_SMA,RsqPrice,i),RsqPeriod,i);
      for(int i=limit; i>=0; i--) rsqavg[i] = iMAOnArray(rsq,0,RsqAverage,0,RsqAverageMode,i);
      return(0);
   }
   
   //
   //
   //
   //
   //

   limit = (int)MathMax(limit,MathMin(Bars-1,iCustom(NULL,TimeFrame,indicatorFileName,-99,0,0)*TimeFrame/_Period));
   for (int i=limit; i>=0; i--)
   {
      int y = iBarShift(NULL,TimeFrame,Time[i]);
         rsq[i]    = iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,RsqPeriod,RsqPrice,RsqAverage,RsqAverageMode,0,y);
         rsqavg[i] = iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,RsqPeriod,RsqPrice,RsqAverage,RsqAverageMode,1,y);
         if (!Interpolate || (i>0 && y==iBarShift(NULL,TimeFrame,Time[i-1]))) continue;
                  
         //
         //
         //
         //
         //
                  
         int n,j; datetime time = iTime(NULL,TimeFrame,y);
           for(n = 1; (i+n)<Bars && Time[i+n] >= time; n++) continue;	
           for(j = 1; j<n && (i+n)<Bars && (i+j)<Bars; j++)
           {
              rsq[i+j]    = rsq[i]    + (rsq[i+n]   -rsq[i]   )*j/n;
              rsqavg[i+j] = rsqavg[i] + (rsqavg[i+n]-rsqavg[i])*j/n;
           }                           
   }
   return(0);
}   
//+------------------------------------------------------------------------------------------------------------------+
double workr[][1];
double iRsq(double price, double period, int i, int instanceNo=0)
{
   if (ArrayRange(workr,0) != Bars) ArrayResize(workr,Bars); i = Bars-i-1;
  
   //
   //
   //
   //
   //

      workr[i][instanceNo] = price;

         double SumX  = 0;
         double SumXX = 0;
         double SumXY = 0;
         double SumYY = 0;
         double SumY  = 0;
 
                  for(int k=0; k<period && (i-k)>=0; k++)
                  {
                     double tprice = workr[i-k][instanceNo];
                        SumX  += (k+1); 
                        SumXX += (k+1)*(k+1);
                        SumXY += (k+1)*tprice;
                        SumYY +=       tprice*tprice;
                        SumY  +=       tprice;
                  }
   
         double Q1  = SumXY - SumX*SumY/period;
         double Q2  = SumXX - SumX*SumX/period;
         double Q3  = SumYY - SumY*SumY/period;
         return(100.0*(Q1*Q1)/(Q2*Q3));
}
//+------------------------------------------------------------------------------------------------------------------+
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("");
}
//+------------------------------------------------------------------------------------------------------------------+
