//+------------------------------------------------------------------+
//|                                            Kiosotto SELL BUY.mq4 |
//|                                   Copyright 2014, Masakazu Corp. |
//|                                          http://www.masakazu.com |
//+------------------------------------------------------------------+
// NoRepaint, mod by Genry 18-dec-2018
// Kiosotto SELL BUY 2015 v4 Alert [mobidik]ms-nrp.mq4

#property indicator_separate_window
#property indicator_buffers 11
#property indicator_color1 clrDodgerBlue
#property indicator_color2 clrRed
#property indicator_width1 3
#property indicator_width2 3

#property indicator_color3     clrGold
#property indicator_width3     1
#property indicator_color4     clrWhite
#property indicator_style4     STYLE_DASH

#property indicator_color9  clrDodgerBlue
#property indicator_color10 clrRed
#property indicator_color9  clrRoyalBlue
#property indicator_color10 clrFireBrick

#property indicator_levelcolor clrSilver
#property indicator_levelstyle 2
#property indicator_minimum    0
#property strict

//
//
enum enRsiTypes
{
   rsi_rsi,  // Regular RSI
   rsi_wil,  // Slow RSI
   rsi_rap,  // Rapid RSI
   rsi_har,  // Harris RSI
   rsi_rsx,  // RSX
   rsi_cut   // Cuttlers RSI
};
enum enFilterOn
{
   cc_RSIcrossMA,      // Filter on RSI cross MA
   cc_RSIcrossMASlope, // Filter on RSI cross MA+slope
   cc_onSLOPE          // Filter on RSI slope
};
enum enPrices
{
   pr_close,      // Close
   pr_open,       // Open
   pr_high,       // High
   pr_low,        // Low
   pr_median,     // Median
   pr_typical,    // Typical
   pr_weighted,   // Weighted
   pr_average,    // Average (high+low+open+close)/4
   pr_medianb,    // Average median body (open+close)/2
   pr_tbiased,    // Trend biased price
   pr_tbiased2,   // Trend biased (extreme) price
   pr_haclose,    // Heiken ashi close
   pr_haopen ,    // Heiken ashi open
   pr_hahigh,     // Heiken ashi high
   pr_halow,      // Heiken ashi low
   pr_hamedian,   // Heiken ashi median
   pr_hatypical,  // Heiken ashi typical
   pr_haweighted, // Heiken ashi weighted
   pr_haaverage,  // Heiken ashi average
   pr_hamedianb,  // Heiken ashi median body
   pr_hatbiased,  // Heiken ashi trend biased price
   pr_hatbiased2, // Heiken ashi trend biased (extreme) price
   pr_habclose,   // Heiken ashi (better formula) close
   pr_habopen ,   // Heiken ashi (better formula) open
   pr_habhigh,    // Heiken ashi (better formula) high
   pr_hablow,     // Heiken ashi (better formula) low
   pr_habmedian,  // Heiken ashi (better formula) median
   pr_habtypical, // Heiken ashi (better formula) typical
   pr_habweighted,// Heiken ashi (better formula) weighted
   pr_habaverage, // Heiken ashi (better formula) average
   pr_habmedianb, // Heiken ashi (better formula) median body
   pr_habtbiased, // Heiken ashi (better formula) trend biased price
   pr_habtbiased2 // Heiken ashi (better formula) trend biased (extreme) price
};
enum maTypes
{
   ma_sma,     // simple moving average - SMA
   ma_ema,     // exponential moving average - EMA
   ma_dsema,   // double smoothed exponential moving average - DSEMA
   ma_dema,    // double exponential moving average - DEMA
   ma_tema,    // tripple exponential moving average - TEMA
   ma_smma,    // smoothed moving average - SMMA
   ma_lwma,    // linear weighted moving average - LWMA
   ma_pwma,    // parabolic weighted moving average - PWMA
   ma_alxma,   // Alexander moving average - ALXMA
   ma_vwma,    // volume weighted moving average - VWMA
   ma_hull,    // Hull moving average
   ma_tma,     // triangular moving average
   ma_sine,    // sine weighted moving average
   ma_linr,    // linear regression value
   ma_ie2,     // IE/2
   ma_nlma,    // non lag moving average
   ma_zlma,    // zero lag moving average
   ma_lead,    // leader exponential moving average
   ma_ssm,     // super smoother
   ma_smoo     // smoother
};
//
//

extern bool       UseCustomCalls = false;
string            Symbol_Calc    = "";
extern int        dev_period     = 11;
extern int        AlertsLevel    = 11;
extern int        NumBars        = 400;                // Number of Bars to display (0 = all bars)
extern int        SignalBar      = 1;
//+-----------------------------------------------------------------------------------------------------------+
extern enPrices   MacdPrice      = pr_close;           // Wae Macd Price to use, default: Close, pr_habtbiased
extern int        MacdFastMa     = 9;                  // Wae Macd Fast Ma, default: 20
extern int        MacdSlowMa     = 26;                 // Wae Macd Slow Ma, default: 40
extern maTypes    MacdMaMethod   = ma_smma;            // Wae Macd Ma Method, default: EMA
extern int        Sensitive      = 150;                // Wae Macd Sensitivity, default: 150
//+-----------------------------------------------------------------------------------------------------------+
extern int        BandsLength    = 9;                  // StdDev Bands Length, default: 21, 20
extern maTypes    BandsMaMethod  = ma_ema;             // StdDev Bands Ma Method, default: EMA
extern enPrices   BandsPrice     = pr_close;           // StdDev Bands Price, default: Close, pr_habtbiased
extern double     BandsDeviation = 2.0;                // StdDev Bands Deviation, default: 2.0, 4.0, 3.0, 3.45
//+-----------------------------------------------------------------------------------------------------------+
input int         AtrPeriod      = 14;                 // ATR Period, default: 100
input double      AtrMultiplier  = 4.0;                // ATR Multiplier, default: 3.75, 4.0
//+-----------------------------------------------------------------------------------------------------------+
extern enFilterOn FilterOn       = cc_RSIcrossMASlope; // RSI Filter on: ,default: RSI cross MA+slope
extern int        RsiPeriod      = 11;                 // RSI period, default: 14
extern enRsiTypes RsiMethod      = rsi_rsi;            // RSI method, default: Regular RSI
extern enPrices   RsiPrice       = pr_habclose;        // RSI Price to use, default: Close
extern int        AveragePeriod  = 2;                  // RSI Average signal period, default: 21
extern maTypes    AverageType    = ma_lwma;            // RSI Average signal and RSI-Ma Method, default: EMA
extern string     Note1          = "RSI < Up Level for Reversal Buy ArrowsOnEntry";
extern string     Note2          = "RSI > Down Level for Reversal Sell ArrowsOnEntry";
input double      LevelUp        = 60;                 // RSI Up Level
input double      LevelDown      = 40;                 // RSI Down Level
//+-----------------------------------------------------------------------------------------------------------+
extern bool       UseAutoWidth   = true;               // Auto adjust histogram width?
extern int        HistogramWidth = 3;                  // Histogram width (if auto width = false)
//+-----------------------------------------------------------------------------------------------------------+
extern bool       AlertsMessage  = false;
extern bool       AlertsSound    = false;
extern bool       AlertsEmail    = false;
extern bool       AlertsMobile   = false;
//+-----------------------------------------------------------------------------------------------------------+
extern bool       ArrowsVisible  = true;
extern bool       ArrowsOnEntry  = true;               // ArrowsOnEntry ? (false = ArrowsOnAlertsLevel)
extern int        ArrowsGap      = 10;
extern int        ArrowsSize     = 1;
input int         ArrowsUpCode   = 221;                // Arrows Up Code
input int         ArrowsDnCode   = 222;                // Arrows Dn Code
extern color      ArrowsUpColor  = clrGreen;
extern color      ArrowsDnColor  = clrFireBrick;
//+-----------------------------------------------------------------------------------------------------------+

