//------------------------------------------------------------------
#property copyright "Copyright 2016, mladen - MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
//------------------------------------------------------------------
#property indicator_chart_window
#property indicator_buffers 7
#property indicator_color1  C'214,248,214'
#property indicator_color2  C'255,236,213'
#property indicator_width1  10
#property indicator_width2  10
#property strict

//
//
//
//
//

enum enDisplay
{
   en_lin,  // Display channel
   en_his,  // Display fill
   en_all,  // Display channel and fill
   en_lid,  // Display channel with dots
   en_hid,  // Display fill with dots
   en_ald,  // Display channel and fill with dots
   en_dot   // Display dots
};
enum enCalcType
{
   st_atr, // Use atr
   st_std, // Use standard deviation 
   st_ste, // Use standard error
   st_sam, // Custom strandard deviation - with sample correction
   st_nos  // Custom strandard deviation - without sample correction
   
};

extern int             period                = 10;               // Super trend period
extern double          multiplier            = 2.0;              // Super trend multiplier
extern int             midPricePeriod        = 21;               // Mid price period (1 for original super trend)
extern enCalcType      Type                  = st_sam;           // Calculate using?
extern enDisplay       DisplayType           = en_ald;           // Display type
extern int             LinesWidth            = 2;                // Channel Lines width (when lines are included in display)
extern color           UpChannelColor        = clrGreen;         // Upper channel color
extern color           MdChannelColor        = clrDarkSlateGray; // Middle channel line color
extern color           DnChannelColor        = clrOrange;        // Lower channel color
extern bool            alertsOn              = false;            // Turn alerts on
extern bool            alertsOnCurrent       = true;             // Alerts on current (still opened) bar
extern bool            alertsMessage         = true;             // Alerts should show pop-up message
extern bool            alertsSound           = false;            // Alerts should play alert sound
extern bool            alertsPushNotif       = false;            // Alerts should send push notification
extern bool            alertsEmail           = false;            // Alerts should send email
extern int             UpArrowSize           = 2;                // Up Arrow size
extern int             DnArrowSize           = 2;                // Down Arrow size
extern int             UpArrowCode           = 159;              // Up Arrow code
extern int             DnArrowCode           = 159;              // Down arrow code
extern double          UpArrowGap            = 0.5;              // Up Arrow gap        
extern double          DnArrowGap            = 0.5;              // Dn Arrow gap
extern color           UpArrowColor          = clrLimeGreen;     // Up Arrow Color
extern color           DnArrowColor          = clrOrange;        // Down Arrow Color
extern bool            verticalLinesVisible  = false;            // Show vertical lines
extern string          verticalLinesID       = "st Lines";       // Vertical lines ID
extern color           verticalLinesUpColor  = clrDeepSkyBlue;   // Vertical lines up color 
extern color           verticalLinesDnColor  = clrPaleVioletRed; // Vertical lines down color
extern ENUM_LINE_STYLE verticalLinesStyle    = STYLE_DOT;        // Vertical lines style
extern int             verticalLinesWidth    = 0;                // lines width




double Up[],Dn[],md[],upFill[],dnFill[],trendu[],trendd[],Direction[],arrowu[],arrowd[];

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

int init()
{
   IndicatorBuffers(10);
   int lstyle = DRAW_LINE;      if (DisplayType==en_his || DisplayType==en_hid || DisplayType==en_dot) lstyle = DRAW_NONE;
   int hstyle = DRAW_HISTOGRAM; if (DisplayType==en_lin || DisplayType==en_lid || DisplayType==en_dot) hstyle = DRAW_NONE;
   int astyle = DRAW_ARROW;     if (DisplayType<en_lid)                                                astyle = DRAW_NONE;
   SetIndexBuffer(0, upFill);   SetIndexStyle(0, hstyle);
   SetIndexBuffer(1, dnFill);   SetIndexStyle(1, hstyle); 
   SetIndexBuffer(2, md);       SetIndexStyle(2, lstyle,EMPTY,LinesWidth,MdChannelColor); 
   SetIndexBuffer(3, trendu);   SetIndexStyle(3, lstyle,EMPTY,LinesWidth,UpChannelColor); 
   SetIndexBuffer(4, trendd);   SetIndexStyle(4, lstyle,EMPTY,LinesWidth,DnChannelColor); 
   SetIndexBuffer(5, arrowu);   SetIndexStyle(5, astyle,0,UpArrowSize,UpArrowColor); SetIndexArrow(5,UpArrowCode);
   SetIndexBuffer(6, arrowd);   SetIndexStyle(6, astyle,0,DnArrowSize,DnArrowColor); SetIndexArrow(6,DnArrowCode);
   SetIndexBuffer(7, Up);
   SetIndexBuffer(8, Dn);     
   SetIndexBuffer(9, Direction); 
   IndicatorShortName("SuperTrend channel");
return(0);
}
int deinit() 
{ 
   string tlookFor       = verticalLinesID+":";
   int    tlookForLength = StringLen(tlookFor);
   for (int i=ObjectsTotal()-1; i>=0; i--)
   {
      string objectName = ObjectName(i);
         if (StringSubstr(objectName,0,tlookForLength) == tlookFor) ObjectDelete(objectName);
   }
return(0); 
}  

//
//
//
//
//

