//+------------------------------------------------------------------+
//|                                                          RCI.mq4 |
//|                                                          k-matsu |
//|                               http://www.age.jp/~k-matsu/FX/MT4/ |
//+------------------------------------------------------------------+
#property copyright "k-matsu"
#property link      "http://www.age.jp/~k-matsu/FX/MT4/"

#property indicator_separate_window
#property indicator_buffers 1
#property indicator_color1 Tan
//---- input parameters
extern int       RCIPeriod=9;
extern bool      RCImin0max100=false;
extern int       CountBarMax=0;
//---- buffers
double RCIBuffer[];
//---- internal variables
double numerator, denominator;
string shortname;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
//---- indicators
   SetIndexStyle(0,DRAW_LINE);
   SetIndexBuffer(0,RCIBuffer);
   SetLevelStyle(STYLE_DOT, 1, Gray);
//----
   // parameter check
   if (RCIPeriod < 2) RCIPeriod = 2;

   // internal variables
   denominator = RCIPeriod * (RCIPeriod * RCIPeriod - 1);
   if (RCImin0max100) {
     numerator = 300.0;
     SetLevelValue(0, 50);
   } else {
     numerator = 600.0;
     SetLevelValue(0, 0);
   }
   shortname = StringConcatenate("RCI(",RCIPeriod,")");
   IndicatorShortName(shortname);

   return(0);
  }

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
  {
   int    counted_bars=IndicatorCounted();
//----
   if (counted_bars > 0) counted_bars--;
   int i, j, k, RankEqualCount;
   int limit = Bars - MathMax(counted_bars, RCIPeriod);
   if (CountBarMax > 0) limit = MathMin(limit, CountBarMax);
   double d, RankSum, RankAverage;

   double RankArray[][2];
   if (ArrayResize(RankArray, RCIPeriod+1) != (RCIPeriod+1)*2) {
     shortname = StringConcatenate(shortname,",Fatal:ArrayResize failed.)");
     IndicatorShortName(shortname);
     return(1);
   }

   for (i = limit; i >= 0; i--) {
     for (j = 1; j <= RCIPeriod; j++) {
       RankArray[j][0] = Close[i+j-1];
       RankArray[j][1] = j;
     }
     ArraySort(RankArray, RCIPeriod, 1, MODE_DESCEND);

     for (j = 1; j <= RCIPeriod; j = k) {
       RankEqualCount = 1;
       RankSum = j;
       for (k = j+1; k <= RCIPeriod; k++) {
         if (RankArray[k][0] == RankArray[j][0]) {
           RankEqualCount++;
           RankSum += k;
         } else
           break;
       }
       RankAverage = RankSum / RankEqualCount;
       for (k = j; k < j+RankEqualCount; k++)
         RankArray[k][0] = RankAverage;
     }

     d = 0.0;
     for (j = 1; j <= RCIPeriod; j++) 
       d += MathPow(RankArray[j][1] - RankArray[j][0], 2);
     RCIBuffer[i] = 100 - numerator * d / denominator;
   }

//----
   return(0);
  }
//+------------------------------------------------------------------+