//+------------------------------------------------------------------+
//|                                                   CCI simple.mq4 |
//+------------------------------------------------------------------+
#property copyright "www,forex-tsd.com"
#property link      "www,forex-tsd.com"

#property indicator_separate_window
#property indicator_buffers 3
#property indicator_color1  LimeGreen
#property indicator_width1  1
#property indicator_color2  Red
#property indicator_width2  1
#property indicator_color3  Goldenrod
#property indicator_width3  3
#property indicator_level1  -100
#property indicator_level2  0
#property indicator_level3  100
#property indicator_levelcolor MediumOrchid




//
//
//
//
//
extern string separator1              = "***T3 CCI Settings ***";
extern int    CCIPeriod               = 14;
extern int    CCIPrice                = PRICE_TYPICAL;
extern int    T3Period                = 5;
extern double T3Hot                   = 0.70;
extern bool   T3Original              = false;
extern double OverSold                = -100;
extern double OverBought              =  100;

extern string separator2              = "*** Indicator Settings ***";
extern bool   drawDivergences         = true;
extern bool   drawIndicatorTrendLines = true;
extern bool   drawPriceTrendLines     = true;
extern string drawLinesIdentificator  = "ccidiverge";
extern bool   displayAlert            = true;
extern string NameSound               = "alert1.wav";






double bullishDivergence[];
double bearishDivergence[];
double CCI[];
double prices[];
double emas[][6];

double alpha;
double c1;
double c2;
double c3;
double c4;
double pipMultiplier = 1;

static datetime lastAlertTime;
string indicatorName;
string labelNames;

//
//
//
//
//

int init()
{
      IndicatorBuffers(4);
      SetIndexBuffer(0,bullishDivergence);SetIndexStyle(0, DRAW_ARROW);SetIndexArrow(0, 233);
      SetIndexBuffer(1,bearishDivergence);SetIndexStyle(1, DRAW_ARROW);SetIndexArrow(1, 234);
      SetIndexBuffer(2,CCI);
      SetIndexBuffer(3,prices);
      
      SetLevelValue(0,OverBought);
      SetLevelValue(1,OverSold);
      
      IndicatorDigits(Digits + 2);
         
       
       double a = T3Hot;
             c1 = -a*a*a;
             c2 =  3*(a*a+a*a*a);
             c3 = -3*(2*a*a+a+a*a*a);
             c4 = 1+3*a+a*a*a+3*a*a;

      T3Period = MathMax(1,T3Period);
      if (T3Original)
           alpha = 2.0/(1.0 + T3Period);
      else alpha = 2.0/(2.0 + (T3Period-1.0)/2.0);
      
     labelNames = "T3 CCI_DivergenceLine "+drawLinesIdentificator+":";
             
   indicatorName = "T3 CCI Divergence";
   IndicatorShortName(indicatorName);
   
   return(0);
}

int deinit()
  {
   int length=StringLen(labelNames);
   for(int i=ObjectsTotal()-1; i>=0; i--)
   {
   string name = ObjectName(i);
   if(StringSubstr(name,0,length) == labelNames)  ObjectDelete(name);   
   }
return(0);
  }
//
//
//
//

int start()
{
   if (Digits==3 || Digits==5) 
         pipMultiplier = 10;
   else  pipMultiplier = 1; 
   
   int counted_bars=IndicatorCounted();
   int i,k,limit;

   if(counted_bars<0) return(-1);
   if(counted_bars>0) counted_bars--;
         limit = MathMin(Bars-counted_bars,Bars-1);
         if (ArrayRange(emas,0) != Bars) ArrayResize(emas,Bars);

   //
   //
   //
   //
   //

   for(i=limit; i>=0; i--)
   {
      prices[i]  = iMA(NULL,0,1,0,MODE_SMA,CCIPrice,i);
      double avg = 0; for(k=0; k<CCIPeriod; k++) avg +=         prices[i+k];      avg /= CCIPeriod;
      double dev = 0; for(k=0; k<CCIPeriod; k++) dev += MathAbs(prices[i+k]-avg); dev /= CCIPeriod;
         if (dev!=0)
               CCI[i] = iT3((prices[i]-avg)/(0.015*dev),i);
               
         else  CCI[i] = iT3(0,                         i);  
         
       if (drawDivergences)
       {
       CatchBullishDivergence(i);
       CatchBearishDivergence(i);
       }           
   }
   return(0);
}



