//------------------------------------------------------------------
#property copyright "www.forex-station.com"
#property link      "www.forex-station.com"
//------------------------------------------------------------------
#property indicator_separate_window
#property indicator_buffers 7

#property indicator_color1  C'0,204,0'
#property indicator_color2  C'214,0,0'
#property indicator_color3  clrGray
#property indicator_color4  clrBlue
#property indicator_color5  clrSienna
#property indicator_color6  clrRed
#property indicator_color7  clrOrange


#property indicator_width4  2
#property indicator_width5  2
#property indicator_width6  3
#property indicator_width7  2

#property indicator_style1  STYLE_DOT
#property indicator_style2  STYLE_DOT
#property indicator_style3  STYLE_DOT

#property strict

//
//
//
enum  enMaTypes
      {
         ma_sma,                                        // Simple moving average
         ma_ema,                                        // Exponential moving average
         ma_smma,                                       // Smoothed moving average
         ma_lwma,                                       // Linear weighted moving average
         ma_linr                                        // Least squares moving average
      };
//
//

extern ENUM_TIMEFRAMES   TimeFrame    = PERIOD_CURRENT;  // Time frame
extern string            note1        = ".........First RSI settings.........";
input int                RSIPeriod1   = 6;              // RSI period
input int                MAPeriod1    = 6;              // Signal period
input enMaTypes          MAType1      = ma_lwma;        // Signal type
input ENUM_APPLIED_PRICE MAPrice1     = PRICE_CLOSE;    // RSI price to use
extern bool              Showrsi1  = true;              // First RSI visible?
extern bool              Showsignal   = true;           // First Signal visible?
extern string            note2        = ".........Second RSI settings.........";
input int                RSIPeriod2   = 13;             // RSI period
input int                MAPeriod2    = 13;             // Signal period
input enMaTypes          MAType2      = ma_lwma;        // Signal type
input ENUM_APPLIED_PRICE MAPrice2     = PRICE_CLOSE;    // RSI price to use
extern bool              Showrsi2     = true;           // Second RSI visible?
extern bool              Showsigna2   = true;           // Second Signal visible?
extern string            note3        = ".........Levels settings.........";
extern double            OverSold     = 70;             // Oversold level
extern double            OverBought   = 30;             // Overbought level
extern bool              ShowLevels   = true;           // Levels are visible?
input bool               Interpolate  = true;           // Interpolate in multi time frame mode on/off?

double rsi1[],rsi2[],signal1[],signal2[],levelu[],leveld[],mid[],count[];
string indicatorFileName;
#define _mtfCall(_buff,_ind) iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,note1,RSIPeriod1,MAPeriod1,MAType1,MAPrice1,Showrsi1,Showsignal,note2,RSIPeriod2,MAPeriod2,MAType2,MAPrice2,Showrsi2,Showsigna2,note3,OverSold,OverBought,ShowLevels,_buff,_ind)

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

int OnInit()
{
   IndicatorBuffers(8);
   
   SetIndexBuffer(0,levelu);                  SetIndexStyle(0,ShowLevels  ? DRAW_LINE :  DRAW_NONE);
   SetIndexBuffer(1,leveld);                  SetIndexStyle(1,ShowLevels  ? DRAW_LINE :  DRAW_NONE);
   SetIndexBuffer(2,mid);                     SetIndexStyle(2,ShowLevels  ? DRAW_LINE :  DRAW_NONE);
   
   SetIndexBuffer(3,rsi1,    INDICATOR_DATA); SetIndexStyle(3,Showrsi1    ? DRAW_LINE :  DRAW_NONE);
   SetIndexBuffer(4,signal1, INDICATOR_DATA); SetIndexStyle(4,Showsignal  ? DRAW_LINE :  DRAW_NONE);
   SetIndexBuffer(5,rsi2,    INDICATOR_DATA); SetIndexStyle(5,Showrsi2    ? DRAW_LINE :  DRAW_NONE);
   SetIndexBuffer(6,signal2, INDICATOR_DATA); SetIndexStyle(6,Showsigna2  ? DRAW_LINE :  DRAW_NONE); 
   
   SetIndexBuffer(7,count);
   
   indicatorFileName = WindowExpertName();
   TimeFrame         = fmax(TimeFrame,_Period); 
   
   IndicatorSetString(INDICATOR_SHORTNAME,timeFrameToString(TimeFrame)+" RSI  ("+(string)RSIPeriod1+","+(string)RSIPeriod2+")");
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason){   }

