//------------------------------------------------------------------
#property copyright "www.forex-station.com"
#property link      "www.forex-station.com"
//------------------------------------------------------------------

#property indicator_separate_window
#property indicator_buffers    9
#property indicator_color1     clrDodgerBlue
#property indicator_color2     clrGold
#property indicator_color3     clrDodgerBlue
#property indicator_color4     clrLime
#property indicator_color5     clrRed
#property indicator_color6     clrLimeGreen
#property indicator_color7     clrLimeGreen
#property indicator_color8     clrOrangeRed
#property indicator_color9     clrOrangeRed
#property indicator_width2     2
#property indicator_width4     2
#property indicator_levelcolor clrDimGray
#property strict

//
//
//
//
//

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
};
enum stdMethods
{
   std_custSam, // Custom - with sample correction
   std_custNos  // Custom - without sample correction
};
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
};


extern int        RsiPeriod                    = 14;           // Rsi period
extern enRsiTypes RsiMethod                    = rsi_rsx;      // Rsi type
extern enPrices   RsiPrice                     = pr_close;     // Rsi price to use
extern double     RsiPriceLinePeriod           = 1;            // Rsi price line period
extern double     RsiPriceLinePhase            = 0;            // Rsi price line jurik phase
extern bool       RsiPriceLineDouble           = false;        // Rsi price line jurik smooth double
extern double     RsiSignalLinePeriod          = 14;           // Rsi signal line period
extern double     RsiSignalLinePhase           = 0;            // Rsi signal line jurik phase
extern bool       RsiSignalLineDouble          = false;        // Rsi signal line jurik double smooth
extern stdMethods DeviationType                = std_custSam;  // Deviation calculation type
extern int        VolatilityBandPeriod         = 34;           // Volatility band period
extern double     VolatilityBandMultiplier     = 1.6185;       // Volatility band multiplier
extern bool       Adaptive                     = false;        // Adaptive average?
extern bool       divergenceVisible            = false;        // Should the divergence be visible
extern bool       divergenceOnValuesVisible    = true;         // Divergence lines on macd visible?
extern bool       divergenceOnChartVisible     = true;         // Divergence lines on main chart visible?
extern int        DivergearrowSize             = 1;            // Divergence arrows size
extern double     DivergencearrowsUpperGap     = .05;          // Upper Gap between divergence arrows and indicator line
extern double     DivergencearrowsLowerGap     = .05;          // Lower Gap between divergence arrows and indicator line
extern bool       ShowClassicalDivergence      = true;         // Classical divergence visible
extern bool       ShowHiddenDivergence         = true;         // Hidden divergence visible
extern color      divergenceBullishColor       = clrLimeGreen; // Bullish divergences color
extern color      divergenceBearishColor       = clrOrangeRed; // Bearish divergences color
extern int        ClassicDivergenceUpArrowCode = 233;          // classical divergence up arrow code
extern int        ClassicDivergenceDnArrowCode = 234;          // classical divergence dn arrow code
extern int        HiddenDivergenceUpArrowCode  = 159;          // hidden divergence up arrow code
extern int        HiddenDivergenceDnArrowCode  = 159;          // hidden divergence dn arrow code
extern string     divergenceUniqueID           = "tdi div";    // Unique ID for divergence lines
extern bool       alertsOn                     = false;        // Turn alerts on?
extern bool       alertsOnCurrent              = false;        // Alerts on still opened bar?
extern bool       alertsMessage                = true;         // Alerts should display message?
extern bool       alertsSound                  = false;        // Alerts should play a sound?
extern bool       alertsNotify                 = false;        // Alerts should send a notification?
extern bool       alertsEmail                  = false;        // Alerts should send an email?
extern string     soundFile                    = "alert2.wav"; // Sound file
extern double     LevelDown                    = 32;           // Lower level
extern double     LevelMiddle                  = 50;           // Middle level
extern double     LevelUp                      = 68;           // Upper level


double rsi[];
double rsiPl[];
double rsiSl[];
double bandUp[];
double bandMi[];
double bandDn[];
double cbulld[];
double hbulld[];
double cbeard[];
double hbeard[];
string shortName;
double trend[];
double prices[];

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+

