//+------------------------------------------------------------------+
//|                        Smoothed RSI Inverse Fisher Transform.mq4 |
//|                                     © 2011 MaryJane@ForexFactory |
//|   Indicator formula © 2010 Sylvain Vervoort, http://stocata.org/ |
//+------------------------------------------------------------------+

#property indicator_separate_window
#property indicator_buffers 1
#property indicator_color1 Blue
#property indicator_width1 3
#property indicator_level1 12
#property indicator_level2 88
#property indicator_levelcolor DarkGray
//--- input parameters
extern int       RsiPeriod=4;
extern int       EmaPeriod=4;
//--- buffers
double wma0[], wma1[], wma2[], wma3[], wma4[], wma5[], wma6[], wma7[], wma8[], wma9[];
double ema0[], ema1[], rainbow[], rsi[], srsi[], fish[];
int OldTime, OldBars;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
   {
//---- indicators
   IndicatorBuffers(6); 
   SetIndexStyle(0, DRAW_LINE);
   SetIndexBuffer(0, fish);
   SetIndexBuffer(1, rainbow);
   SetIndexBuffer(2, rsi);
   SetIndexBuffer(3, ema0);
   SetIndexBuffer(4, ema1);
   SetIndexBuffer(5, srsi);
//---- reset counters   
   OldTime = 0; OldBars = 0;
//----
   return(0);
   }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
   {
//----
   
//----
   return(0);
   }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
   {
   int counted_bars = IndicatorCounted();
   if (counted_bars < 0) return (-1);
   if (counted_bars > 0) counted_bars--;
   int limit = Bars - 1 - counted_bars;
//---- resize/shift extra buffers on first and every next bar
   if (Time[0] != OldTime) SyncExtraBuffers();
//---- prepare partial averages
   for (int i = limit; i >= 0; i--) wma0[i] = iMA(NULL, 0, 2, 0, MODE_LWMA, PRICE_CLOSE, i);
   for (i = limit; i >= 0; i--) wma1[i] = iMAOnArray(wma0, 0, 2, 0, MODE_LWMA, i);
   for (i = limit; i >= 0; i--) wma2[i] = iMAOnArray(wma1, 0, 2, 0, MODE_LWMA, i);
   for (i = limit; i >= 0; i--) wma3[i] = iMAOnArray(wma2, 0, 2, 0, MODE_LWMA, i);
   for (i = limit; i >= 0; i--) wma4[i] = iMAOnArray(wma3, 0, 2, 0, MODE_LWMA, i);
   for (i = limit; i >= 0; i--) wma5[i] = iMAOnArray(wma4, 0, 2, 0, MODE_LWMA, i);
   for (i = limit; i >= 0; i--) wma6[i] = iMAOnArray(wma5, 0, 2, 0, MODE_LWMA, i);
   for (i = limit; i >= 0; i--) wma7[i] = iMAOnArray(wma6, 0, 2, 0, MODE_LWMA, i);
   for (i = limit; i >= 0; i--) wma8[i] = iMAOnArray(wma7, 0, 2, 0, MODE_LWMA, i);
   for (i = limit; i >= 0; i--) wma9[i] = iMAOnArray(wma8, 0, 2, 0, MODE_LWMA, i);
//---- weigh the averages
   for (i = limit; i >= 0; i--)
      {
      double rb_val =  5 * wma0[i] + 4 * wma1[i] + 3 * wma2[i] + 2 * wma3[i] + wma4[i] + wma5[i] + wma6[i] + wma7[i] + wma8[i] + wma9[i];
      rb_val /= 20;
      rainbow[i] = rb_val;
      }
//---- calculate rsi from rainbow smoothed price curve 
   for (i = limit; i >= 0; i--) rsi[i] = 0.1 * (iRSIOnArray(rainbow, 0, RsiPeriod, i) - 50);
//---- smooth the rsi with Vervoort zero lag MA
   for (i = limit; i >= 0; i--) ema0[i] = iMAOnArray(rsi, 0, EmaPeriod, 0, MODE_EMA, i);
   for (i = limit; i >= 0; i--) ema1[i] = iMAOnArray(ema0, 0, EmaPeriod, 0, MODE_EMA, i);
   for (i = limit; i >= 0; i--) srsi[i] = ema0[i] + (ema0[i] - ema1[i]);
//---- do the fish
   for (i = limit; i >= 0; i--) fish[i] = ((MathExp(2 * srsi[i]) - 1) / (MathExp(2 * srsi[i]) + 1) + 1) * 50;
//----
   return(0);
   }
//+------------------------------------------------------------------+
//| Shift array elements without having to do it one-by-one          |
//+------------------------------------------------------------------+
void SyncExtraBuffers()
   {
   if (OldBars == Bars)
//---- if Bars = MaxBarsOnChart, arrays wouldn't resize & shift below
//---- we have to shrink them a bit, one bar does.
      {
      ArrayResize(wma0, Bars - 1);
      ArrayResize(wma1, Bars - 1);
      ArrayResize(wma2, Bars - 1);
      ArrayResize(wma3, Bars - 1);
      ArrayResize(wma4, Bars - 1);
      ArrayResize(wma5, Bars - 1);
      ArrayResize(wma6, Bars - 1);
      ArrayResize(wma7, Bars - 1);
      ArrayResize(wma8, Bars - 1);
      ArrayResize(wma9, Bars - 1);
      }
//---- on first Start(), when Time[0] != 0, this will give an init size to arrays and
//---- set them as Series (because of iMAOnArray and iRSIOnArray). Hence nothing
//---- in init() as this place will be visited first in any case.
//---- The flip trick below is necessary on further resizing/shifting since ArrayResize()
//---- adds/removes elements on the LEFT SIDE if set as Series so arrays wouldn't shift
//---- and it would be necessary to do a for (n=Bars-1; n>=0; n--){wmaX[n+1]=wmaX[n];}
//---- ten times on every new bar. this is much quicker.
   ArraySetAsSeries(wma0, false); ArrayResize(wma0, Bars); ArraySetAsSeries(wma0, true);
   ArraySetAsSeries(wma1, false); ArrayResize(wma1, Bars); ArraySetAsSeries(wma1, true);
   ArraySetAsSeries(wma2, false); ArrayResize(wma2, Bars); ArraySetAsSeries(wma2, true);
   ArraySetAsSeries(wma3, false); ArrayResize(wma3, Bars); ArraySetAsSeries(wma3, true);
   ArraySetAsSeries(wma4, false); ArrayResize(wma4, Bars); ArraySetAsSeries(wma4, true);
   ArraySetAsSeries(wma5, false); ArrayResize(wma5, Bars); ArraySetAsSeries(wma5, true);
   ArraySetAsSeries(wma6, false); ArrayResize(wma6, Bars); ArraySetAsSeries(wma6, true);
   ArraySetAsSeries(wma7, false); ArrayResize(wma7, Bars); ArraySetAsSeries(wma7, true);
   ArraySetAsSeries(wma6, false); ArrayResize(wma6, Bars); ArraySetAsSeries(wma6, true);
   ArraySetAsSeries(wma8, false); ArrayResize(wma8, Bars); ArraySetAsSeries(wma8, true);
   ArraySetAsSeries(wma9, false); ArrayResize(wma9, Bars); ArraySetAsSeries(wma9, true);
//---- reset counters   
   OldTime = Time[0]; OldBars = Bars;
   }
//+------------------------------------------------------------------+