//
//
//

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(7,0)*TimeFrame/_Period));
       
         for (i=limit;i>=0 && !_StopFlag; i--)
         {
            int y = iBarShift(NULL,TimeFrame,time[i]);
               levelu[i]  = _mtfCall(0,y);
               leveld[i]  = _mtfCall(1,y);
               mid[i]     = _mtfCall(2,y);
               rsi1[i]    = _mtfCall(3,y);
               signal1[i] = _mtfCall(4,y);
               rsi2[i]    = _mtfCall(5,y);
               signal2[i] = _mtfCall(6,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(rsi1); 
                     _interpolate(signal1);
                     _interpolate(rsi2); 
                     _interpolate(signal2); 
                  }                    
         } 
        
   return(rates_total);
   } 
      
   //
   //
   //
          
   
   for(i=limit;i>=0; i--)
   {  
      rsi1[i]    = iRsi(iMA(NULL,0,1,0,MODE_SMA,MAPrice1,i),   RSIPeriod1,i,0);  
      signal1[i] = iCustomMa(MAType1,rsi1[i],MAPeriod1,i,rates_total,0);  
            
      rsi2[i]    = iRsi(iMA(NULL,0,1,0,MODE_SMA,MAPrice2,i),   RSIPeriod2,i,1);   
      signal2[i] = iCustomMa(MAType2,rsi2[i],MAPeriod2,i,rates_total,1);  
      
       levelu[i] = OverSold;
       leveld[i] = OverBought; 
       mid[i]    = 50;
      
   }
return(rates_total);
}

//------------------------------------------------------------------
//                                                                  
//------------------------------------------------------------------
//
//
//
//
//

string getAvgName(int method)
{
   switch(method)
   {
      case ma_ema:  return("EMA");
      case ma_linr: return("LSMA");
      case ma_lwma: return("LWMA");
      case ma_sma:  return("SMA");
      case ma_smma: return("SMMA");
   }
return("");      
}

//------------------------------------------------------------------
//                                                                  
//------------------------------------------------------------------
//
#define _rsiInstances 2
#define _rsiWorkBufferx3 3*_rsiInstances
//////////////////////////////
double workRsi[][_rsiWorkBufferx3];
#define _price  0
#define _change 1
#define _changa 2

double iRsi(double price, double period, int i, int instanceNo=0)
{
   if (ArrayRange(workRsi,0)!=Bars) ArrayResize(workRsi,Bars);
      int z = instanceNo*3; 
      int r = Bars-i-1;
   
   //
   //
   //
   //
   //
   
   workRsi[r][z+_price] = price;
         double alpha = 1.0/period; 
         if (r<period)
            {
               int k; double sum = 0; for (k=0; k<period && (r-k-1)>=0; k++) sum += MathAbs(workRsi[r-k][z+_price]-workRsi[r-k-1][z+_price]);
                  workRsi[r][z+_change] = (workRsi[r][z+_price]-workRsi[0][z+_price])/MathMax(k,1);
                  workRsi[r][z+_changa] =                                         sum/MathMax(k,1);
            }
         else
            {
               double change = workRsi[r][z+_price]-workRsi[r-1][z+_price];
                               workRsi[r][z+_change] = workRsi[r-1][z+_change] + alpha*(        change  - workRsi[r-1][z+_change]);
                               workRsi[r][z+_changa] = workRsi[r-1][z+_changa] + alpha*(MathAbs(change) - workRsi[r-1][z+_changa]);
            }
         if (workRsi[r][z+_changa] != 0)
               return(50.0*(workRsi[r][z+_change]/workRsi[r][z+_changa]+1));
         else  return(50.0);
   
}

