//|--------------------------------------------------------------------------------------------------------------------+
//| https://www.tradingview.com/wiki/Connors_RSI_(CRSI)                                                                |
//| There are three major components to Connors RSI                                                                    |
//|                                                                                                                    |
//| RSI = Standard RSI developed by Wilder.                                                                            |
//|   This is typically a short-term RSI. In this example it is defaulted at 3 Period RSI.                             |
//|                                                                                                                    |
//| UpDown Length = The number of consecutive days that a security price has  either                                    |
//|   closed up (higher than previous day) or                                                                          |
//|   closed down (lower than previous days).                                                                          |
//|     Closing up values represented in positive numbers and closing down is represented with negative numbers.       |
//|     If a security closes at the same price on back to back days, the UpDown Length is 0.                           |
//|     Connors RSI then applies a short-term RSI to the UpDown Streak Value. In this example it is a 2 period RSI.    |
//|                                                                                                                    |
//| ROC = The Rate-of-Change.                                                                                          |
//|   The ROC takes a user-defined look-back period and calculates a percentage of the number of values                |
//|   within that look back period that are below the current day price change percentage.                             |
//|                                                                                                                    |
//| The final CRSI calculation then simply finding the average value of the three components.                          |
//| CRSI(3,2,100) = [ RSI(3) + RSI(UpDown Length,2) + ROC(100) ] / 3                                                   |
//+--------------------------------------------------------------------------------------------------------------------+
#property copyright "mladen"
#property link      "www.forex-tsd.com"
//https://www.forexfactory.com/showthread.php?p=10854915#post10854915
//https://www.mql5.com/en/forum/200210
#property strict
//------------------------------------------------------------------
#property indicator_separate_window
#property indicator_buffers 7
//
extern int RsiPeriod    = 3;
extern int UpDownPeriod = 2;
extern int ROCPeriod    = 100;
extern int Price        = PRICE_CLOSE;
//
//========== Indicator Configuration Data ==========================
enum ENUM_INDI_BUFFS                 { C_RSI_IDX = 0,      UPDN_HIST_IDX,    UPDN_STREAK_VAL_IDX,  UPDN_RSI_IDX,   BAR_PCT_CHNG_IDX,    ROC_IDX,        RSI_IDX,    endIndiBuffIdx };
string          lineName[]         = { "CONNER_RSi2",      "UP_DN_HISTORY",  "UP_DN_STREAK",       "UPDN_RSI",     "BAR_PERCENT_CHNG",  "CHANGE_RATE",  "CHART_RSI" };
color           lineColor[]        = { clrLimeGreen,       clrAquamarine,    clrAliceBlue,         clrOrchid,      clrBisque,           clrYellow,      clrMediumSlateBlue  };
int             lineWidth[]        = {  1,                  1,                1,                    1,               1,                  1,              1            };
ENUM_LINE_STYLE lineStyle[]        = { STYLE_SOLID,        STYLE_SOLID,      STYLE_SOLID,          STYLE_SOLID,     STYLE_SOLID,        STYLE_SOLID,    STYLE_SOLID   };
int             lineDraw[]         = { DRAW_LINE,          DRAW_NONE,        DRAW_NONE,            DRAW_NONE,       DRAW_NONE,          DRAW_NONE,      DRAW_NONE     };
double          buffInitVal[]      = { EMPTY_VALUE,        0.0,              0.0,                  0.0,             0.0,                0.0,            EMPTY_VALUE   };
struct IndiStruct
 {
   double indiBuff[];
 } indiStruct[endIndiBuffIdx];
//======== End Indicator Configuration Data =======================
int    minBars;
string shortName = "Connors_RSI_forex-tsd";
string commentStr = "";
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
 {
   ENUM_INIT_RETCODE returnCode = INIT_SUCCEEDED;
   int arry_minBars[3]; arry_minBars[0] = RsiPeriod; arry_minBars[1] = UpDownPeriod;  arry_minBars[2] = ROCPeriod;
   minBars = arry_minBars[ArrayMaximum(arry_minBars,WHOLE_ARRAY,0)]+2;
   if(Bars<minBars)
    {
      commentStr = __FUNCTION__+" Not enough bars for "+shortName+", requires "+IntegerToString(minBars)+", found "+IntegerToString(Bars)+" bars.";
      Comment(commentStr); Print(commentStr);
    }
   initializeBuffers();
   //
   return(returnCode);
 }
void initializeBuffers(void)
 {
   IndicatorBuffers(endIndiBuffIdx);
   IndicatorSetDouble(INDICATOR_MINIMUM, 0);
   IndicatorSetDouble(INDICATOR_MAXIMUM, 100);
   IndicatorSetInteger(INDICATOR_LEVELCOLOR, clrIvory);
   IndicatorSetInteger(INDICATOR_LEVELSTYLE, STYLE_DOT);
   IndicatorSetInteger(INDICATOR_LEVELWIDTH, 1);
   IndicatorSetDouble(INDICATOR_LEVELVALUE, 0, 5);
   IndicatorSetDouble(INDICATOR_LEVELVALUE, 1, 95);
   for(int idx=0; idx<endIndiBuffIdx; idx++)
    {
      initializeIndiBuff(indiStruct[idx].indiBuff, idx, lineName[idx], lineDraw[idx], lineStyle[idx], lineColor[idx], lineWidth[idx], buffInitVal[idx]);
    }   
 }