int init() {
   IndicatorBuffers(12);
   SetIndexBuffer(0, bandUp);
   SetIndexBuffer(1, bandMi);
   SetIndexBuffer(2, bandDn);
   SetIndexBuffer(3, rsiPl);
   SetIndexBuffer(4, rsiSl);
   SetIndexBuffer(5, cbulld);   SetIndexStyle(5, DRAW_ARROW,0,DivergearrowSize); SetIndexArrow(5, ClassicDivergenceUpArrowCode);
   SetIndexBuffer(6, hbulld);   SetIndexStyle(6, DRAW_ARROW,0,DivergearrowSize); SetIndexArrow(6, HiddenDivergenceUpArrowCode);
   SetIndexBuffer(7, cbeard);   SetIndexStyle(7, DRAW_ARROW,0,DivergearrowSize); SetIndexArrow(7, ClassicDivergenceDnArrowCode);
   SetIndexBuffer(8, hbeard);   SetIndexStyle(8, DRAW_ARROW,0,DivergearrowSize); SetIndexArrow(8, HiddenDivergenceDnArrowCode);
   SetIndexBuffer(9, rsi);
   SetIndexBuffer(10,trend);
   SetIndexBuffer(11,prices);

   SetLevelValue(0,LevelUp);
   SetLevelValue(1,LevelMiddle);
   SetLevelValue(2,LevelDown);
   
   shortName = divergenceUniqueID+": TDI of "+getRsiName((int)RsiMethod)+"  ("+(string)RsiPeriod+","+(string)RsiPriceLinePeriod+", "+(string)RsiSignalLinePeriod+")";
   IndicatorShortName(shortName);
 
return (0);
}
void OnDeinit(const int reason) 
{ 
    int lookForLength = StringLen(divergenceUniqueID);
   
      for (int i=ObjectsTotal()-1; i>=0; i--) 
      {
         string name = ObjectName(i);  if (StringSubstr(name,0,lookForLength) == divergenceUniqueID) ObjectDelete(name);
      }
return;
}

  
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//

int start() {
   int i,limit,counted_bars=IndicatorCounted();
   if(counted_bars<0) return(-1);
   if(counted_bars>0) counted_bars--;
         limit = fmin(Bars-counted_bars,Bars-1);
         
   
   //
   //
   //
   //
   //
   
     for (i=limit; i >= 0; i--)
     {    
        prices[i] = getPrice(RsiPrice,Open,Close,High,Low,i); double period = RsiPeriod;    
        if (Adaptive)
        { 
          double noise = 0, vhf = 0;
          double max   = prices[i];
          double min   = prices[i];
          for (int k=0; k<RsiPeriod && (i+k+1)<Bars; k++)
          {
              noise += fabs(prices[i+k]-prices[i+k+1]);
              max    = fmax(prices[i+k],max);   
              min    = fmin(prices[i+k],min);   
          }      
          if (noise>0) vhf = (max-min)/noise;
          if (vhf!=0)
                period = fmin(fmax(-MathLog(vhf)*RsiPeriod,RsiPeriod/2.0),RsiPeriod*3.0);
          else  period = RsiPeriod;
        }  
                
        //
        //
        //
        //
        //
        
        rsi[i]    = iRsi(RsiMethod,prices[i],period,i);  
        rsiPl[i]  = iDSmooth(rsi[i],RsiPriceLinePeriod ,RsiPriceLinePhase ,RsiPriceLineDouble, i, 0);
        rsiSl[i]  = iDSmooth(rsi[i],RsiSignalLinePeriod,RsiSignalLinePhase,RsiSignalLineDouble,i,20);
        bandMi[i] = 0; for (int k=0; k<VolatilityBandPeriod && (i+k)<Bars; k++) bandMi[i] += rsi[i+k]; bandMi[i] /= VolatilityBandPeriod;
        double deviation = iDeviation(rsi[i],VolatilityBandPeriod,DeviationType==std_custSam,i);
               bandUp[i] = bandMi[i]+VolatilityBandMultiplier*deviation;
               bandDn[i] = bandMi[i]-VolatilityBandMultiplier*deviation;
               trend[i] = (i<Bars-1) ? (rsiPl[i]>rsiSl[i]) ? 1 : (rsiPl[i]<rsiSl[i+1]) ? -1 : trend[i+1] : 0;
               if (divergenceVisible)
               {
                 CatchBullishDivergence(rsiPl,i);
                 CatchBearishDivergence(rsiPl,i);
               } 
      }
      if (alertsOn)
      {
         int whichBar = 1; if (alertsOnCurrent) whichBar = 0; 
         if (trend[whichBar] != trend[whichBar+1])
         {
            if (trend[whichBar] == 1) doAlert(" up");
            if (trend[whichBar] ==-1) doAlert(" down");       
         }         
   }              
   return (0);
 }      
 
