//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "www.forex-tsd.com"
#property link      "www.forex-tsd.com"

#property indicator_chart_window
#property indicator_buffers 6
#property indicator_color1  clrDimGray
#property indicator_color2  clrDimGray
#property indicator_color3  clrDarkGray
#property indicator_color4  clrDeepSkyBlue
#property indicator_color5  clrSandyBrown
#property indicator_color6  clrSandyBrown
#property indicator_width3  2
#property indicator_width4  2
#property indicator_width5  2
#property indicator_width6  2
#property indicator_style1  STYLE_DOT
#property indicator_style2  STYLE_DOT

//
//
//
//
//

extern int                EmaPeriod        = 22;
extern int                FastEmaPeriod    = 13;
extern ENUM_APPLIED_PRICE Price            = PRICE_CLOSE;
extern double             DeviationsFactor = 2.7;
extern int                DeviationsPeriod = 100;
extern bool               alertsOn         = false;    // Turn alerts on
extern bool               alertsOnCurrent  = true;     // Alerts on currnt (still opened) bar
extern bool               alertsMessage    = true;     // Aleert 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

//
//
//
//
//

double slowEma[];
double slowEmada[];
double slowEmadb[];
double fastEma[];
double envelopeUp[];
double envelopeDn[];
double trend[];

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

int init()
{
   IndicatorBuffers(7);
   SetIndexBuffer(0,envelopeUp);
   SetIndexBuffer(1,envelopeDn);
   SetIndexBuffer(2,fastEma);
   SetIndexBuffer(3,slowEma);
   SetIndexBuffer(4,slowEmada);
   SetIndexBuffer(5,slowEmadb);
   SetIndexBuffer(6,trend);

      IndicatorShortName("Elder auto envelope");
   return(0);
}
int deinit() { return(0); }

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

double work[][2];
#define _percp 0
#define _devs  1

//
//
//
//
//

int start()
{
   int counted_bars=IndicatorCounted();
   int period = MathMax(PERIOD_W1,Period());
      if(counted_bars<0) return(-1);
      if(counted_bars>0) counted_bars--;
           int k,limit=MathMin(Bars-counted_bars,Bars-1);

   //
   //
   //
   //
   //

   if (ArrayRange(work,0) != Bars) ArrayResize(work,Bars);
   if (trend[limit]==-1) CleanPoint(limit,slowEmada,slowEmadb);
   for(int i=limit, r=Bars-i-1; i>=0; i--,r++)
   {
      double ema   = iMA(NULL,0,EmaPeriod,0,MODE_EMA,Price,i); 
      double bullp = MathAbs(High[i]-ema);
      double bearp = MathAbs(Low[i] -ema);
      double maxp  = MathMax(bullp,bearp);
      work[r][_percp] = maxp/ema;
      work[r][_devs]  = work[r-1][_devs];
         
         //
         //
         //
         //
         //

            if (iBarShift(NULL,period,Time[i])!= iBarShift(NULL,period,Time[i+1]))
            {
               double avg = 0;
               double sum = 0;
               for (k=0; k<DeviationsPeriod && (r-k-1)>=0; k++) avg += work[r-k-1][_percp];
                                                                avg /= DeviationsPeriod;
               for (k=0; k<DeviationsPeriod && (r-k-1)>=0; k++) sum += (work[r-k-1][_percp]-avg)*(work[r-k-1][_percp]-avg);
            
               //
               //
               //
               //
               //
               
               work[r][_devs] = MathSqrt(sum/DeviationsPeriod);
            }
    
         //
         //
         //
         //
         //
      
         slowEma[i]    = ema;
         envelopeUp[i] = ema*(1+(DeviationsFactor*work[r][_devs]));
         envelopeDn[i] = ema*(1-(DeviationsFactor*work[r][_devs]));
            if (FastEmaPeriod>0)
            {
               fastEma[i]   = iMA(NULL,0,FastEmaPeriod,0,MODE_EMA,Price,i); 
               slowEmada[i] = EMPTY_VALUE;
               slowEmadb[i] = EMPTY_VALUE;
               trend[i]     = trend[i+1];
               if (fastEma[i]>slowEma[i]) trend[i] =  1;
               if (fastEma[i]<slowEma[i]) trend[i] = -1;
               if (trend[i]==-1) PlotPoint(i,slowEmada,slowEmadb,slowEma);
            }               
   }
   manageAlerts();
   return(0);         
}

//-------------------------------------------------------------------
//                                                                  
//-------------------------------------------------------------------
//
//
//
//
//

void manageAlerts()
{
   if (alertsOn)
   {
      int whichBar = 1; if (alertsOnCurrent) whichBar = 0;
      if (trend[whichBar] != trend[whichBar+1])
      {
         if (trend[whichBar] ==  1) doAlert(whichBar,"up");
         if (trend[whichBar] == -1) doAlert(whichBar,"down");
      }
   }
}

//
//
//
//
//

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 =  Symbol()+" at "+TimeToStr(TimeLocal(),TIME_SECONDS)+" Elders auto envelope trend changed to "+doWhat;
          if (alertsMessage)   Alert(message);
          if (alertsEmail)     SendMail(Symbol()+" Elders auto envelope",message);
          if (alertsPushNotif) SendNotification(message);
          if (alertsSound)     PlaySound("alert2.wav");
   }
}

//-------------------------------------------------------------------
//                                                                  
//-------------------------------------------------------------------
//
//
//
//
//

void CleanPoint(int i,double& first[],double& second[])
{
   if (i>=Bars-3) return;
   if ((second[i]  != EMPTY_VALUE) && (second[i+1] != EMPTY_VALUE))
        second[i+1] = EMPTY_VALUE;
   else
      if ((first[i] != EMPTY_VALUE) && (first[i+1] != EMPTY_VALUE) && (first[i+2] == EMPTY_VALUE))
          first[i+1] = EMPTY_VALUE;
}

void PlotPoint(int i,double& first[],double& second[],double& from[])
{
   if (i>=Bars-2) return;
   if (first[i+1] == EMPTY_VALUE)
      if (first[i+2] == EMPTY_VALUE) 
            { first[i]  = from[i];  first[i+1]  = from[i+1]; second[i] = EMPTY_VALUE; }
      else  { second[i] =  from[i]; second[i+1] = from[i+1]; first[i]  = EMPTY_VALUE; }
   else     { first[i]  = from[i];                           second[i] = EMPTY_VALUE; }
}