////////////////////////
//
//
//

#define _maInstances 2
#define _maWorkBufferx1 1*_maInstances

double iCustomMa(int mode, double price, double length, int r, int bars, int instanceNo=0)
{
   r = bars-r-1;
   switch (mode)
   {
      case ma_sma   : return(iSma(price,(int)ceil(length),r,bars,instanceNo));
      case ma_ema   : return(iEma(price,length,r,bars,instanceNo));
      case ma_smma  : return(iSmma(price,(int)ceil(length),r,bars,instanceNo));
      case ma_lwma  : return(iLwma(price,(int)ceil(length),r,bars,instanceNo));
      case ma_linr  : return(iLinr(price,(int)ceil(length),r,bars,instanceNo));
      default       : return(price);
   }
}

//
//
//
//
//

double workSma[][_maWorkBufferx1];
double iSma(double price, int period, int r, int _bars, int instanceNo=0)
{
   if (ArrayRange(workSma,0)!= _bars) ArrayResize(workSma,_bars);

   workSma[r][instanceNo+0] = price;
   double avg = price; int k=1;  for(; k<period && (r-k)>=0; k++) avg += workSma[r-k][instanceNo+0];  
   return(avg/(double)k);
}

//
//
//
//
//

double workEma[][_maWorkBufferx1];
double iEma(double price, double period, int r, int _bars, int instanceNo=0)
{
   if (ArrayRange(workEma,0)!= _bars) ArrayResize(workEma,_bars);

   workEma[r][instanceNo] = price;
   if (r>0 && period>1)
          workEma[r][instanceNo] = workEma[r-1][instanceNo]+(2.0/(1.0+period))*(price-workEma[r-1][instanceNo]);
   return(workEma[r][instanceNo]);
}

//
//
//
//
//

double workSmma[][_maWorkBufferx1];
double iSmma(double price, double period, int r, int _bars, int instanceNo=0)
{
   if (ArrayRange(workSmma,0)!= _bars) ArrayResize(workSmma,_bars);

   workSmma[r][instanceNo] = price;
   if (r>1 && period>1)
          workSmma[r][instanceNo] = workSmma[r-1][instanceNo]+(price-workSmma[r-1][instanceNo])/period;
   return(workSmma[r][instanceNo]);
}

//
//
//
//
//

double workLwma[][_maWorkBufferx1];
double iLwma(double price, double period, int r, int _bars, int instanceNo=0)
{
   if (ArrayRange(workLwma,0)!= _bars) ArrayResize(workLwma,_bars);
   
   workLwma[r][instanceNo] = price; if (period<=1) return(price);
      double sumw = period;
      double sum  = period*price;

      for(int k=1; k<period && (r-k)>=0; k++)
      {
         double weight = period-k;
                sumw  += weight;
                sum   += weight*workLwma[r-k][instanceNo];  
      }             
      return(sum/sumw);
}

//
//
//
//
//

double workLinr[][_maWorkBufferx1];
double iLinr(double price, int period, int r, int bars, int instanceNo=0)
{
   if (ArrayRange(workLinr,0)!= bars) ArrayResize(workLinr,bars);

   //
   //
   //
   //
   //
   
      period = fmax(period,1);
      workLinr[r][instanceNo] = price;
      if (r<period) return(price);
         double lwmw = period; double lwma = lwmw*price;
         double sma  = price;
         for(int k=1; k<period && (r-k)>=0; k++)
         {
            double weight = period-k;
                   lwmw  += weight;
                   lwma  += weight*workLinr[r-k][instanceNo];  
                   sma   +=        workLinr[r-k][instanceNo];
         }             
   
   return(3.0*lwma/lwmw-2.0*sma/period);
}

//-------------------------------------------------------------------
//                                                                  
//-------------------------------------------------------------------
//
//
//
//
//-------------------------------------------------------------------
//
//-------------------------------------------------------------------
//
//
//
//
//

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("");
}
 