double iT3(double price,int shift)
{
   int i = Bars-shift-1;
   if (i < 1)
      {
         emas[i][0] = price;
         emas[i][1] = price;
         emas[i][2] = price;
         emas[i][3] = price;
         emas[i][4] = price;
         emas[i][5] = price;
      }
   else
      {
         emas[i][0] = emas[i-1][0]+alpha*(price     -emas[i-1][0]);
         emas[i][1] = emas[i-1][1]+alpha*(emas[i][0]-emas[i-1][1]);
         emas[i][2] = emas[i-1][2]+alpha*(emas[i][1]-emas[i-1][2]);
         emas[i][3] = emas[i-1][3]+alpha*(emas[i][2]-emas[i-1][3]);
         emas[i][4] = emas[i-1][4]+alpha*(emas[i][3]-emas[i-1][4]);
         emas[i][5] = emas[i-1][5]+alpha*(emas[i][4]-emas[i-1][5]);
      }
   return(c1*emas[i][5] + c2*emas[i][4] + c3*emas[i][3] + c4*emas[i][2]);
}


void CatchBullishDivergence(int shift)
{
   shift++;
         bullishDivergence[shift] = EMPTY_VALUE;
            ObjectDelete(labelNames+"l"+DoubleToStr(Time[shift],0));
            ObjectDelete(labelNames+"l"+"os" + DoubleToStr(Time[shift],0));            
   if(!IsIndicatorLow(shift)) return;  

   //
   //
   //
   //
   //
      
   int currentLow = shift;
   int lastLow = GetIndicatorLastLow(shift+1);

   //
   //
   //
   //
   //
    
   if(CCI[currentLow] > CCI[lastLow] && Low[currentLow] < Low[lastLow])
   {
      bullishDivergence[currentLow] = CCI[currentLow] - Point*pipMultiplier;
      if(drawPriceTrendLines == true)
                 DrawPriceTrendLine("l",Time[currentLow],Time[lastLow],Low[currentLow],Low[lastLow],Green,STYLE_SOLID);
      if(drawIndicatorTrendLines == true)
                 DrawIndicatorTrendLine("l",Time[currentLow],Time[lastLow],CCI[currentLow],CCI[lastLow],Green,STYLE_SOLID);
      if(displayAlert == true)
                 DisplayAlert("Classical bullish divergence on: ",currentLow);  
                        
   }
     
   //
   //
   //
   //
   //
        
   if(CCI[currentLow] < CCI[lastLow] && Low[currentLow] > Low[lastLow])
   {
      bullishDivergence[currentLow] = CCI[currentLow] - Point*pipMultiplier;
      if(drawPriceTrendLines == true)
                 DrawPriceTrendLine("l",Time[currentLow],Time[lastLow],Low[currentLow],Low[lastLow], Green, STYLE_DOT);
      if(drawIndicatorTrendLines == true)                            
                 DrawIndicatorTrendLine("l",Time[currentLow],Time[lastLow],CCI[currentLow], CCI[lastLow], Green, STYLE_DOT);
      if(displayAlert == true)
                 DisplayAlert("Reverse bullish divergence on: ",currentLow); 
   }
}


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

