//+------------------------------------------------------------------+
//|                                           inverse fisher rvi.mq4 |
//|                             translated from Mladen's mt5 version |
//+------------------------------------------------------------------+
#property copyright "www.forex-station.com"
#property link      "www.forex-station.com"

#property indicator_separate_window
#property indicator_buffers 4
#property indicator_color1  clrDeepSkyBlue
#property indicator_color2  clrLightSalmon
#property indicator_color3  clrLightSalmon
#property indicator_color4  clrDarkGray
#property indicator_width1  2
#property indicator_width2  2
#property indicator_width3  2
#property strict

extern ENUM_TIMEFRAMES   TimeFrame   = PERIOD_CURRENT;  // Time frame
input int                inpRviPeriod = 32;             // RVI period
input bool               Interpolate = true;            // Interpolate in multi time frame mode on/off?

double val[],valDa[],valDb[],valc[],sig[],rvi[],count[];
string indicatorFileName;
#define _mtfCall(_buff,_ind) iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,inpRviPeriod,_buff,_ind)
//
//
//
//
//

int OnInit()
{
   IndicatorBuffers(7);
   SetIndexBuffer(0,val,INDICATOR_DATA);    SetIndexStyle(0,DRAW_LINE);
   SetIndexBuffer(1,valDa,INDICATOR_DATA);  SetIndexStyle(1,DRAW_LINE);
   SetIndexBuffer(2,valDb,INDICATOR_DATA);  SetIndexStyle(2,DRAW_LINE);
   SetIndexBuffer(3,sig,INDICATOR_DATA);    SetIndexStyle(3,DRAW_LINE);
   SetIndexBuffer(4,rvi,INDICATOR_CALCULATIONS);
   SetIndexBuffer(5,valc,INDICATOR_CALCULATIONS);
   SetIndexBuffer(6,count);
   SetLevelValue(0,0);
   
   indicatorFileName = WindowExpertName();
   TimeFrame         = fmax(TimeFrame,_Period); 
   
   IndicatorSetString(INDICATOR_SHORTNAME,timeFrameToString(TimeFrame)+" Fisher RVI ("+(string)inpRviPeriod+")");
   
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason){   }
//+------------------------------------------------------------------+
//| 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 i,limit=fmin(rates_total-prev_calculated+1,rates_total-1); count[0] = limit;
      
       if (TimeFrame!=_Period)
      {
         limit = (int)fmax(limit,fmin(rates_total-1,_mtfCall(6,0)*TimeFrame/_Period));
         if (valc[limit]==-1) CleanPoint(limit,valDa,valDb);
         for (i=limit;i>=0 && !_StopFlag; i--)
         {
            int y = iBarShift(NULL,TimeFrame,time[i]);
               val[i]   = _mtfCall(0,y);
               sig[i]   = _mtfCall(3,y);
               valDa[i] = valDb[i]  = EMPTY_VALUE;
              
               valc[i] = _mtfCall(5,y);
                     
               //
               //
               //
                     
               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 dtime = iTime(NULL,TimeFrame,y);
                  for(n = 1; (i+n)<rates_total && time[i+n] >= dtime; n++) continue;	
                  for(k = 1; k<n && (i+n)<rates_total && (i+k)<rates_total; k++) 
                  {
                     _interpolate(val); 
                     _interpolate(sig);
                    
                  }                    
         } 
         for(i=limit;i>=0; i--) if (valc[i] ==-1) PlotPoint(i,valDa,valDb,val);
         
   return(rates_total);
   } 
      //
      
      if (valc[limit]==-1) CleanPoint(limit,valDa,valDb);
      for(i=limit; i>=0; i--)
      {
         double num   = 0.0;
         double denom = 0.0;
         for(int k=0; k<inpRviPeriod && (i+k+3)<rates_total; k++)
         {
            num   += close[i+k]-open[i+k]+2*(close[i+k+1]-open[i+k+1])+2*(close[i+k+2]-open[i+k+2])+close[i+k+3]-open[i+k+3];
            denom += high[i+k] -low[i+k] +2*(high[i+k+1] -low[i+k+1]) +2*(high[i+k+2] -low[i+k+2]) +high[i+k+3] -low[i+k+3];
         }
         rvi[i]=(denom!=0.0) ? num/denom : 0;
         double lo    = rvi[ArrayMinimum(rvi,inpRviPeriod,i)];
         double hi    = rvi[ArrayMaximum(rvi,inpRviPeriod,i)];
         double stoRvi = (hi!=lo) ? fmax(fmin(2.0*((rvi[i]-lo)/(hi-lo)-0.5),0.99999),-0.99999) : 0;
         
         //
         //
         //
         //
         //
         
         val[i]   = (exp(2*stoRvi)-1)/(exp(2*stoRvi)+1);
         sig[i]   = (i<rates_total-1) ? val[i+1] : val[i];
         valDa[i] = EMPTY_VALUE;
         valDb[i] = EMPTY_VALUE;
         valc[i]  = (val[i]>sig[i]) ? 1 :(val[i]<sig[i]) ? -1 :(i<rates_total-1) ? valc[i+1]: 0;
         if (valc[i] ==-1) PlotPoint(i,valDa,valDb,val);
     }
return (rates_total);
}

//-------------------------------------------------------------------
//                                                                  
//-------------------------------------------------------------------
//
//
//
//
//

void CleanPoint(int i,double& first[],double& second[])
{
   if (i>=Bars-3) return;
   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 (i>=Bars-2) return;
   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("");
}