//------------------------------------------------------------------
#property copyright "www.forex-station.com"
#property link      "www.forex-station.com"
//------------------------------------------------------------------
#property indicator_chart_window
#property indicator_buffers 2

#property indicator_label1  "Chandelier upper"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrBlue
#property indicator_width1  3

#property indicator_label2  "Chandelier lower"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrRed
#property indicator_width2  3
#property strict

extern ENUM_TIMEFRAMES TimeFrame       = PERIOD_CURRENT;  // Time frame
input int              Length          = 15;              // Hi/Lo look back period
input int              AtrPeriod       = 14;              // Atr period
input double           Kv              = 4.0;             // Atr multiplier
input int              Shift           = 1;               // Shift
input bool             Interpolate     = true;            // Interpolate on/off?

//
//
//
//
//

double upLine[],dnLine[],smin[],smax[],trend[],count[];
string indicatorFileName;
#define _mtfCall(_buff,_y) iCustom(NULL,TimeFrame,indicatorFileName,PERIOD_CURRENT,Length,AtrPeriod,Kv,Shift,_buff,_y)

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

int OnInit()
{
   IndicatorBuffers(6);
   SetIndexBuffer(0, upLine,INDICATOR_DATA); 
   SetIndexBuffer(1, dnLine,INDICATOR_DATA); 
   SetIndexBuffer(2, smax,  INDICATOR_CALCULATIONS);
   SetIndexBuffer(3, smin,  INDICATOR_CALCULATIONS);
   SetIndexBuffer(4, trend, INDICATOR_CALCULATIONS);
   SetIndexBuffer(5, count, INDICATOR_CALCULATIONS);
      
   indicatorFileName = WindowExpertName();
   TimeFrame         = fmax(TimeFrame,_Period);  
        
   IndicatorSetString(INDICATOR_SHORTNAME,timeFrameToString(TimeFrame)+" Chandelier stops");
return(INIT_SUCCEEDED);
}  
void OnDeinit(const int reason) { }

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

int OnCalculate (const int       rates_total,
                 const int       prev_calculated,
                 const datetime& time[],
                 const double&   open[],
                 const double&   high[],
                 const double&   low[],
                 const double&   close[],
                 const long&     tick_volume[],
                 const long&     volume[],
                 const int&      spread[] )
{
       int i,limit=fmin(rates_total-prev_calculated+1,rates_total-1); count[0]=limit;
            if (TimeFrame!=_Period)
            {
               limit = (int)fmax(limit,fmin(rates_total-1,_mtfCall(5,0)*TimeFrame/_Period));
               for (i=limit;i>=0; i--)
               {
                  int y = iBarShift(NULL,TimeFrame,time[i]);
                     smax[i]  = _mtfCall(2,y);
                     smin[i]  = _mtfCall(3,y);
                     trend[i] = _mtfCall(4,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)<rates_total && time[i+n] >= btime; n++) continue;	
                        for(k = 1; k<n && (i+n)<rates_total && (i+k)<rates_total; k++) 
                        {
                           _interpolate(smax);
                           _interpolate(smin);
                        }                  
               }
               for (i=limit;i>=0; i--)
               {
                   upLine[i] = (trend[i] == 1) ? smin[i] : EMPTY_VALUE;
                   dnLine[i] = (trend[i] ==-1) ? smax[i] : EMPTY_VALUE;
               }         
   return(rates_total);
   }               

   //
   //
   //
   //
   //

   for(i=limit; i>=0; i--)
   {
      smin[i]  = high[iHighest(NULL,0,MODE_HIGH,Length,(int)fmin(rates_total-1,i+Shift))] - Kv*iATR(NULL,0,AtrPeriod,(int)fmin(rates_total-1,i+Shift)); 
	   smax[i]  =  low[iLowest( NULL,0,MODE_LOW, Length,(int)fmin(rates_total-1,i+Shift))] + Kv*iATR(NULL,0,AtrPeriod,(int)fmin(rates_total-1,i+Shift));
      trend[i] = (i<rates_total-1) ? (close[i]>smax[i+1]) ? 1 : (close[i]<smin[i+1]) ? -1 : trend[i+1] : 0;
      if (i<rates_total-1)
      {
          if (trend[i]==-1 && smax[i]>smax[i+1]) smax[i] = smax[i+1];
          if (trend[i]== 1 && smin[i]<smin[i+1]) smin[i] = smin[i+1];
      }                  
      upLine[i] = (trend[i] == 1) ? smin[i] : EMPTY_VALUE;
      dnLine[i] = (trend[i] ==-1) ? smax[i] : EMPTY_VALUE;
   }       
return(rates_total);
}

//
//
//
//
//

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("");
}