void CatchBearishDivergence(int shift)
{
   shift++; 
         bearishDivergence[shift] = EMPTY_VALUE;
            ObjectDelete(labelNames+"h"+DoubleToStr(Time[shift],0));
            ObjectDelete(labelNames+"h"+"os" + DoubleToStr(Time[shift],0));            
   if(IsIndicatorPeak(shift) == false) return;
   int currentPeak = shift;
   int lastPeak = GetIndicatorLastPeak(shift+1);

   //
   //
   //
   //
   //
      
   if(CCI[currentPeak] < CCI[lastPeak] && High[currentPeak]>High[lastPeak])
   {
       bearishDivergence[currentPeak] = CCI[currentPeak] + Point*pipMultiplier;
       if(drawPriceTrendLines == true)
               DrawPriceTrendLine("h",Time[currentPeak],Time[lastPeak],High[currentPeak],High[lastPeak],Red,STYLE_SOLID);
       if(drawIndicatorTrendLines == true)
               DrawIndicatorTrendLine("h",Time[currentPeak],Time[lastPeak],CCI[currentPeak],CCI[lastPeak],Red,STYLE_SOLID);
       if(displayAlert == true)
               DisplayAlert("Classical bearish divergence on: ",currentPeak); 
                        
   }
   
   //
   //
   //
   //
   //

   if(CCI[currentPeak] > CCI[lastPeak] && High[currentPeak] < High[lastPeak])
   {
      bearishDivergence[currentPeak] = CCI[currentPeak] + Point*pipMultiplier;
      if (drawPriceTrendLines == true)
               DrawPriceTrendLine("h",Time[currentPeak],Time[lastPeak],High[currentPeak],High[lastPeak], Red, STYLE_DOT);
      if (drawIndicatorTrendLines == true)
               DrawIndicatorTrendLine("h",Time[currentPeak],Time[lastPeak],CCI[currentPeak],CCI[lastPeak], Red, STYLE_DOT);
      if(displayAlert == true)
               DisplayAlert("Reverse bearish divergence on: ",currentPeak);
                         
   }   
}
//+------------------------------------------------------------------+
bool IsIndicatorPeak(int shift)
  {
   if(CCI[shift] >= CCI[shift+1] && CCI[shift] > CCI[shift+2] && 
      CCI[shift] > CCI[shift-1])
       return(true);
   else 
       return(false);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool IsIndicatorLow(int shift)
  {
   if(CCI[shift] <= CCI[shift+1] && CCI[shift] < CCI[shift+2] && 
      CCI[shift] < CCI[shift-1])
       return(true);
   else 
       return(false);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int GetIndicatorLastPeak(int shift)
  {
           for(int i = shift+5; i < Bars; i++)
             {
               if(CCI[i] >= CCI[i+1] && CCI[i] > CCI[i+2] &&
                  CCI[i] >= CCI[i-1] && CCI[i] > CCI[i-2])
                   return(i);
             }
   return(-1);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int GetIndicatorLastLow(int shift)
  {
            for(int i = shift+5; i < Bars; i++)
             {
                if(CCI[i] <= CCI[i+1] && CCI[i] < CCI[i+2] &&
                   CCI[i] <= CCI[i-1] && CCI[i] < CCI[i-2])
                    return(i);
              }
     
    return(-1);
  }

void DisplayAlert(string message, int shift)
  {
   if(shift <= 2 && Time[shift] != lastAlertTime)
     {
       lastAlertTime = Time[shift];
       PlaySound(NameSound);
       Alert(message, Symbol(), " , ", Period(), " minutes chart");
       
       
     }
  }


void DrawPriceTrendLine(string first,datetime t1, datetime t2, double p1, double p2, color lineColor, double style)
{
   string label = labelNames+first+"os"+DoubleToStr(t1,0);
   ObjectDelete(label);
      ObjectCreate(label, OBJ_TREND, 0, t1, p1, t2, p2, 0, 0);
         ObjectSet(label, OBJPROP_RAY, 0);
         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(indicatorName);
   if (indicatorWindow < 0) return;
   
   string label = labelNames+first+DoubleToStr(t1,0);
   ObjectDelete(label);
      ObjectCreate(label, OBJ_TREND, indicatorWindow, t1, p1, t2, p2, 0, 0);
         ObjectSet(label, OBJPROP_RAY, 0);
         ObjectSet(label, OBJPROP_COLOR, lineColor);
         ObjectSet(label, OBJPROP_STYLE, style);
}