void initializeIndiBuff( double& buffer[], const int& buffNum, const string& label, const int& draw, const ENUM_LINE_STYLE& lStyle, const color& lClr, const int lWidth, const double& initVal )
 {
   SetIndexBuffer    ( buffNum, buffer );
   SetIndexLabel     ( buffNum, label );
   SetIndexStyle     ( buffNum, draw, lStyle, lWidth, lClr );
   SetIndexShift     ( buffNum, 0 );
   SetIndexEmptyValue( buffNum, initVal );
   SetIndexDrawBegin ( buffNum, 0 );
 }
//+------------------------------------------------------------------+
//| Custor indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
 {
   if(StringLen(commentStr)>0)
    {
      Comment("");
    }
 }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[],
                const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[])
 {
   int limit;
   if(prev_calculated<1) // first time
    {
      if(rates_total<minBars)
       {
         return(0);
       }
      limit = rates_total-minBars;
    }
   else
    {
      limit = rates_total-prev_calculated;
    }
   runTheIndicator(limit);
   //       
   return(rates_total);
 }
void runTheIndicator(const int& limit)
 {
   
   for(int i=limit; i>=0; i--)
    {
      indiStruct[UPDN_HIST_IDX].indiBuff[i] = iMA(NULL,0,1,0,MODE_SMA,Price,i);
      if (indiStruct[UPDN_HIST_IDX].indiBuff[i] == indiStruct[UPDN_HIST_IDX].indiBuff[i+1])
       {
         indiStruct[UPDN_STREAK_VAL_IDX].indiBuff[i] = 0;
       }
      else if(indiStruct[UPDN_HIST_IDX].indiBuff[i] <  indiStruct[UPDN_HIST_IDX].indiBuff[i+1])
       {
         if (indiStruct[UPDN_STREAK_VAL_IDX].indiBuff[i+1] > 0)
            indiStruct[UPDN_STREAK_VAL_IDX].indiBuff[i] = -1;
         else
            indiStruct[UPDN_STREAK_VAL_IDX].indiBuff[i] = indiStruct[UPDN_STREAK_VAL_IDX].indiBuff[i+1]-1;
       }
      else if (indiStruct[UPDN_HIST_IDX].indiBuff[i] >  indiStruct[UPDN_HIST_IDX].indiBuff[i+1])
       {
         if (indiStruct[UPDN_STREAK_VAL_IDX].indiBuff[i+1] < 0)
            indiStruct[UPDN_STREAK_VAL_IDX].indiBuff[i] =  1;
         else
            indiStruct[UPDN_STREAK_VAL_IDX].indiBuff[i] = indiStruct[UPDN_STREAK_VAL_IDX].indiBuff[i+1]+1;
       }
    }
   for(int i=limit; i>=0; i--)
    {   
      indiStruct[RSI_IDX].indiBuff[i] = iRSI(NULL,0,RsiPeriod,Price,i);  // Standard RSI developed by Wilder.
      //
      indiStruct[UPDN_RSI_IDX].indiBuff[i] = iRSIOnArray(indiStruct[UPDN_STREAK_VAL_IDX].indiBuff,WHOLE_ARRAY,UpDownPeriod,i);
      indiStruct[ROC_IDX].indiBuff[i]  = 0;
      if (indiStruct[UPDN_HIST_IDX].indiBuff[i+1]!=0)
         indiStruct[ROC_IDX].indiBuff[i] = (indiStruct[UPDN_HIST_IDX].indiBuff[i]/indiStruct[UPDN_HIST_IDX].indiBuff[i+1]-1.0)*100.0;
      //
      indiStruct[BAR_PCT_CHNG_IDX].indiBuff[i] = 0;
      for (int k=1; k<=ROCPeriod; k++)
       {
         if (indiStruct[ROC_IDX].indiBuff[i] >= indiStruct[ROC_IDX].indiBuff[i+k])
            indiStruct[BAR_PCT_CHNG_IDX].indiBuff[i]++;
         indiStruct[BAR_PCT_CHNG_IDX].indiBuff[i] = (indiStruct[BAR_PCT_CHNG_IDX].indiBuff[i] / ROCPeriod) * 100;
       }
      //
      indiStruct[C_RSI_IDX].indiBuff[i] = (indiStruct[RSI_IDX].indiBuff[i] + indiStruct[UPDN_RSI_IDX].indiBuff[i] + indiStruct[BAR_PCT_CHNG_IDX].indiBuff[i]) / 3.0;
    }
 }
//