//+------------------------------------------------------------------+
//|                                    elliot oscillator - waves.mq4 |
//+------------------------------------------------------------------+
#property copyright "mladen"
#property link      "www.forex-tsd.com"

#property indicator_separate_window
#property indicator_buffers 6
#property indicator_color1  clrDeepSkyBlue
#property indicator_color2  clrPaleVioletRed
#property indicator_color3  clrGold
#property indicator_color4  clrGold
#property indicator_color5  clrDimGray
#property indicator_color6  clrDimGray
#property indicator_width1  2
#property indicator_width2  2
#property indicator_width3  2
#property indicator_width4  2
#property indicator_width5  2
#property indicator_width6  2
#property strict

//
//
//
//
//

extern int             shortPeriod      =  5;                // Short period
extern int             longPeriod       = 35;                // Long period 
extern ENUM_APPLIED_PRICE Price         = PRICE_MEDIAN;      // Price (original should be median)
extern ENUM_MA_METHOD  MaMethod         = MODE_SMA;          // Average method to use (original should be SMA)
extern string          linesIdentifier  = "elliotWaveLines"; // Unique ID for the indicator
extern color           linesColor       = clrBlack;          // Zigzag lines color
extern ENUM_LINE_STYLE linesStyle       = STYLE_DOT;         // Zigzag lines style
extern bool            alertsOn         = false;             // Turn alerts on?
extern bool            alertsOnCurrent  = true;              // Alerts on still opened bar?
extern bool            alertsMessage    = true;              // Alerts should display a message?
extern bool            alertsSound      = false;             // Alerts should play alert sound?
extern bool            alertsEmail      = false;             // Alerts should send email?
extern bool            alertsPush       = false;             // Alerts should send notification?

//
//
//
//
//

double ellBuffer[];
double ellUBuffer[];
double ellDBuffer[];
double mauBuffer[];
double madBuffer[];
double peakUp[];
double peakDn[];
double trend[];

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

int init()
{
   IndicatorBuffers(8);
   SetIndexBuffer(0,ellUBuffer); SetIndexStyle(0,DRAW_HISTOGRAM);
   SetIndexBuffer(1,ellDBuffer); SetIndexStyle(1,DRAW_HISTOGRAM);
   SetIndexBuffer(2,peakUp);     SetIndexStyle(2,DRAW_HISTOGRAM);
   SetIndexBuffer(3,peakDn);     SetIndexStyle(3,DRAW_HISTOGRAM);
   SetIndexBuffer(4,mauBuffer);
   SetIndexBuffer(5,madBuffer);
   SetIndexBuffer(6,trend);
   SetIndexBuffer(7,ellBuffer); 
   IndicatorShortName("Elliot oscillator ( "+(string)shortPeriod+","+(string)longPeriod+")");
   return(0);
}
int deinit()
{
   string lookFor = linesIdentifier+":";
   for (int i=ObjectsTotal(); i>=0; i--)
      {
         string name = ObjectName(i);
         if (StringFind(name,lookFor)==0) ObjectDelete(name);
      }
   return(0); 
}

//
//
//
//
//