//------------------------------------------------------------------
//                                                                  
//------------------------------------------------------------------
//
//
//
//
//
//

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];
#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;
   
   //
   //
   //
   //
   //
   
   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 :
         {         
            double up = 0;
            double dn = 0;
            for(int k=0; k<(int)period && (r-k-1)>=0; k++)
            {
               double 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 :
         {
            double up = 0;
            double dn = 0;
            for(int k=0; k<(int)period && (r-k-1)>=0; k++)
            {
               double 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 avgUp=0,avgDn=0; double up=0; double dn=0;
            for(int k=0; k<(int)period && (r-k-1)>=0; k++)
            {
               double diff = workRsi[r-k][instanceNo+_price]- workRsi[r-k-1][instanceNo+_price];
               if(diff>0)
                     { avgUp += diff; up++; }
               else  { avgDn -= diff; dn++; }
            }
            if (up!=0) avgUp /= up;
            if (dn!=0) avgDn /= dn;
            double rs = 1;
               if (avgDn!=0) rs = avgUp/avgDn;
               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++)
            {
               double 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);
}

//------------------------------------------------------------------
//                                                                  
//------------------------------------------------------------------
// 
//
//
//
//

double workDev[];
double iDeviation(double value, int length, bool isSample, int i)
{
   if (ArraySize(workDev)!=Bars) ArrayResize(workDev,Bars); i=Bars-i-1; workDev[i] = value;
                 
   //
   //
   //
   //
   //
   
      double oldMean   = value;
      double newMean   = value;
      double squares   = 0; int k;
      for (k=1; k<length && (i-k)>=0; k++)
      {
         newMean  = (workDev[i-k]-oldMean)/(k+1)+oldMean;
         squares += (workDev[i-k]-oldMean)*(workDev[i-k]-newMean);
         oldMean  = newMean;
      }
      return(MathSqrt(squares/MathMax(k-isSample,1)));
}

//
//
//
//
//

double workEma[][2];
double iEma(double price, double period, int r, int instanceNo=0)
{
   if (ArrayRange(workEma,0)!= Bars) ArrayResize(workEma,Bars); r = Bars-r-1;

   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]);
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//
//

#define priceInstances 1
double workHa[][priceInstances*4];
double getPrice(int tprice, const double& open[], const double& close[], const double& high[], const double& low[], int i, int instanceNo=0)
{
  if (tprice>=pr_haclose)
   {
      if (ArrayRange(workHa,0)!= Bars) ArrayResize(workHa,Bars); instanceNo*=4;
         int r = Bars-i-1;
         
         //
         //
         //
         //
         //
         
         double haOpen;
         if (r>0)
                haOpen  = (workHa[r-1][instanceNo+2] + workHa[r-1][instanceNo+3])/2.0;
         else   haOpen  = (open[i]+close[i])/2;
         double haClose = (open[i] + high[i] + low[i] + close[i]) / 4.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:     return(haClose);
            case pr_haopen:      return(haOpen);
            case pr_hahigh:      return(haHigh);
            case pr_halow:       return(haLow);
            case pr_hamedian:    return((haHigh+haLow)/2.0);
            case pr_hamedianb:   return((haOpen+haClose)/2.0);
            case pr_hatypical:   return((haHigh+haLow+haClose)/3.0);
            case pr_haweighted:  return((haHigh+haLow+haClose+haClose)/4.0);
            case pr_haaverage:   return((haHigh+haLow+haClose+haOpen)/4.0);
            case pr_hatbiased:
               if (haClose>haOpen)
                     return((haHigh+haClose)/2.0);
               else  return((haLow+haClose)/2.0);        
            case pr_hatbiased2:
               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);
}   


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//

double wrk[][40];

#define bsmax  5
#define bsmin  6
#define volty  7
#define vsum   8
#define avolty 9

double iDSmooth(double price, double length, double phase, bool isDouble, int i, int s=0) 
{
   if (isDouble)
         return (iSmooth(iSmooth(price,MathSqrt(length),phase,i,s),MathSqrt(length),phase,i,s+10));
   else  return (iSmooth(price,length,phase,i,s));
}

//
//
//
//
//

double iSmooth(double price, double length, double phase, int i, int s=0)
{
   if (length <=1) return(price);
   if (ArrayRange(wrk,0) != Bars) ArrayResize(wrk,Bars);
   
   int r = Bars-i-1; 
      if (r==0) { int k; for(k=0; k<7; k++) wrk[r][k+s]=price; for(; k<10; k++) wrk[r][k+s]=0; return(price); }

   //
   //
   //
   //
   //
   
      double len1   = MathMax(MathLog(MathSqrt(0.5*(length-1)))/MathLog(2.0)+2.0,0);
      double pow1   = MathMax(len1-2.0,0.5);
      double del1   = price - wrk[r-1][bsmax+s];
      double del2   = price - wrk[r-1][bsmin+s];
      double div    = 1.0/(10.0+10.0*(MathMin(MathMax(length-10,0),100))/100);
      int    forBar = MathMin(r,10);
	
         wrk[r][volty+s] = 0;
               if(MathAbs(del1) > MathAbs(del2)) wrk[r][volty+s] = MathAbs(del1); 
               if(MathAbs(del1) < MathAbs(del2)) wrk[r][volty+s] = MathAbs(del2); 
         wrk[r][vsum+s] =	wrk[r-1][vsum+s] + (wrk[r][volty+s]-wrk[r-forBar][volty+s])*div;
         
         //
         //
         //
         //
         //
   
         wrk[r][avolty+s] = wrk[r-1][avolty+s]+(2.0/(MathMax(4.0*length,30)+1.0))*(wrk[r][vsum+s]-wrk[r-1][avolty+s]);
            double dVolty = 0;
            if (wrk[r][avolty+s] > 0)
                  dVolty = wrk[r][volty+s]/wrk[r][avolty+s];   
	               if (dVolty > MathPow(len1,1.0/pow1)) dVolty = MathPow(len1,1.0/pow1);
                  if (dVolty < 1)                      dVolty = 1.0;

      //
      //
      //
      //
      //
	        
   	double pow2 = MathPow(dVolty, pow1);
      double len2 = MathSqrt(0.5*(length-1))*len1;
      double Kv   = MathPow(len2/(len2+1), MathSqrt(pow2));

         if (del1 > 0) wrk[r][bsmax+s] = price; else wrk[r][bsmax+s] = price - Kv*del1;
         if (del2 < 0) wrk[r][bsmin+s] = price; else wrk[r][bsmin+s] = price - Kv*del2;
	
   //
   //
   //
   //
   //
      
      double R     = MathMax(MathMin(phase,100),-100)/100.0 + 1.5;
      double beta  = 0.45*(length-1)/(0.45*(length-1)+2);
      double alpha = MathPow(beta,pow2);

         wrk[r][0+s] = price + alpha*(wrk[r-1][0+s]-price);
         wrk[r][1+s] = (price - wrk[r][0+s])*(1-beta) + beta*wrk[r-1][1+s];
         wrk[r][2+s] = (wrk[r][0+s] + R*wrk[r][1+s]);
         wrk[r][3+s] = (wrk[r][2+s] - wrk[r-1][4+s])*MathPow((1-alpha),2) + MathPow(alpha,2)*wrk[r-1][3+s];
         wrk[r][4+s] = (wrk[r-1][4+s] + wrk[r][3+s]); 

   //
   //
   //
   //
   //

   return(wrk[r][4+s]);
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//


void CatchBullishDivergence(double& values[], int i)
{
   i++;
            cbulld[(int)fmin(i,Bars-1)] = EMPTY_VALUE;
            hbulld[(int)fmin(i,Bars-1)] = EMPTY_VALUE;
            ObjectDelete(divergenceUniqueID+"l"+ DoubleToStr(Time[(int)fmin(i,Bars-1)],0));
            ObjectDelete(divergenceUniqueID+"l"+"os" + DoubleToStr(Time[(int)fmin(i,Bars-1)],0));            
   if (!IsIndicatorLow(values,(int)fmin(i,Bars-1))) return;  

   //
   //
   //
   //
   //

   int currentLow = i;
   int lastLow    = GetIndicatorLastLow(values,i+1);
      if (currentLow>=0 && currentLow<Bars && lastLow>=0) 
      if (values[currentLow] > values[lastLow] && Low[currentLow] < Low[lastLow])
      {
        if (ShowClassicalDivergence)
        {
          cbulld[currentLow] = values[currentLow] - DivergencearrowsLowerGap;
          if(divergenceOnChartVisible)  DrawPriceTrendLine("l",Time[currentLow],Time[lastLow],Low[currentLow],Low[lastLow],          divergenceBullishColor,STYLE_SOLID);
          if(divergenceOnValuesVisible) DrawIndicatorTrendLine("l",Time[currentLow],Time[lastLow],values[currentLow],values[lastLow],divergenceBullishColor,STYLE_SOLID);
        }
      }
      
      if (currentLow>=0 && currentLow<Bars && lastLow>=0) 
      if (values[currentLow] < values[lastLow] && Low[currentLow] > Low[lastLow])
      {
        if (ShowHiddenDivergence)
        {
          hbulld[currentLow] = values[currentLow] - DivergencearrowsLowerGap;
          if(divergenceOnChartVisible)  DrawPriceTrendLine("l",Time[currentLow],Time[lastLow],Low[currentLow],Low[lastLow],           divergenceBullishColor, STYLE_DOT);
          if(divergenceOnValuesVisible) DrawIndicatorTrendLine("l",Time[currentLow],Time[lastLow],values[currentLow],values[lastLow], divergenceBullishColor, STYLE_DOT);
        }
      }
}

//
//
//
//
//

void CatchBearishDivergence(double& values[], int i)
{
   i++; 
            cbeard[(int)fmin(i,Bars-1)] = EMPTY_VALUE;
            hbeard[(int)fmin(i,Bars-1)] = EMPTY_VALUE;
            ObjectDelete(divergenceUniqueID+"h"+DoubleToStr(Time[(int)fmin(i,Bars-1)],0));
            ObjectDelete(divergenceUniqueID+"h"+"os" + DoubleToStr(Time[(int)fmin(i,Bars-1)],0));            
   if (IsIndicatorPeak(values,(int)fmin(i,Bars-1)) == false) return;

   //
   //
   //
   //
   //
      
   int currentPeak = i;
   int lastPeak = GetIndicatorLastPeak(values,i+1);
      if (currentPeak>=0 && currentPeak<Bars && lastPeak>=0) 
      if (values[currentPeak] < values[lastPeak] && High[currentPeak]>High[lastPeak])
      {
        if (ShowClassicalDivergence)
        {
          cbeard[currentPeak] = values[currentPeak] + DivergencearrowsUpperGap;
          if (divergenceOnChartVisible)  DrawPriceTrendLine("h",Time[currentPeak],Time[lastPeak],High[currentPeak],High[lastPeak],        divergenceBearishColor,STYLE_SOLID);
          if (divergenceOnValuesVisible) DrawIndicatorTrendLine("h",Time[currentPeak],Time[lastPeak],values[currentPeak],values[lastPeak],divergenceBearishColor,STYLE_SOLID);
        }
      }
      if (currentPeak>=0 && currentPeak<Bars && lastPeak>=0) 
      if (values[currentPeak] > values[lastPeak] && High[currentPeak] < High[lastPeak])
      {
        if (ShowHiddenDivergence)
        {
          hbeard[currentPeak] = values[currentPeak] + DivergencearrowsUpperGap;
          if (divergenceOnChartVisible)  DrawPriceTrendLine("h",Time[currentPeak],Time[lastPeak],High[currentPeak],High[lastPeak],         divergenceBearishColor, STYLE_DOT);
          if (divergenceOnValuesVisible) DrawIndicatorTrendLine("h",Time[currentPeak],Time[lastPeak],values[currentPeak],values[lastPeak], divergenceBearishColor, STYLE_DOT);
        }
      }
}

//
//
//
//
//

bool IsIndicatorPeak(double& values[], int i) { return(values[i] >= values[(int)fmin(i+1,Bars-1)] && values[i] > values[(int)fmin(i+2,Bars-1)] && values[i] > values[(int)fmax(i-1,0)]); }
bool IsIndicatorLow( double& values[], int i) { return(values[i] <= values[(int)fmin(i+1,Bars-1)] && values[i] < values[(int)fmin(i+2,Bars-1)] && values[i] < values[(int)fmax(i-1,0)]); }

int GetIndicatorLastPeak(double& values[], int shift)
{
   for(int i = shift+5; i<Bars && (i+2)<(Bars-1) && (i-2)>=0; i++)
         if (values[i] >= values[i+1] && values[i] > values[i+2] && values[i] >= values[i-1] && values[i] > values[i-2]) return(i);
   return(-1);
}
int GetIndicatorLastLow(double& values[], int shift)
{
   for(int i = shift+5; i<Bars && (i+2)<(Bars-1) && (i-2)>=0; i++)
         if (values[i] <= values[i+1] && values[i] < values[i+2] && values[i] <= values[i-1] && values[i] < values[i-2]) return(i);
   return(-1);
}

//+------------------------------------------------------------------
//|                                                                  
//+------------------------------------------------------------------
//
//
//
//
//

void DrawPriceTrendLine(string first,datetime t1, datetime t2, double p1, double p2, color lineColor, double style)
{
   string   label = divergenceUniqueID+first+"os"+DoubleToStr(t1,0);
   ObjectDelete(label);
      ObjectCreate(label, OBJ_TREND, 0, t1+Period()*60-1, p1, t2, p2, 0, 0);
         ObjectSet(label, OBJPROP_RAY, false);
         ObjectSet(label, OBJPROP_COLOR, lineColor);
         ObjectSet(label, OBJPROP_STYLE, style);
}
void DrawIndicatorTrendLine(string first,datetime t1, datetime t2, double p1, double p2, color lineColor, double style)
{
   int indicatorWindow = WindowFind(shortName);
   if (indicatorWindow < 0) return;
   string label = divergenceUniqueID+first+DoubleToStr(t1,0);
   ObjectDelete(label);
      ObjectCreate(label, OBJ_TREND, indicatorWindow, t1+Period()*60-1, p1, t2, p2, 0, 0);
         ObjectSet(label, OBJPROP_RAY, false);
         ObjectSet(label, OBJPROP_COLOR, lineColor);
         ObjectSet(label, OBJPROP_STYLE, style);
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

void doAlert(string doWhat)
{
   static string   previousAlert="nothing";
   static datetime previousTime;
   string message;
   
      if (previousAlert != doWhat || previousTime != Time[0]) {
          previousAlert  = doWhat;
          previousTime   = Time[0];

          //
          //
          //
          //
          //

          message =  StringConcatenate(_Symbol," at ",TimeToStr(TimeLocal(),TIME_SECONDS)," TDI ",doWhat);
             if (alertsMessage) Alert(message);
             if (alertsNotify)  SendNotification(message);
             if (alertsEmail)   SendMail(_Symbol+" TDI ",message);
             if (alertsSound)   PlaySound(soundFile);
      }
}

