#property copyright "mladen"
#property link      "mladenfx@gmail.com"

#property indicator_separate_window
#property indicator_buffers 4
#property indicator_color1  clrDimGray
#property indicator_color2  clrRed
#property indicator_color3  clrLime
#property indicator_color4  clrGold
#property indicator_width4  1
#property indicator_style2  STYLE_DOT
#property indicator_style3  STYLE_DOT

extern ENUM_TIMEFRAMES TimeFrame = PERIOD_CURRENT;  // Time frame
extern int             CCIPeriod        = 12;
extern ENUM_APPLIED_PRICE CCIPrice      = PRICE_CLOSE;
extern int             HighLowPeriod    = 13;
extern int             T3Period         = 5;
extern double          T3Hot            = 0.8;
extern bool            T3Original       = true;
extern bool            ShowChannel      = true;
extern bool            ShowZigZag       = true;
extern bool            alertsOn         = true;
extern bool            alertsOnCurrent  = true;
extern bool            alertsMessage    = true;
extern bool            alertsSound      = true;
extern bool            alertsEmail      = false;
extern bool            alertsNotify     = true;
extern string          soundFile        = "alert2.wav";
extern bool            arrowsVisible    = false;             // Arrows visible?
extern bool            arrowsOnNewest   = true;              // Arrows drawn on newest bar of higher time frame bar?
extern string          arrowsIdentifier = "cci Arrows1";    // Unique ID for arrows
extern double          arrowsUpperGap   = 0.5;               // Upper arrow gap
extern double          arrowsLowerGap   = 0.5;               // Lower arrow gap
extern color           arrowsUpColor    = clrLimeGreen;      // Up arrow color
extern color           arrowsDnColor    = clrOrange;         // Down arrow color
extern int             arrowsUpCode     = 159;               // Up arrow code
extern int             arrowsDnCode     = 159;               // Down arrow code
input bool             Interpolate      = true;            // Interpolate true/false?
int Direction =0;

double T3RSIBuffer[];
double HighBuffer[];
double LowBuffer[];
double ZigZagBuffer[];
double ZigZagLow[];
double ZigZagHigh[];
double trend[],count[];

double emas[][6];
double alpha;
double c1;
double c2;
double c3;
double c4;
string indicatorFileName;
#define _mtfCall(_buff,_ind) iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,CCIPeriod,CCIPrice,HighLowPeriod,T3Period,T3Hot,T3Original,ShowChannel,ShowZigZag,alertsOn,alertsOnCurrent,alertsMessage,alertsSound,alertsEmail,alertsNotify,soundFile,arrowsVisible,arrowsOnNewest,arrowsIdentifier,arrowsUpperGap,arrowsLowerGap,arrowsUpColor,arrowsDnColor,arrowsUpCode,arrowsDnCode,_buff,_ind)

int init()
{
   IndicatorBuffers(8);
   SetIndexBuffer(0,ZigZagBuffer);
   SetIndexBuffer(1,HighBuffer);
   SetIndexBuffer(2,LowBuffer);
   SetIndexBuffer(3,T3RSIBuffer);
   SetIndexBuffer(4,ZigZagLow);
   SetIndexBuffer(5,ZigZagHigh);
   SetIndexBuffer(6,trend);
   SetIndexBuffer(7,count);
   SetIndexStyle(0,DRAW_SECTION);
   SetIndexEmptyValue(0,0);
   SetIndexEmptyValue(3,0);
   SetIndexEmptyValue(4,0);
   SetIndexEmptyValue(5,0);
   SetIndexLabel(0,NULL);

   if (ShowChannel)
   {
      SetIndexStyle(1,DRAW_LINE);
      SetIndexStyle(2,DRAW_LINE);
   }
   else      
   {
     SetIndexStyle(1,DRAW_NONE);
     SetIndexStyle(2,DRAW_NONE);
   }

      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);
      
      indicatorFileName = WindowExpertName();
      TimeFrame         = fmax(TimeFrame,_Period);
   IndicatorShortName(timeFrameToString(TimeFrame)+" CCIchannel");
   return(0);
}
void OnDeinit(const int reason)
{ 
    string lookFor       = arrowsIdentifier+":";
    int    lookForLength = StringLen(lookFor);
    for (int i=ObjectsTotal()-1; i>=0; i--)
    {
       string objectName = ObjectName(i);
       if (StringSubstr(objectName,0,lookForLength) == lookFor) ObjectDelete(objectName);
    }
}

