//------------------------------------------------------------------
#property copyright   "mladen"
#property link        "www.forex-tsd.com"
#property version     "1.00"
//------------------------------------------------------------------
#property indicator_chart_window
#property indicator_buffers 6
#property indicator_plots   3
#property indicator_label1  "st zone"
#property indicator_type1   DRAW_FILLING
#property indicator_color1  clrGainsboro,clrGainsboro
#property indicator_label2  "sd middle"
#property indicator_type2   DRAW_LINE
#property indicator_style2  STYLE_DOT
#property indicator_color2  clrGray
#property indicator_label3  "Super trend"
#property indicator_type3   DRAW_COLOR_LINE
#property indicator_color3  clrDimGray,clrLimeGreen,clrOrange
#property indicator_width3  2

//
//
//
//
//

enum enCalcType
{
   st_atr, // Use atr
   st_ste, // Use standard error
   st_sam, // Custom strandard deviation - with sample correction
   st_nos  // Custom strandard deviation - without sample correction
};

input int        period          = 66;          // Super trend period
input double     multiplier      = 2.236;       // Super trend multiplier
input int        midPricePeriod  = 10;          // Mid price period (1 for original super trend)
input enCalcType Type            = st_atr;      // Calculate using?
input bool       alertsOn        = false;       // Turn alerts on?
input bool       alertsOnCurrent = true;        // Alert on current bar?
input bool       alertsMessage   = true;        // Display messageas on alerts?
input bool       alertsSound     = false;       // Play sound on alerts?
input bool       alertsEmail     = false;       // Send email on alerts?
input bool       alertsNotify    = false;       // Send push notification on alerts?

double sup[],supc[],mid[],fup[],fdn[],trend[];

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

int OnInit()
{
   SetIndexBuffer(0,fup,INDICATOR_DATA);
   SetIndexBuffer(1,fdn,INDICATOR_DATA);
   SetIndexBuffer(2,mid,INDICATOR_DATA);
   SetIndexBuffer(3,sup,INDICATOR_DATA);
   SetIndexBuffer(4,supc,INDICATOR_COLOR_INDEX);
   SetIndexBuffer(5,trend,INDICATOR_CALCULATIONS);
   IndicatorSetString(INDICATOR_SHORTNAME,"SuperTrend (experiment) ("+(string)period+","+(string)multiplier+","+(string)midPricePeriod+")");
   return(0);
}

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

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[])
{ 
   if (Bars(_Symbol,_Period)<rates_total) return(-1);
   
   //
   //
   //
   //
   //

   for (int i=(int)MathMax(prev_calculated-1,0); i<rates_total && !IsStopped(); i++)
   {
      double val=0;
         switch (Type)
         {
            case st_atr : for (int k=0; k<period && (i-k)>0; k++) val += MathMax(high[i-k],close[i-k-1])-MathMin(low[i-k],close[i-k-1]); val/=period;  break;
            case st_ste : val = iStdError(close[i],period,i,rates_total);                                                                              break;
            default :     val = iDeviation(close[i],period,Type==st_sam,i,rates_total);
         }            
      double cprice = close[i];
      double hprice = high[i];
      double lprice = low[i];
         for (int k=1; k<midPricePeriod && (i-k)>=0; k++) { hprice = MathMax(hprice,high[i-k]); lprice = MathMin(lprice,low[i-k]); }
      double mprice   = (hprice+lprice)/2.0; 
             fup[i]   = mprice+multiplier*val;
             fdn[i]   = mprice-multiplier*val;
             mid[i]   = (fup[i]+fdn[i])/2.0;
             trend[i] = (i>0) ? (cprice > fup[i-1]) ? 1 : (cprice < fdn[i-1]) ? -1 : trend[i-1] : 0;
                  if (trend[i] ==  1) { fdn[i] = MathMax(fdn[i],fdn[i-1]); fup[i] = MathMax(fup[i],fup[i-1]); sup[i] = fdn[i]; }
                  if (trend[i] == -1) { fup[i] = MathMin(fup[i],fup[i-1]); fdn[i] = MathMin(fdn[i],fdn[i-1]); sup[i] = fup[i]; }
             supc[i] = (trend[i]==1) ? 1 : (trend[i]==-1) ? 2 : 0;
   }
   manageAlerts(time,supc,rates_total);
   return(rates_total);
}



//------------------------------------------------------------------
//                                                                  
//------------------------------------------------------------------
// 
//
//
//
//

#define _devInstances 1
double workDev[][_devInstances];
double iDeviation(double value, int length, bool isSample, int i, int bars, int instanceNo=0)
{
   if (ArrayRange(workDev,0)!=bars) ArrayResize(workDev,bars); 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/MathMax(k-isSample,1)));
}

//
//
//
//
//

double workErr[][_devInstances];
double iStdError(double value, int length,int i, int bars, int instanceNo=0)
{
   if (ArrayRange(workErr,0)!=bars) ArrayResize(workErr,bars); 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 manageAlerts(const datetime& time[], double& ttrend[], int bars)
{
   if (alertsOn)
   {
      int whichBar = bars-1; if (!alertsOnCurrent) whichBar = bars-2; datetime time1 = time[whichBar];
      if (ttrend[whichBar] != ttrend[whichBar-1])
      {
         if (ttrend[whichBar] == 1) doAlert(time1,"up");
         if (ttrend[whichBar] == 2) doAlert(time1,"down");
      }         
   }
}   

//
//
//
//
//

void doAlert(datetime forTime, string doWhat)
{
   static string   previousAlert="nothing";
   static datetime previousTime;
   string message;
   
   if (previousAlert != doWhat || previousTime != forTime) 
   {
      previousAlert  = doWhat;
      previousTime   = forTime;

      //
      //
      //
      //
      //

      message = TimeToString(TimeLocal(),TIME_SECONDS)+" "+_Symbol+" super trend state changed to "+doWhat;
         if (alertsMessage) Alert(message);
         if (alertsEmail)   SendMail(_Symbol+" super trend",message);
         if (alertsNotify)  SendNotification(message);
         if (alertsSound)   PlaySound("alert2.wav");
   }
}