datetime TimeBar;
double KioUp[];
double KioDn[];
double Ma[],dz[],bias[],rev[],rsi[],rsiAvg[],rsitrend[];
double WaeUp[],WaeDn[],macd[];
double avg[];
double avgUp[];
double avgDn[];
double prices[];
double trend[];

#define PREFIX "kIo-"
double PairPip;
int maxPeriod;
int PreviousChartScale = WRONG_VALUE;

int init()
{
   IndicatorBuffers(17);

   if(UseCustomCalls) ArrowsVisible=false;

   if(UseAutoWidth && !UseCustomCalls) SetAutoWidth();
   else
   {
      SetIndexStyle(0,DRAW_HISTOGRAM,STYLE_SOLID,HistogramWidth);
      SetIndexStyle(1,DRAW_HISTOGRAM,STYLE_SOLID,HistogramWidth);
   }

   SetIndexBuffer(0,KioUp);    SetIndexLabel(0,"KioUp");
   SetIndexBuffer(1,KioDn);    SetIndexLabel(1,"KioDn");
   SetIndexBuffer(2,Ma);       SetIndexStyle(2,DRAW_LINE); SetIndexLabel(2,"Ma");
   SetIndexBuffer(3,dz);       SetIndexStyle(3,DRAW_LINE); SetIndexLabel(3,"Dz");
   SetIndexBuffer(4,bias);     SetIndexStyle(4,DRAW_NONE); SetIndexLabel(4,"Bias");
   SetIndexBuffer(5,rev);      SetIndexStyle(5,DRAW_NONE); SetIndexLabel(5,"rev");
   SetIndexBuffer(6,rsi);      SetIndexStyle(6,DRAW_NONE); SetIndexLabel(6,"rsi");
   SetIndexBuffer(7,rsiAvg);   SetIndexStyle(7,DRAW_NONE); SetIndexLabel(7,"rsiAvg");
   SetIndexBuffer(8,rsitrend); SetIndexStyle(8,DRAW_NONE); SetIndexLabel(8,"rsitrend");
   SetIndexBuffer(9,WaeUp);    SetIndexStyle(9,DRAW_NONE,STYLE_DOT,1); SetIndexLabel(9,"WaeUp"); SetIndexEmptyValue(9, 0.0);
   SetIndexBuffer(10,WaeDn);   SetIndexStyle(10,DRAW_NONE,STYLE_DOT,1); SetIndexLabel(10,"WaeDn"); SetIndexEmptyValue(10, 0.0);
   SetIndexBuffer(11,macd);
   SetIndexBuffer(12,avg);
   SetIndexBuffer(13,avgUp);
   SetIndexBuffer(14,avgDn);
   SetIndexBuffer(15,prices);
   SetIndexBuffer(16,trend);

   SetLevelValue(0,AlertsLevel);
   if(Symbol_Calc == "") Symbol_Calc = Symbol();
   else  StringToUpper(Symbol_Calc);

   string name = WindowExpertName()+" "+Symbol_Calc+" Per="+(string)dev_period+" Lev="+(string)AlertsLevel;
   IndicatorShortName(name);

   if(MathMod(MarketInfo(Symbol(),MODE_DIGITS),2)==0)
   {
      PairPip = MarketInfo(Symbol(), MODE_POINT) * 10;
   }
   else
   {
      PairPip = MarketInfo(Symbol(), MODE_POINT) * 100;
   }

   maxPeriod=MathMax(MacdSlowMa,BandsLength);
   maxPeriod=MathMax(dev_period,maxPeriod);
   maxPeriod=MathMax(AtrPeriod,maxPeriod);
   // Comment("PairPip: ",1/PairPip);

   return(0);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   ObjectsDeleteAll(0,PREFIX,-1,-1);
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int start()
{
   {
      if(UseAutoWidth && !UseCustomCalls) SetAutoWidth();
      int counted_bars=IndicatorCounted();
      int i,j,limit;
      double hpres, lpres, TSBUL, TSBER, sbl, sbr;

      j=0;

      if(counted_bars < 0) return(-1);
      if(counted_bars > 0) counted_bars--;
      // limit = MathMin(Bars-counted_bars,Bars-1);
      limit = MathMin(Bars-counted_bars,Bars-maxPeriod);
      if(NumBars>0 && limit>NumBars) limit = NumBars;

      for(i = limit; i >= 0; i--)
      {
         // ATR Dead Zone and (StdDev x Band Deviation) explosion lines
         prices[i] = getPrice(BandsPrice,Open,Close,High,Low,i,Bars)/PairPip;
         avg[i]    = iCustomMa(BandsMaMethod,prices[i],BandsLength,i,2);
         double sDev = iDeviation(prices,BandsLength,avg[i],i);
         avgUp[i]  = avg[i] + BandsDeviation * sDev;
         avgDn[i]  = avg[i] - BandsDeviation * sDev;
         Ma[i]= (avgUp[i]-avgDn[i]);
         dz[i] = (iATR(NULL,0,AtrPeriod,i)*AtrMultiplier)/PairPip; //ATR Multiplier, default: 3.7

         // Waddah Attar Explosion (WAE) calculations
         macd[i]     = iCustomMa(MacdMaMethod,getPrice(MacdPrice,Open,Close,High,Low,i,Bars),MacdFastMa,i,0)-iCustomMa(MacdMaMethod,getPrice(MacdPrice,Open,Close,High,Low,i,Bars),MacdSlowMa,i,1);
         double diff = ((macd[i]-macd[i+1]) * Sensitive)/PairPip;

         WaeUp[i] =  WaeDn[i] = 0;
         if(diff>0) WaeUp[i] = diff;
         if(diff<0) WaeDn[i] = (-1*diff);

         // Rsi Calulations
         rsi[i] = iRsi(RsiMethod,iCustomMa(AverageType,getPrice(RsiPrice,Open,Close,High,Low,i,Bars),RsiPeriod,i,0),RsiPeriod,i);
         rsiAvg[i] = iCustomMa(AverageType,rsi[i],AveragePeriod,i,1);

         switch(FilterOn)
         {
            case cc_RSIcrossMA      :  rsitrend[i] = (i<Bars-1) ? (rsi[i] > rsiAvg[i]) ? 1 : (rsi[i] < rsiAvg[i]) ? -1 : rsitrend[i+1] : 0;  break;
            case cc_RSIcrossMASlope :  rsitrend[i] = (i<Bars-1) ? (rsi[i] > rsiAvg[i] && rsi[i] > rsi[i+1]) ? 1 : (rsi[i] < rsiAvg[i] && rsi[i] < rsi[i+1]) ? -1 : rsitrend[i+1] : 0;  break;
            default   : if(i<Bars-1) rsitrend[i] = (i<Bars-1) ? (rsi[i] > rsi[i+1]) ? 1 : (rsi[i] < rsi[i+1]) ? -1 : rsitrend[i+1] : 0;
         }

         //
         //
         //
         //
         //

         j = 0;
         TSBUL = 0;
         TSBER = 0;
         hpres =0;
         lpres = 9999999;
         while(j<dev_period)
         {
            sbl = 0;
            sbr = 0;
            {
               int shift=i+j;
               datetime date = iTime(Symbol_Calc, 0, shift);
               int bsht = iBarShift(Symbol_Calc, Period(), date, false);
               int kolichestvo = (int)(bsht-MathRound(Period()/Period()));
               if(kolichestvo < 0) {kolichestvo=0;}
               for(int n=bsht; n>kolichestvo; n--) //for (int n=bsht;n>=kolichestvo;n--)
               {
                  double ii = iRSI(Symbol_Calc,0,dev_period,PRICE_CLOSE,n);
                  double hnw = iHigh(Symbol_Calc, Period(), n);
                  double lnw = iLow(Symbol_Calc, Period(), n);
                  double cle = iClose(Symbol_Calc, Period(), n);


                  if(hnw> hpres)
                  {
                     hpres = hnw;
                     sbl = sbl + ii*cle;
                  }
                  if(lpres> lnw)
                  {
                     lpres = lnw;
                     sbr = sbr + ii*cle;
                  }
               }
            }
            TSBUL = TSBUL + sbl ;
            TSBER = TSBER + sbr ;

            j++;
         }

         if(TSBUL!=0) KioUp[i] = TSBER/TSBUL; else KioUp[i] = 0;
         if(TSBER!=0) KioDn[i] = TSBUL/TSBER; else KioDn[i] = 0;

         //
         //

         if(KioUp[i]>KioDn[i])
         {
            if(KioUp[i]>dz[i] && KioUp[i]>Ma[i] && KioUp[i]>KioUp[i+1] && KioUp[i] != EMPTY_VALUE) bias[i]=2;
            else if(KioUp[i]>dz[i] && KioUp[i]>Ma[i] && KioUp[i] != EMPTY_VALUE) bias[i]=1;
            else bias[i]=0;
         }
         else if(KioDn[i]>KioUp[i])
         {
            if(KioDn[i]>dz[i] && KioDn[i]>Ma[i] && KioDn[i]>KioDn[i+1] && KioDn[i] != EMPTY_VALUE) bias[i]=-2;
            else if(KioDn[i]>dz[i] && KioDn[i]>Ma[i] && KioDn[i] != EMPTY_VALUE) bias[i]=-1;
            else bias[i]=0;
         }
         else bias[i]=0;

         if(bias[i]>1 && KioUp[i]>AlertsLevel) trend[i-1] =-1;
         if(bias[i]<-1 && KioDn[i]>AlertsLevel) trend[i-1] = 1;

         rev[i] = 0;
         if(trend[i]==1) rev[i] = 1;
         else if(trend[i]==-1) rev[i] = -1;
         else if((rev[i+1]==1 || rev[i+1]==2) && rsi[i]<LevelUp && rsitrend[i]>0 && WaeUp[i]>Ma[i] && WaeUp[i]>dz[i] &&
                 (WaeUp[i]>WaeUp[i+1] || WaeDn[i+1] != EMPTY_VALUE) && Ma[i]>=Ma[i+1] && WaeUp[i] != EMPTY_VALUE) rev[i] = 2;
         else if((rev[i+1]==1 || rev[i+1]==2) && rsi[i]<LevelUp) rev[i] = 1;
         else if((rev[i+1]==-1 || rev[i+1]==-2) && rsi[i]>LevelDown && rsitrend[i]<0 && WaeDn[i]>Ma[i] && WaeDn[i]>dz[i] &&
                 (WaeDn[i]>WaeDn[i+1] || WaeUp[i+1] != EMPTY_VALUE) && Ma[i]>=Ma[i+1] && WaeDn[i] != EMPTY_VALUE) rev[i] = -2;
         else if((rev[i+1]==-1 || rev[i+1]==-2) && rsi[i]>LevelDown) rev[i] = -1;
         else rev[i] = 0;

         //
         //

         if(ArrowsVisible)
         {
            if(ArrowsOnEntry)
            {
               if(rev[i]>1 && rev[i+1]<2)
                  arrows_wind(i,"Up",ArrowsGap,ArrowsUpCode,ArrowsUpColor,ArrowsSize,false);
               else
                  ObjectDelete(PREFIX+"Up"+TimeToStr(Time[i],TIME_DATE|TIME_SECONDS));

               if(rev[i]<-1 && rev[i+1]>-2)
                  arrows_wind(i,"Dn",ArrowsGap,ArrowsDnCode,ArrowsDnColor,ArrowsSize,true);
               else
                  ObjectDelete(PREFIX + "Dn" + TimeToStr(Time[i],TIME_DATE|TIME_SECONDS));
            }
            else
            {
               if(KioDn[i]>AlertsLevel && KioDn[i+1]<AlertsLevel)
                  arrows_wind(i,"Up",ArrowsGap,ArrowsUpCode,ArrowsUpColor,ArrowsSize,false);
               else
                  ObjectDelete(PREFIX+"Up"+TimeToStr(Time[i],TIME_DATE|TIME_SECONDS));

               if(KioUp[i]>AlertsLevel && KioUp[i+1]<AlertsLevel)
                  arrows_wind(i,"Dn",ArrowsGap,ArrowsDnCode,ArrowsDnColor,ArrowsSize,true);
               else
                  ObjectDelete(PREFIX + "Dn" + TimeToStr(Time[i],TIME_DATE|TIME_SECONDS));
            }

         }
      }
   }

   if(AlertsMessage || AlertsSound || AlertsEmail || AlertsMobile)
   {
      string message1 = (WindowExpertName()+" - "+Symbol_Calc+"  "+PeriodString()+" - Signal Up");
      string message2 = (WindowExpertName()+" - "+Symbol_Calc+"  "+PeriodString()+" - Signal Dn");

      if(TimeBar!=Time[0] && KioDn[SignalBar]>AlertsLevel)
      {
         if(AlertsMessage) Alert(message1);
         if(AlertsSound)   PlaySound("alert2.wav");
         if(AlertsEmail)   SendMail(Symbol_Calc+" - "+WindowExpertName()+" - ",message1);
         if(AlertsMobile)  SendNotification(message1);
         TimeBar=Time[0];
      }
      if(TimeBar!=Time[0] && KioUp[SignalBar]>AlertsLevel)
      {
         if(AlertsMessage) Alert(message2);
         if(AlertsSound)   PlaySound("alert2.wav");
         if(AlertsEmail)   SendMail(Symbol_Calc+" - "+WindowExpertName()+" - ",message2);
         if(AlertsMobile)  SendNotification(message2);
         TimeBar=Time[0];
      }
   }
   return(0);
}

//+-------------------------------------------------------------------
//|
//+-------------------------------------------------------------------
//
//
//
//
//

double iDeviation(double& array[], double period, double ma, int i)
{
   double sum = 0.00;
   for(int k=0; k<period; k++) sum += (array[i+k]-ma)*(array[i+k]-ma);
   return(MathSqrt(sum/period));
}

//
//
//
//
//

//+------------------------------------------------------------------+
//| Period String                                                    |
//+------------------------------------------------------------------+
string PeriodString()
{
   switch(_Period)
   {
      case PERIOD_M1:  return("M1");
      case PERIOD_M5:  return("M5");
      case PERIOD_M15: return("M15");
      case PERIOD_M30: return("M30");
      case PERIOD_H1:  return("H1");
      case PERIOD_H4:  return("H4");
      case PERIOD_D1:  return("D1");
      case PERIOD_W1:  return("W1");
      case PERIOD_MN1: return("MN1");
   }
   return("M" + string(_Period));
}
//+------------------------------------------------------------------+
//| arrows wind                                                      |
//+------------------------------------------------------------------+
void arrows_wind(int k, string N,int ots,int code,color clr, int size,bool up)
{
   string name = PREFIX+N+TimeToStr(Time[k]);
   double gap = ots*Point;

   ObjectCreate(name,OBJ_ARROW,0,Time[k],0);
   ObjectSetInteger(0,name,OBJPROP_COLOR, clr);
   ObjectSetInteger(0,name,OBJPROP_ARROWCODE,code);
   ObjectSetInteger(0,name,OBJPROP_WIDTH,size);
   ObjectSetInteger(0,name,OBJPROP_SELECTABLE,0);
   if(up)
   {
      ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_BOTTOM);
      ObjectSetDouble(0,name,OBJPROP_PRICE1,High[k]+gap);
   }
   else
   {
      ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_TOP);
      ObjectSetDouble(0,name,OBJPROP_PRICE1,Low[k]-gap);
   }
}