int start()
{
   int lastZag;
  int i,counted_bars=IndicatorCounted();
      if(counted_bars<0) return(-1);
      if(counted_bars>0) counted_bars--;
         int limit = fmin(Bars-counted_bars,Bars-1); count[0] = limit;
         if (TimeFrame != _Period)
         {
            limit = (int)fmax(limit,fmin(Bars-1,_mtfCall(7,0)*TimeFrame/_Period));
            for (i=limit;i>=0 && !_StopFlag; i--)
            {
                int y = iBarShift(NULL,TimeFrame,Time[i]);
                   ZigZagBuffer[i] = _mtfCall(0,y); 
                   HighBuffer[i]   = _mtfCall(1,y);
                   LowBuffer[i]    = _mtfCall(2,y); 
                   T3RSIBuffer[i]  = _mtfCall(3,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 btime = iTime(NULL,TimeFrame,y);
                      for(n = 1; (i+n)<Bars && Time[i+n] >= btime; n++) continue;	
                      for(k = 1; k<n && (i+n)<Bars && (i+k)<Bars; k++) 
                      {
                       // _interpolate(ZigZagBuffer);
                        _interpolate(HighBuffer);
                        _interpolate(LowBuffer); 
                        _interpolate(T3RSIBuffer);
                      }                       
            }
   return(0);
   } 
    
   if (ArrayRange(emas,0) != Bars) ArrayResize(emas,Bars);
   if (ShowZigZag)
   for (lastZag=limit+1; lastZag<Bars; lastZag++) if (ZigZagLow[lastZag] != 0 || ZigZagHigh[lastZag] != 0) break;
   for(i=limit; i>=0; i--) 
   {
      T3RSIBuffer[i] = iT3(iCCI(NULL,0,CCIPeriod,CCIPrice,i),i);
      LowBuffer[i]   = T3RSIBuffer[ArrayMinimum(T3RSIBuffer,HighLowPeriod,i)];
      HighBuffer[i]  = T3RSIBuffer[ArrayMaximum(T3RSIBuffer,HighLowPeriod,i)];
    
      trend[i] = 0;
           if (T3RSIBuffer[i]>=HighBuffer[i]) trend[i] = 1;
           if (T3RSIBuffer[i]<=LowBuffer[i])  trend[i] =-1;  
   
     if (arrowsVisible)
      {
         string lookFor = arrowsIdentifier+":"+(string)Time[i]; ObjectDelete(lookFor);            
         if (i<(Bars-1) && trend[i] != trend[i+1])
         {
            if (trend[i+1] ==  1 && trend[i] != 1) drawArrow(i,arrowsDnColor,arrowsDnCode,true);
            if (trend[i+1] == -1 && trend[i] !=-1) drawArrow(i,arrowsUpColor,arrowsUpCode,false);
         }
      }
 
         if (!ShowZigZag) continue;


         
         ZigZagLow[i]  = 0;
         ZigZagHigh[i] = 0;
         if (LowBuffer[i] < LowBuffer[i+1])
            {
               if (ZigZagBuffer[lastZag] == LowBuffer[lastZag])
                   ZigZagBuffer[lastZag] = 0;
                   ZigZagBuffer[i]       =  LowBuffer[i];
                   ZigZagLow[i]          =  LowBuffer[i];
                                 lastZag = i;
                                 continue;
            }
         if (HighBuffer[i] > HighBuffer[i+1])
            {
               if (ZigZagBuffer[lastZag] == HighBuffer[lastZag])
                   ZigZagBuffer[lastZag] = 0;
                   ZigZagBuffer[i]       =  HighBuffer[i];
                   ZigZagHigh[i]         =  HighBuffer[i];
                                 lastZag = i;
                                 continue;
            }
         if (ZigZagBuffer[i] != 0)
            {
               ZigZagBuffer[i] = 0;
               for (lastZag=i+1; lastZag<Bars; lastZag++)
               {
                  if (ZigZagLow[lastZag]  != 0) { ZigZagBuffer[lastZag] = ZigZagLow[lastZag];  break; }
                  if (ZigZagHigh[lastZag] != 0) { ZigZagBuffer[lastZag] = ZigZagHigh[lastZag]; break; }
               }
            }
            
    }
  
   if (alertsOn)
   {
      if (alertsOnCurrent)
           int whichBar = 0;
      else     whichBar = 1;
      if (trend[whichBar] != trend[whichBar+1])
      {
         if (trend[whichBar+1] ==  1 && trend[whichBar] != 1) {
         if (Direction != 1) {
                 Direction = 1;
                 doAlert(whichBar," : RSIchannel - SELL");
                 }
                 }
         if (trend[whichBar+1] == -1 && trend[whichBar] !=-1) {
         if (Direction !=-1){
         Direction = -1;
         doAlert(whichBar," : RSIchannel - BUY");
         }
         }
      }         
   }
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 doAlert(int forBar, string doWhat)
{
   static string   previousAlert="nothing";
   static datetime previousTime;
   string message;
   
   if (previousAlert != doWhat || previousTime != Time[forBar]) {
       previousAlert  = doWhat;
       previousTime   = Time[forBar];

       message =  StringConcatenate(Symbol()," M",Period(),doWhat);
             if (alertsMessage) Alert(message);
             if (alertsNotify)  SendNotification(message);
             if (alertsEmail)   SendMail(StringConcatenate(Symbol()," rsi channel "),message);
             if (alertsSound)   PlaySound(soundFile); 
   }
}

//-------------------------------------------------------------------
//                                                                  
//-------------------------------------------------------------------
//
//
//
//
//

void drawArrow(int i,color theColor,int theCode,bool up)
{
   string name = arrowsIdentifier+":"+(string)Time[i];
   double gap  = iATR(NULL,0,20,i);   
   
      //
      //
      //
      //
      //

      datetime time = Time[i]; if (arrowsOnNewest) time += _Period*60-1;      
      ObjectCreate(name,OBJ_ARROW,0,time,0);
         ObjectSet(name,OBJPROP_ARROWCODE,theCode);
         ObjectSet(name,OBJPROP_COLOR,theColor);
         if (up)
               ObjectSet(name,OBJPROP_PRICE1,High[i] + arrowsUpperGap * gap);
         else  ObjectSet(name,OBJPROP_PRICE1,Low[i]  - arrowsLowerGap * gap);
}

//
//
//
//
//

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("");
}