int start()
{
   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); 

   //
   //
   //
   //
   //

   for(i=limit; i >= 0; i--)
   {
      double val=0;
         switch (Type)
         {
            case st_atr : val = iATR(NULL,0,period,i);                           break;
            case st_std : val = iStdDev(NULL,0,period,0,MODE_SMA,PRICE_CLOSE,i); break;
            case st_ste : val = iStdError(Close[i],period,i);                    break;
            default :     val = iDeviation(Close[i],period,Type==st_sam,i);
         }            
      double cprice = Close[i];
      double mprice = (High[ArrayMaximum(High,midPricePeriod,i)]+Low[ArrayMinimum(Low,midPricePeriod,i)])*0.5;
             Up[i]  = mprice+multiplier*val;
             Dn[i]  = mprice-multiplier*val;
             md[i]  = (Up[i]+Dn[i])*0.5;
             arrowu[i] = EMPTY_VALUE;
             arrowd[i] = EMPTY_VALUE;
             
             //
             //
             //
             //
             //
         
             Direction[i] = (i<Bars-1) ? (cprice > Up[i+1]) ? 1 : (cprice < Dn[i+1]) ? -1 : Direction[i+1] : 0;
             if (Direction[i] ==  1) 
             { 
                Dn[i]     = fmax(Dn[i],Dn[i+1]); 
                Up[i]     = fmax(Up[i],Up[i+1]);
                trendu[i] = Up[i];
                trendd[i] = Dn[i];
             }
             if (Direction[i] == -1) 
             { 
                 Up[i]     = fmin(Up[i],Up[i+1]); 
                 Dn[i]     = fmin(Dn[i],Dn[i+1]); 
                 trendd[i] = Up[i];
                 trendu[i] = Dn[i];
                 
             }
             upFill[i] = trendu[i]; 
             dnFill[i] = trendd[i];
             
             //
             //
             //
             //
             //
             
             if (i<Bars-1 && Direction[i] != Direction[i+1])
             {
               if (Direction[i] ==  1) arrowu[i] = fmin(trendu[i],Low[i] )-iATR(NULL,0,15,i)*UpArrowGap;
               if (Direction[i] == -1) arrowd[i] = fmax(trendd[i],High[i])+iATR(NULL,0,15,i)*DnArrowGap;
             } 
             
             //
             //
             //
             //
             //
         
             if (verticalLinesVisible)
             {
                string tlookFor = verticalLinesID+":"+(string)Time[i]; ObjectDelete(tlookFor);  
                if (i<Bars-1 && Direction[i] != Direction[i+1])
                {
                  if (Direction[i] == 1) drawLine(i,verticalLinesUpColor);
                  if (Direction[i] ==-1) drawLine(i,verticalLinesDnColor);
           
                }
             }             
   }
   
   //
   //
   //
   //
   //
   
   if (alertsOn)
   {
      int whichBar = 1; if (alertsOnCurrent) whichBar = 0;
      if (Direction[whichBar] != Direction[whichBar+1])
      if (Direction[whichBar] == 1)
            doAlert("up");
      else  doAlert("down");       
   }  
return(0);
}

//------------------------------------------------------------------
//                                                                  
//------------------------------------------------------------------
// 
//
//
//
//

#define _devInstances 1
double workDev[][_devInstances];
double iDeviation(double value, int length, bool isSample, int i, int instanceNo=0)
{
   if (ArrayRange(workDev,0)!=Bars) ArrayResize(workDev,Bars); i=Bars-i-1; workDev[i][instanceNo] = 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][instanceNo]-oldMean)/(k+1)+oldMean;
         squares += (workDev[i-k][instanceNo]-oldMean)*(workDev[i-k][instanceNo]-newMean);
         oldMean  = newMean;
      }
      return(MathSqrt(squares/fmax(k-isSample,1)));
}

//
//
//
//
//

double workErr[][_devInstances];
double iStdError(double value, int length,int i, int instanceNo=0)
{
   if (ArrayRange(workErr,0)!=Bars) ArrayResize(workErr,Bars); i = Bars-i-1; workErr[i][instanceNo] = value;
                        
      //
      //
      //
      //
      //
                              
      double avgY     = workErr[i][instanceNo]; int j; for (j=1; j<length && (i-j)>=0; j++) avgY += workErr[i-j][instanceNo]; avgY /= j;
      double avgX     = length * (length-1) * 0.5 / length;
      double sumDxSqr = 0.00;
      double sumDySqr = 0.00;
      double sumDxDy  = 0.00;
   
      for (int k=0; k<length && (i-k)>=0; k++)
      {
         double dx = k-avgX;
         double dy = workErr[i-k][instanceNo]-avgY;
            sumDxSqr += (dx*dx);
            sumDySqr += (dy*dy);
            sumDxDy  += (dx*dy);
      }
      double err2 = (sumDySqr-(sumDxDy*sumDxDy)/sumDxSqr)/(length-2); 
      
   //
   //
   //
   //
   //
         
   if (err2 > 0)
         return(MathSqrt(err2));
   else  return(0.00);       
}

//------------------------------------------------------------------
//                                                                  
//------------------------------------------------------------------
//
//
//
//
//

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)," SuperTrend Channel ",doWhat);
             if (alertsMessage)   Alert(message);
             if (alertsPushNotif) SendNotification(message);
             if (alertsEmail)     SendMail(StringConcatenate(Symbol()," SuperTrend Channel "),message);
             if (alertsSound)     PlaySound("alert2.wav");
      }
}

//
//
//
//
//

void drawLine(int i,color theColor)
{
      string name = verticalLinesID+":"+(string)Time[i];
   
      //
      //
      //
      //
      //
         
      datetime time = Time[i]; //if (linesOnNewest) time += _Period*60-1;    
      ObjectCreate(name,OBJ_VLINE,0,time,0);
         ObjectSet(name,OBJPROP_COLOR,theColor);
         ObjectSet(name,OBJPROP_STYLE,verticalLinesStyle);
         ObjectSet(name,OBJPROP_WIDTH,verticalLinesWidth);
         ObjectSet(name,OBJPROP_BACK,true);
}