//------------------------------------------------------------------
// MA Types (fixed for property strict)
//------------------------------------------------------------------
//
//
//
//
//

string methodNames[] = {"SMA","EMA","Double smoothed EMA","Double EMA","Triple EMA","Smoothed MA","Linear weighted MA","Parabolic weighted MA","Alexander MA","Volume weghted MA","Hull MA","Triangular MA","Sine weighted MA","Linear regression","IE/2","NonLag MA","Zero lag EMA","Leader EMA","Super smoother","Smoother"};
string getAverageName(int method)
{
   int max = ArraySize(methodNames)-1;
   method=MathMax(MathMin(method,max),0); return(methodNames[method]);
}

//
//
//
//
//

#define _maWorkBufferx1 3
#define _maWorkBufferx2 6
#define _maWorkBufferx3 9
#define _maWorkBufferx5 15

double iCustomMa(int mode, double price, double length, int i, int instanceNo=0)
{
   int r = Bars-i-1;
   switch(mode)
   {
      case 0  : return(iSma(price,(int)length,r,instanceNo));
      case 1  : return(iEma(price,length,r,instanceNo));
      case 2  : return(iDsema(price,length,r,instanceNo));
      case 3  : return(iDema(price,length,r,instanceNo));
      case 4  : return(iTema(price,length,r,instanceNo));
      case 5  : return(iSmma(price,length,r,instanceNo));
      case 6  : return(iLwma(price,length,r,instanceNo));
      case 7  : return(iLwmp(price,length,r,instanceNo));
      case 8  : return(iAlex(price,length,r,instanceNo));
      case 9  : return(iWwma(price,length,r,instanceNo));
      case 10 : return(iHull(price,length,r,instanceNo));
      case 11 : return(iTma(price,length,r,instanceNo));
      case 12 : return(iSineWMA(price,(int)length,r,instanceNo));
      case 13 : return(iLinr(price,length,r,instanceNo));
      case 14 : return(iIe2(price,length,r,instanceNo));
      case 15 : return(iNonLagMa(price,length,r,instanceNo));
      case 16 : return(iZeroLag(price,length,r,instanceNo));
      case 17 : return(iLeader(price,length,r,instanceNo));
      case 18 : return(iSsm(price,length,r,instanceNo));
      case 19 : return(iSmooth(price,(int)length,r,instanceNo));
      default : return(0);
   }
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

double workSma[][_maWorkBufferx2];
double iSma(double price, int period, int r, int instanceNo=0)
{
   int k;
   if(ArrayRange(workSma,0)!= Bars) ArrayResize(workSma,Bars); instanceNo *= 2;

   //
   //
   //
   //
   //

   workSma[r][instanceNo] = price;
   if(r>=period)
      workSma[r][instanceNo+1] = workSma[r-1][instanceNo+1]+(workSma[r][instanceNo]-workSma[r-period][instanceNo])/period;
   else
   {
      workSma[r][instanceNo+1] = 0; for(k=0; k<period && (r-k)>=0; k++) workSma[r][instanceNo+1] += workSma[r-k][instanceNo];
      workSma[r][instanceNo+1] /= k;
   }
   return(workSma[r][instanceNo+1]);
}

//
//
//
//
//

double workEma[][_maWorkBufferx1];
double iEma(double price, double period, int r, int instanceNo=0)
{
   if(ArrayRange(workEma,0)!= Bars) ArrayResize(workEma,Bars);

   //
   //
   //
   //
   //

   double alpha = 2.0 / (1.0+period);
   workEma[r][instanceNo] = workEma[r-1][instanceNo]+alpha*(price-workEma[r-1][instanceNo]);
   return(workEma[r][instanceNo]);
}

//
//
//
//
//

double workDsema[][_maWorkBufferx2];
#define _ema1 0
#define _ema2 1

double iDsema(double price, double period, int r, int instanceNo=0)
{
   if(ArrayRange(workDsema,0)!= Bars) ArrayResize(workDsema,Bars); instanceNo*=2;

   //
   //
   //
   //
   //

   double alpha = 2.0 /(1.0+MathSqrt(period));
   workDsema[r][_ema1+instanceNo] = workDsema[r-1][_ema1+instanceNo]+alpha*(price                         -workDsema[r-1][_ema1+instanceNo]);
   workDsema[r][_ema2+instanceNo] = workDsema[r-1][_ema2+instanceNo]+alpha*(workDsema[r][_ema1+instanceNo]-workDsema[r-1][_ema2+instanceNo]);
   return(workDsema[r][_ema2+instanceNo]);
}

//
//
//
//
//

double workDema[][_maWorkBufferx2];
#define _dema1 0
#define _dema2 1

double iDema(double price, double period, int r, int instanceNo=0)
{
   if(ArrayRange(workDema,0)!= Bars) ArrayResize(workDema,Bars); instanceNo*=2;

   //
   //
   //
   //
   //

   double alpha = 2.0 / (1.0+period);
   workDema[r][_dema1+instanceNo] = workDema[r-1][_dema1+instanceNo]+alpha*(price                         -workDema[r-1][_dema1+instanceNo]);
   workDema[r][_dema2+instanceNo] = workDema[r-1][_dema2+instanceNo]+alpha*(workDema[r][_dema1+instanceNo]-workDema[r-1][_dema2+instanceNo]);
   return(workDema[r][_dema1+instanceNo]*2.0-workDema[r][_dema2+instanceNo]);
}

//
//
//
//
//

double workTema[][_maWorkBufferx3];
#define _tema1 0
#define _tema2 1
#define _tema3 2

double iTema(double price, double period, int r, int instanceNo=0)
{
   if(ArrayRange(workTema,0)!= Bars) ArrayResize(workTema,Bars); instanceNo*=3;

   //
   //
   //
   //
   //

   double alpha = 2.0 / (1.0+period);
   workTema[r][_tema1+instanceNo] = workTema[r-1][_tema1+instanceNo]+alpha*(price                         -workTema[r-1][_tema1+instanceNo]);
   workTema[r][_tema2+instanceNo] = workTema[r-1][_tema2+instanceNo]+alpha*(workTema[r][_tema1+instanceNo]-workTema[r-1][_tema2+instanceNo]);
   workTema[r][_tema3+instanceNo] = workTema[r-1][_tema3+instanceNo]+alpha*(workTema[r][_tema2+instanceNo]-workTema[r-1][_tema3+instanceNo]);
   return(workTema[r][_tema3+instanceNo]+3.0*(workTema[r][_tema1+instanceNo]-workTema[r][_tema2+instanceNo]));
}

//
//
//
//
//

double workSmma[][_maWorkBufferx1];
double iSmma(double price, double period, int r, int instanceNo=0)
{
   if(ArrayRange(workSmma,0)!= Bars) ArrayResize(workSmma,Bars);

   //
   //
   //
   //
   //

   if(r<period)
      workSmma[r][instanceNo] = price;
   else  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 instanceNo=0)
{
   if(ArrayRange(workLwma,0)!= Bars) ArrayResize(workLwma,Bars);

   //
   //
   //
   //
   //

   workLwma[r][instanceNo] = 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 workLwmp[][_maWorkBufferx1];
double iLwmp(double price, double period, int r, int instanceNo=0)
{
   if(ArrayRange(workLwmp,0)!= Bars) ArrayResize(workLwmp,Bars);

   //
   //
   //
   //
   //

   workLwmp[r][instanceNo] = price;
   double sumw = period*period;
   double sum  = sumw*price;

   for(int k=1; k<period && (r-k)>=0; k++)
   {
      double weight = (period-k)*(period-k);
      sumw  += weight;
      sum   += weight*workLwmp[r-k][instanceNo];
   }
   return(sum/sumw);
}

//
//
//
//
//

double workAlex[][_maWorkBufferx1];
double iAlex(double price, double period, int r, int instanceNo=0)
{
   if(ArrayRange(workAlex,0)!= Bars) ArrayResize(workAlex,Bars);
   if(period<4) return(price);

   //
   //
   //
   //
   //

   workAlex[r][instanceNo] = price;
   double sumw = period-2;
   double sum  = sumw*price;

   for(int k=1; k<period && (r-k)>=0; k++)
   {
      double weight = period-k-2;
      sumw  += weight;
      sum   += weight*workAlex[r-k][instanceNo];
   }
   return(sum/sumw);
}

//
//
//
//
//

double workTma[][_maWorkBufferx1];
double iTma(double price, double period, int r, int instanceNo=0)
{
   if(ArrayRange(workTma,0)!= Bars) ArrayResize(workTma,Bars);

   //
   //
   //
   //
   //

   workTma[r][instanceNo] = price;

   double half = (period+1.0)/2.0;
   double sum  = price;
   double sumw = 1;

   for(int k=1; k<period && (r-k)>=0; k++)
   {
      double weight = k+1; if(weight > half) weight = period-k;
      sumw  += weight;
      sum   += weight*workTma[r-k][instanceNo];
   }
   return(sum/sumw);
}

//
//
//
//
//

double workSineWMA[][_maWorkBufferx1];
#define Pi 3.14159265358979323846264338327950288

double iSineWMA(double price, int period, int r, int instanceNo=0)
{
   if(period<1) return(price);
   if(ArrayRange(workSineWMA,0)!= Bars) ArrayResize(workSineWMA,Bars);

   //
   //
   //
   //
   //

   workSineWMA[r][instanceNo] = price;
   double sum  = 0;
   double sumw = 0;

   for(int k=0; k<period && (r-k)>=0; k++)
   {
      double weight = MathSin(Pi*(k+1.0)/(period+1.0));
      sumw  += weight;
      sum   += weight*workSineWMA[r-k][instanceNo];
   }
   return(sum/sumw);
}

//
//
//
//
//

double workWwma[][_maWorkBufferx1];
double iWwma(double price, double period, int r, int instanceNo=0)
{
   if(ArrayRange(workWwma,0)!= Bars) ArrayResize(workWwma,Bars);

   //
   //
   //
   //
   //

   workWwma[r][instanceNo] = price;
   int    i    = Bars-r-1;
   double sumw = (double)Volume[i];
   double sum  = sumw*price;

   for(int k=1; k<period && (r-k)>=0; k++)
   {
      double weight = (double)Volume[i+k];
      sumw  += weight;
      sum   += weight*workWwma[r-k][instanceNo];
   }
   return(sum/sumw);
}

//
//
//
//
//

double workHull[][_maWorkBufferx2];
double iHull(double price, double period, int r, int instanceNo=0)
{
   if(ArrayRange(workHull,0)!= Bars) ArrayResize(workHull,Bars);

   //
   //
   //
   //
   //

   int HmaPeriod  = (int)MathMax(period,2);
   int HalfPeriod = (int)MathFloor(HmaPeriod/2);
   int HullPeriod = (int)MathFloor(MathSqrt(HmaPeriod));
   double hma,hmw,weight; instanceNo *= 2;

   workHull[r][instanceNo] = price;

   //
   //
   //
   //
   //

   hmw = HalfPeriod; hma = hmw*price;
   for(int k=1; k<HalfPeriod && (r-k)>=0; k++)
   {
      weight = HalfPeriod-k;
      hmw   += weight;
      hma   += weight*workHull[r-k][instanceNo];
   }
   workHull[r][instanceNo+1] = 2.0*hma/hmw;

   hmw = HmaPeriod; hma = hmw*price;
   for(int k=1; k<period && (r-k)>=0; k++)
   {
      weight = HmaPeriod-k;
      hmw   += weight;
      hma   += weight*workHull[r-k][instanceNo];
   }
   workHull[r][instanceNo+1] -= hma/hmw;

   //
   //
   //
   //
   //

   hmw = HullPeriod; hma = hmw*workHull[r][instanceNo+1];
   for(int k=1; k<HullPeriod && (r-k)>=0; k++)
   {
      weight = HullPeriod-k;
      hmw   += weight;
      hma   += weight*workHull[r-k][1+instanceNo];
   }
   return(hma/hmw);
}

//
//
//
//
//

double workLinr[][_maWorkBufferx1];
double iLinr(double price, double period, int r, int instanceNo=0)
{
   if(ArrayRange(workLinr,0)!= Bars) ArrayResize(workLinr,Bars);

   //
   //
   //
   //
   //

   period = MathMax(period,1);
   workLinr[r][instanceNo] = 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);
}

//
//
//
//
//

double workIe2[][_maWorkBufferx1];
double iIe2(double price, double period, int r, int instanceNo=0)
{
   if(ArrayRange(workIe2,0)!= Bars) ArrayResize(workIe2,Bars);

   //
   //
   //
   //
   //

   period = MathMax(period,1);
   workIe2[r][instanceNo] = price;
   double sumx=0, sumxx=0, sumxy=0, sumy=0;
   for(int k=0; k<period; k++)
   {
      price = workIe2[r-k][instanceNo];
      sumx  += k;
      sumxx += k*k;
      sumxy += k*price;
      sumy  +=   price;
   }
   double tslope  = (period*sumxy - sumx*sumy)/(sumx*sumx-period*sumxx);
   double average = sumy/period;
   return(((average+tslope)+(sumy+tslope*sumx)/period)/2.0);
}

//
//
//
//
//

double workLeader[][_maWorkBufferx2];
double iLeader(double price, double period, int r, int instanceNo=0)
{
   if(ArrayRange(workLeader,0)!= Bars) ArrayResize(workLeader,Bars); instanceNo*=2;

   //
   //
   //
   //
   //

   period = MathMax(period,1);
   double alpha = 2.0/(period+1.0);
   workLeader[r][instanceNo  ] = workLeader[r-1][instanceNo  ]+alpha*(price                          -workLeader[r-1][instanceNo  ]);
   workLeader[r][instanceNo+1] = workLeader[r-1][instanceNo+1]+alpha*(price-workLeader[r][instanceNo]-workLeader[r-1][instanceNo+1]);

   return(workLeader[r][instanceNo]+workLeader[r][instanceNo+1]);
}

//
//
//
//
//

double workZl[][_maWorkBufferx2];
#define _price 0
#define _zlema 1

double iZeroLag(double price, double length, int r, int instanceNo=0)
{
   if(ArrayRange(workZl,0)!=Bars) ArrayResize(workZl,Bars); instanceNo *= 2; workZl[r][_price+instanceNo] = price;

   //
   //
   //
   //
   //

   double median = 0;
   double alpha  = 2.0/(1.0+length);
   int    per    = (int)((length-1.0)/2.0);
   if(r<per)
      workZl[r][_zlema+instanceNo] = price;
   else
   {
      if((int)length%2==0)
         median = (workZl[r-per][_price+instanceNo]+workZl[r-per-1][_price+instanceNo])/2.0;
      else  median =  workZl[r-per][_price+instanceNo];
      workZl[r][_zlema+instanceNo] = workZl[r-1][_zlema+instanceNo]+alpha*(2.0*price-median-workZl[r-1][_zlema+instanceNo]);
   }
   return(workZl[r][_zlema+instanceNo]);
}

//
//
//
//
//

double workSmooth[][_maWorkBufferx5];
double iSmooth(double price,int length,int r, int instanceNo=0)
{
   if(ArrayRange(workSmooth,0)!=Bars) ArrayResize(workSmooth,Bars); instanceNo *= 5;
   if(r<=2) { workSmooth[r][instanceNo] = price; workSmooth[r][instanceNo+2] = price; workSmooth[r][instanceNo+4] = price; return(price); }

   //
   //
   //
   //
   //

   double alpha = 0.45*(length-1.0)/(0.45*(length-1.0)+2.0);
   workSmooth[r][instanceNo+0] =  price+alpha*(workSmooth[r-1][instanceNo]-price);
   workSmooth[r][instanceNo+1] = (price - workSmooth[r][instanceNo])*(1-alpha)+alpha*workSmooth[r-1][instanceNo+1];
   workSmooth[r][instanceNo+2] =  workSmooth[r][instanceNo+0] + workSmooth[r][instanceNo+1];
   workSmooth[r][instanceNo+3] = (workSmooth[r][instanceNo+2] - workSmooth[r-1][instanceNo+4])*MathPow(1.0-alpha,2) + MathPow(alpha,2)*workSmooth[r-1][instanceNo+3];
   workSmooth[r][instanceNo+4] =  workSmooth[r][instanceNo+3] + workSmooth[r-1][instanceNo+4];
   return(workSmooth[r][instanceNo+4]);
}

//
//
//
//
//

double workSsm[][_maWorkBufferx2];
#define _tprice  0
#define _ssm    1

double workSsmCoeffs[][4];
#define _period 0
#define _c1     1
#define _c2     2
#define _c3     3

//
//
//
//
//

double iSsm(double price, double period, int i, int instanceNo)
{
   if(ArrayRange(workSsm,0) !=Bars)                 ArrayResize(workSsm,Bars);
   if(ArrayRange(workSsmCoeffs,0) < (instanceNo+1)) ArrayResize(workSsmCoeffs,instanceNo+1);
   if(workSsmCoeffs[instanceNo][_period] != period)
   {
      workSsmCoeffs[instanceNo][_period] = period;
      double a1 = MathExp(-1.414*Pi/period);
      double b1 = 2.0*a1*MathCos(1.414*Pi/period);
      workSsmCoeffs[instanceNo][_c2] = b1;
      workSsmCoeffs[instanceNo][_c3] = -a1*a1;
      workSsmCoeffs[instanceNo][_c1] = 1.0 - workSsmCoeffs[instanceNo][_c2] - workSsmCoeffs[instanceNo][_c3];
   }

   //
   //
   //
   //
   //

   int s = instanceNo*2;
   workSsm[i][s+_tprice] = price;
   workSsm[i][s+_ssm]    = workSsmCoeffs[instanceNo][_c1]*(workSsm[i][s+_tprice]+workSsm[i-1][s+_price])/2.0 +
                           workSsmCoeffs[instanceNo][_c2]*workSsm[i-1][s+_ssm]                               +
                           workSsmCoeffs[instanceNo][_c3]*workSsm[i-2][s+_ssm];
   return(workSsm[i][s+_ssm]);
}

//
//
//
//
//

#define _length  0
#define _len     1
#define _weight  2

double  nlmvalues[3][_maWorkBufferx1];
double  nlmprices[ ][_maWorkBufferx1];
double  nlmalphas[ ][_maWorkBufferx1];

//
//
//
//
//

double iNonLagMa(double price, double length, int r, int instanceNo=0)
{
   if(ArrayRange(nlmprices,0) != Bars)       ArrayResize(nlmprices,Bars);
   if(ArrayRange(nlmvalues,0) <  instanceNo) ArrayResize(nlmvalues,instanceNo);
   nlmprices[r][instanceNo]=price;
   if(length<3 || r<3) return(nlmprices[r][instanceNo]);

   //
   //
   //
   //
   //

   if(nlmvalues[_length][instanceNo] != length  || ArraySize(nlmalphas)==0)
   {
      double Cycle = 4.0;
      double Coeff = 3.0*Pi;
      int    Phase = (int)length-1;
      double t;

      nlmvalues[_length][instanceNo] = length;
      nlmvalues[_len   ][instanceNo] = length*4 + Phase;
      nlmvalues[_weight][instanceNo] = 0;

      if(ArrayRange(nlmalphas,0) < nlmvalues[_len][instanceNo]) ArrayResize(nlmalphas,(int)nlmvalues[_len][instanceNo]);
      for(int k=0; k<nlmvalues[_len][instanceNo]; k++)
      {
         if(k<=Phase-1)
            t = 1.0 * k/(Phase-1);
         else        t = 1.0 + (k-Phase+1)*(2.0*Cycle-1.0)/(Cycle*length-1.0);
         double beta = MathCos(Pi*t);
         double g = 1.0/(Coeff*t+1); if(t <= 0.5) g = 1;

         nlmalphas[k][instanceNo]        = g * beta;
         nlmvalues[_weight][instanceNo] += nlmalphas[k][instanceNo];
      }
   }

   //
   //
   //
   //
   //

   if(nlmvalues[_weight][instanceNo]>0)
   {
      double sum = 0;
      for(int k=0; k < nlmvalues[_len][instanceNo]; k++) sum += nlmalphas[k][instanceNo]*nlmprices[r-k][instanceNo];
      return(sum / nlmvalues[_weight][instanceNo]);
   }
   else return(0);
}

//------------------------------------------------------------------
// Prices                                                          |
//------------------------------------------------------------------
//
//
//
//
//

#define _prHABF(_prtype) (_prtype>=pr_habclose && _prtype<=pr_habtbiased2)
#define _priceInstances     1
#define _priceInstancesSize 4
double workHa[][_priceInstances*_priceInstancesSize];
double getPrice(int tprice, const double& open[], const double& close[], const double& high[], const double& low[], int i, int bars, int instanceNo=0)
{
   if(tprice>=pr_haclose)
   {
      if(ArrayRange(workHa,0)!= Bars) ArrayResize(workHa,Bars); instanceNo*=_priceInstancesSize; int r = bars-i-1;

      //
      //
      //
      //
      //

      double haOpen  = (r>0) ? (workHa[r-1][instanceNo+2] + workHa[r-1][instanceNo+3])/2.0 : (open[i]+close[i])/2;;
      double haClose = (open[i]+high[i]+low[i]+close[i]) / 4.0;
      if(_prHABF(tprice))
         if(high[i]!=low[i])
            haClose = (open[i]+close[i])/2.0+(((close[i]-open[i])/(high[i]-low[i]))*MathAbs((close[i]-open[i])/2.0));
         else  haClose = (open[i]+close[i])/2.0;
      double haHigh  = fmax(high[i], fmax(haOpen,haClose));
      double haLow   = fmin(low[i] , fmin(haOpen,haClose));

      //
      //
      //
      //
      //

      if(haOpen<haClose) { workHa[r][instanceNo+0] = haLow;  workHa[r][instanceNo+1] = haHigh; }
      else               { workHa[r][instanceNo+0] = haHigh; workHa[r][instanceNo+1] = haLow;  }
      workHa[r][instanceNo+2] = haOpen;
      workHa[r][instanceNo+3] = haClose;
      //
      //
      //
      //
      //

      switch(tprice)
      {
         case pr_haclose:
         case pr_habclose:    return(haClose);
         case pr_haopen:
         case pr_habopen:     return(haOpen);
         case pr_hahigh:
         case pr_habhigh:     return(haHigh);
         case pr_halow:
         case pr_hablow:      return(haLow);
         case pr_hamedian:
         case pr_habmedian:   return((haHigh+haLow)/2.0);
         case pr_hamedianb:
         case pr_habmedianb:  return((haOpen+haClose)/2.0);
         case pr_hatypical:
         case pr_habtypical:  return((haHigh+haLow+haClose)/3.0);
         case pr_haweighted:
         case pr_habweighted: return((haHigh+haLow+haClose+haClose)/4.0);
         case pr_haaverage:
         case pr_habaverage:  return((haHigh+haLow+haClose+haOpen)/4.0);
         case pr_hatbiased:
         case pr_habtbiased:
            if(haClose>haOpen)
               return((haHigh+haClose)/2.0);
            else  return((haLow+haClose)/2.0);
         case pr_hatbiased2:
         case pr_habtbiased2:
            if(haClose>haOpen)  return(haHigh);
            if(haClose<haOpen)  return(haLow);
            return(haClose);
      }
   }

   //
   //
   //
   //
   //

   switch(tprice)
   {
      case pr_close:     return(close[i]);
      case pr_open:      return(open[i]);
      case pr_high:      return(high[i]);
      case pr_low:       return(low[i]);
      case pr_median:    return((high[i]+low[i])/2.0);
      case pr_medianb:   return((open[i]+close[i])/2.0);
      case pr_typical:   return((high[i]+low[i]+close[i])/3.0);
      case pr_weighted:  return((high[i]+low[i]+close[i]+close[i])/4.0);
      case pr_average:   return((high[i]+low[i]+close[i]+open[i])/4.0);
      case pr_tbiased:
         if(close[i]>open[i])
            return((high[i]+close[i])/2.0);
         else  return((low[i]+close[i])/2.0);
      case pr_tbiased2:
         if(close[i]>open[i]) return(high[i]);
         if(close[i]<open[i]) return(low[i]);
         return(close[i]);
   }
   return(0);
}
//+------------------------------------------------------------------+
//| Set AutoWidth                                                    |
//+------------------------------------------------------------------+
void SetAutoWidth()
{
   int ChartScale = int(ChartGetInteger(0, CHART_SCALE));
   if(PreviousChartScale == ChartScale) return;

   PreviousChartScale = ChartScale;

   int NewBarWidth = 0;
   switch(ChartScale)
   {
      case 0: NewBarWidth = 1;  break;
      case 1: NewBarWidth = 1;  break;
      case 2: NewBarWidth = 2;  break;
      case 3: NewBarWidth = 4;  break;
      case 4: NewBarWidth = 8;  break;
      case 5: NewBarWidth = 16; break;
   }
   SetIndexStyle(0,DRAW_HISTOGRAM,STYLE_SOLID,NewBarWidth);
   SetIndexStyle(1,DRAW_HISTOGRAM,STYLE_SOLID,NewBarWidth);
   // ChartRedraw();
}

//+------------------------------------------------------------------+
//| RSI                                                              |
//+------------------------------------------------------------------+

string rsiMethodNames[] = {"RSI","Slow RSI","Rapid RSI","Harris RSI","RSX","Cuttler RSI"};
string getRsiName(int method)
{
   int max = ArraySize(rsiMethodNames)-1;
   method=fmax(fmin(method,max),0); return(rsiMethodNames[method]);
}

//
//
//
//
//

#define rsiInstances 1
double workRsi[][rsiInstances*13];
// We commented out "#define _price  0" below since it caused a "macro redefinition"
// warning when compiled as it was already defined above in line 986.
// #define _price  0
#define _change 1
#define _changa 2
#define _rsival 1
#define _rsval  1

double iRsi(int rsiMode, double price, double period, int i, int instanceNo=0)
{
   if(ArrayRange(workRsi,0)!=Bars) ArrayResize(workRsi,Bars);
   int z = instanceNo*13;
   int r = Bars-i-1;

   double up = 0;
   double dn = 0;
   double diff = 0;

   //
   //
   //
   //
   //

   workRsi[r][z+_price] = price;
   switch(rsiMode)
   {
      case rsi_rsi:
      {
         double alpha = 1.0/fmax(period,1);
         if(r<period)
         {
            int k; double sum = 0; for(k=0; k<period && (r-k-1)>=0; k++) sum += fabs(workRsi[r-k][z+_price]-workRsi[r-k-1][z+_price]);
            workRsi[r][z+_change] = (workRsi[r][z+_price]-workRsi[0][z+_price])/fmax(k,1);
            workRsi[r][z+_changa] =                                         sum/fmax(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*(fabs(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);
      }

      //
      //
      //
      //
      //

      case rsi_wil :
      {
         up = 0;
         dn = 0;
         for(int k=0; k<(int)period && (r-k-1)>=0; k++)
         {
            diff = workRsi[r-k][z+_price]- workRsi[r-k-1][z+_price];
            if(diff>0)
               up += diff;
            else  dn -= diff;
         }
         if(r<1)
            workRsi[r][z+_rsival] = 50;
         else if(up + dn == 0)
            workRsi[r][z+_rsival] = workRsi[r-1][z+_rsival]+(1/fmax(period,1))*(50            -workRsi[r-1][z+_rsival]);
         else  workRsi[r][z+_rsival] = workRsi[r-1][z+_rsival]+(1/fmax(period,1))*(100*up/(up+dn)-workRsi[r-1][z+_rsival]);
         return(workRsi[r][z+_rsival]);
      }

      //
      //
      //
      //
      //

      case rsi_rap :
      {
         up = 0;
         dn = 0;
         for(int k=0; k<(int)period && (r-k-1)>=0; k++)
         {
            diff = workRsi[r-k][z+_price]- workRsi[r-k-1][z+_price];
            if(diff>0)
               up += diff;
            else  dn -= diff;
         }
         if(up + dn == 0)
            return(50);
         else  return(100 * up / (up + dn));
      }

      //
      //
      //
      //
      //


      case rsi_har :
      {
         double avgUp1=0,avgDn1=0; up=0; dn=0;
         for(int k=0; k<(int)period && (r-k-1)>=0; k++)
         {
            diff = workRsi[r-k][instanceNo+_price]- workRsi[r-k-1][instanceNo+_price];
            if(diff>0)
            { avgUp1 += diff; up++; }
            else  { avgDn1 -= diff; dn++; }
         }
         if(up!=0) avgUp1 /= up;
         if(dn!=0) avgDn1 /= dn;
         double rs = 1;
         if(avgDn1!=0) rs = avgUp1/avgDn1;
         return(100-100/(1.0+rs));
      }

      //
      //
      //
      //
      //

      case rsi_rsx :
      {
         double Kg = (3.0)/(2.0+period), Hg = 1.0-Kg;
         if(r<period) { for(int k=1; k<13; k++) workRsi[r][k+z] = 0; return(50); }

         //
         //
         //
         //
         //

         double mom = workRsi[r][_price+z]-workRsi[r-1][_price+z];
         double moa = fabs(mom);
         for(int k=0; k<3; k++)
         {
            int kk = k*2;
            workRsi[r][z+kk+1] = Kg*mom                + Hg*workRsi[r-1][z+kk+1];
            workRsi[r][z+kk+2] = Kg*workRsi[r][z+kk+1] + Hg*workRsi[r-1][z+kk+2]; mom = 1.5*workRsi[r][z+kk+1] - 0.5 * workRsi[r][z+kk+2];
            workRsi[r][z+kk+7] = Kg*moa                + Hg*workRsi[r-1][z+kk+7];
            workRsi[r][z+kk+8] = Kg*workRsi[r][z+kk+7] + Hg*workRsi[r-1][z+kk+8]; moa = 1.5*workRsi[r][z+kk+7] - 0.5 * workRsi[r][z+kk+8];
         }
         if(moa != 0)
            return(fmax(fmin((mom/moa+1.0)*50.0,100.00),0.00));
         else return(50);
      }

      //
      //
      //
      //
      //

      case rsi_cut :
      {
         double sump = 0;
         double sumn = 0;
         for(int k=0; k<(int)period && r-k-1>=0; k++)
         {
            diff = workRsi[r-k][z+_price]-workRsi[r-k-1][z+_price];
            if(diff > 0) sump += diff;
            if(diff < 0) sumn -= diff;
         }
         if(sumn > 0)
            return(100.0-100.0/(1.0+sump/sumn));
         else  return(50);
      }
   }
   return(0);
}
//+--------------------------- END ----------------------------------+