int start()
{
   double alpha     = 2.0/(1.0+longPeriod+MathCeil(shortPeriod/2.0));
   int counted_bars = IndicatorCounted();
      if(counted_bars < 0) return(-1);
      if(counted_bars > 0) counted_bars--;
           int limit = MathMin(Bars-counted_bars,Bars-longPeriod);
        
   //
   //
   //
   //
   //

      int      count         = 0;
      int      direction     = 0;   
      int      startFrom     = 0;
      double   lastPeakPrice = 0;
      datetime lastPeakTime  = 0;
           for (;limit<(Bars-longPeriod); limit++)
               {
                  if (peakDn[limit]!=EMPTY_VALUE) { if (count==0) { count ++; continue; } direction=-1; startFrom = limit; break; }
                  if (peakUp[limit]!=EMPTY_VALUE) { if (count==0) { count ++; continue; } direction= 1; startFrom = limit; break; }
               }

   //
   //
   //
   //
   //
   
   for(int i = limit; i >= 0; i--)
   {
      ellBuffer[i]  = iMA(NULL,0,shortPeriod,0,MaMethod,Price,i)-iMA(NULL,0,longPeriod,0,MaMethod,Price,i);
      ellUBuffer[i] = EMPTY_VALUE;
      ellDBuffer[i] = EMPTY_VALUE;

         if (mauBuffer[i+1]==EMPTY_VALUE) if (ellBuffer[i]>0) mauBuffer[i+1] = ellBuffer[i]; else  mauBuffer[i+1] = 0;
         if (madBuffer[i+1]==EMPTY_VALUE) if (ellBuffer[i]<0) madBuffer[i+1] = ellBuffer[i]; else  madBuffer[i+1] = 0;
            
      madBuffer[i] = madBuffer[i+1];
      mauBuffer[i] = mauBuffer[i+1];
      trend[i]     = trend[i+1];
      peakUp[i]    = EMPTY_VALUE;
      peakDn[i]    = EMPTY_VALUE;
         
      //
      //
      //
      //
      //
         
      if (ellBuffer[i] < 0) { madBuffer[i] = madBuffer[i+1]+alpha*(ellBuffer[i]-madBuffer[i+1]); ellDBuffer[i] = ellBuffer[i]; }
      if (ellBuffer[i] > 0) { mauBuffer[i] = mauBuffer[i+1]+alpha*(ellBuffer[i]-mauBuffer[i+1]); ellUBuffer[i] = ellBuffer[i]; }
         
         
         //
         //
         //
         //
         //
         
         ObjectDelete(linesIdentifier+":"+(string)Time[i]);
         if (ellBuffer[i] > 0 && ellBuffer[i]>mauBuffer[i])
         {
            if (direction < 0) { markLow(i,startFrom,lastPeakPrice,lastPeakTime); startFrom = i; }
                direction = 1; trend[i] = 1;
         }
         if (ellBuffer[i] < 0 && ellBuffer[i]<madBuffer[i])
         {
            if (direction > 0) { markHigh(i,startFrom,lastPeakPrice,lastPeakTime); startFrom = i; }
                direction = -1;  trend[i] = -1;
         }
   }
   if (direction > 0) markHigh(0,startFrom,lastPeakPrice,lastPeakTime); 
   if (direction < 0) markLow (0,startFrom,lastPeakPrice,lastPeakTime); 
   if (alertsOn)
   {
      int whichBar = 1; if (alertsOnCurrent) whichBar = 0;
      if (trend[whichBar] != trend[whichBar+1])
      {
         if (trend[whichBar] == 1) doAlert(whichBar,DoubleToStr(mauBuffer[whichBar],5)+" crossed up");
         if (trend[whichBar] ==-1) doAlert(whichBar,DoubleToStr(madBuffer[whichBar],5)+" crossed down");
      }         
   }      
   return(0);      
}

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

void markLow(int tstart, int end, double& lastPeakPrice, datetime& lastPeakTime)
{
   while (ellBuffer[tstart+1]>0 && tstart<Bars) tstart++;
   while (ellBuffer[end+1]   <0 && end   <Bars) end++;
   int peakAt = ArrayMinimum(Low,end-tstart+1,tstart); peakDn[peakAt] = ellBuffer[peakAt];
   
   //
   //
   //
   //
   //
   
   if (lastPeakPrice!=0) drawLine(lastPeakPrice,lastPeakTime,Low[peakAt],Time[peakAt]);
       lastPeakPrice = Low[peakAt];
       lastPeakTime  = Time[peakAt];
}
void markHigh(int tstart, int end, double& lastPeakPrice, datetime& lastPeakTime)
{
   while (ellBuffer[tstart+1]<0 && tstart<Bars) tstart++;
   while (ellBuffer[end+1]   >0 && end   <Bars) end++;
   int peakAt = ArrayMaximum(High,end-tstart+1,tstart); peakUp[peakAt] = ellBuffer[peakAt];
   
   //
   //
   //
   //
   //
   
   if (lastPeakPrice!=0) drawLine(lastPeakPrice,lastPeakTime,High[peakAt],Time[peakAt]);
       lastPeakPrice = High[peakAt];
       lastPeakTime  = Time[peakAt];
}

//
//
//
//
//

void drawLine(double startPrice, datetime startTime, double endPrice, datetime endTime)
{
   string name = linesIdentifier+":"+(string)startTime;
      ObjectCreate(name,OBJ_TREND,0,startTime,startPrice,endTime,endPrice);
         ObjectSet(name,OBJPROP_STYLE,linesStyle);
         ObjectSet(name,OBJPROP_COLOR,linesColor);
         ObjectSet(name,OBJPROP_RAY,false);
}

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

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()," at ",TimeToStr(TimeLocal(),TIME_SECONDS)," Elliot oscillator level ",doWhat);
          if (alertsMessage) Alert(message);
          if (alertsEmail)   SendMail(StringConcatenate(Symbol(),"Elliot oscillator "),message);
          if (alertsPush)    SendNotification(message);
          if (alertsSound)   PlaySound("alert2.wav");
   }
}