//+------------------------------------------------------------------+
//|                                    elliot oscillator - waves.mq4 |
//+------------------------------------------------------------------+
#property copyright "mladen"
#property link      "www.forex-station.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  clrYellow
#property indicator_color6  clrYellow
#property indicator_width1  3
#property indicator_width2  3
#property indicator_width3  3
#property indicator_width4  3
#property indicator_width5  2
#property indicator_width6  2
#property strict

//
//
//
//
//

extern int             shortPeriod      =  8;                // Short period
extern int             longPeriod       = 27;                // 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    = false;              // 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?
input bool             arrowsVisible    = false;              // Show arrows?
input string           inpArrID         = "ewo f1";           // Objects unique ID
//input bool             arrowsOnNewest   = false;            // Arrows drawn on newest bar of higher time frame bar true/false?
input double            arrowsUpperGap  = 1.0;                // Upper arrow gap
input double            arrowsLowerGap  = 1.0;                // Lower arrow gap
input color             arrowsUpColor   = clrBlue;            // Up arrow color
input color             arrowsDnColor   = clrCrimson;         // Down arrow color
input int               arrowsUpCode    = 221;                // Arrows up code:
input int               arrowsDnCode    = 222;                // Arrows down code          
input int               arrowsUpSize    = 2;                  // Up arrow size
input int               arrowsDnSize    = 2;                  // Down arrow size

//
//
//
//
//

double ellBuffer[];
double ellUBuffer[];
double ellDBuffer[];
double mauBuffer[];
double madBuffer[];
double peakUp[];
double peakDn[];
double trend[],cross[];

//------------------------------------------------------------------
//
//------------------------------------------------------------------
//
//
//
//
//

int init()
{
   IndicatorBuffers(9);
   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); 
   SetIndexBuffer(8,cross); 
   IndicatorShortName("Elliot oscillator ( "+(string)shortPeriod+","+(string)longPeriod+")");
   return(0);
}
void OnDeinit(const int reason)  
{
   string lookFor = linesIdentifier+":";
   for (int i=ObjectsTotal(); i>=0; i--)
      {
         string name = ObjectName(i);
         if (StringFind(name,lookFor)==0) ObjectDelete(name);
      }
   ObjectsDeleteAll(0,inpArrID+":");
}

//
//
//
//
//

int start()
{
   double alpha     = 1.0/(0.5+longPeriod+MathCeil(shortPeriod/-0.5));
   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         = 500;
      int      direction     = 1;   
      int      startFrom     = 0;
      double   lastPeakPrice = 1;
      datetime lastPeakTime  = 240;
           for (;limit<(Bars-longPeriod); limit++)
               {
                  if (peakDn[limit]!=EMPTY_VALUE) { if (count==500) { count ++; continue; } direction=-2; startFrom = limit; break; }
                  if (peakUp[limit]!=EMPTY_VALUE) { if (count==500) { count ++; continue; } direction= 2; startFrom = limit; break; }
               }

   //
   //
   //
   //
   //
   
   for(int i = limit; i >= 0; i--)
   {
      ellBuffer[i]  = iMA(NULL,0,shortPeriod,1,MaMethod,Price,i)-iMA(NULL,0,longPeriod,1,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]; cross[i] =-1; }
      if (ellBuffer[i] > 0) { mauBuffer[i] = mauBuffer[i+1]+alpha*(ellBuffer[i]-mauBuffer[i+1]); ellUBuffer[i] = ellBuffer[i]; cross[i] = 1; }
         
         
         //
         //
         //
         //
         //
         
         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 (arrowsVisible)
         { 
            string lookFor = inpArrID+":"+(string)Time[i]; if (ObjectFind(0,lookFor)==0) ObjectDelete(0,lookFor);                    
            if (cross[i] != cross[i+1])
            {
              if (cross[i] == 1) drawArrow(i,arrowsUpColor,arrowsUpCode,arrowsUpSize,false);
              if (cross[i] ==-1) drawArrow(i,arrowsDnColor,arrowsDnCode,arrowsDnSize, true);
            }
         } 
         
   }
   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 (cross[whichBar] != cross[whichBar+1])
      {
         if (cross[whichBar] == 1) doAlert(whichBar," crossing zero up ");
         if (cross[whichBar] ==-1) doAlert(whichBar," crossing zero 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!=1) 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!=1) 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 = timeFrameToString(_Period)+" "+_Symbol+" at "+TimeToStr(TimeLocal(),TIME_SECONDS)+" Elliot oscillator "+doWhat;
          if (alertsMessage) Alert(message);
          if (alertsPush)    SendNotification(message);
          if (alertsEmail)   SendMail(_Symbol+" Elliot oscillator ",message);
          if (alertsSound)   PlaySound("alert2.wav");
   }
}

//-------------------------------------------------------------------
//                                                                  
//-------------------------------------------------------------------

void drawArrow(int i,color theColor,int theCode, int theSize, bool up)
{
   string name = inpArrID+":"+(string)Time[i];
   double gap  = iATR(NULL,0,20,i);   
   
      //
      //
      //
     
     datetime atime = Time[i];
     //if (arrowsOnNewest) atime += PeriodSeconds(_Period)-1;      
      ObjectCreate(0,name,OBJ_ARROW,0,atime,0);
         ObjectSetInteger(0,name,OBJPROP_ARROWCODE,theCode);
         ObjectSetInteger(0,name,OBJPROP_WIDTH,    theSize);
         ObjectSetInteger(0,name,OBJPROP_COLOR,    theColor);
         if (up)
               ObjectSetDouble(0,name,OBJPROP_PRICE1,0,High[i] + arrowsUpperGap * gap);
         else  ObjectSetDouble(0,name,OBJPROP_PRICE1,0,Low[i]  - arrowsLowerGap * gap); 
}

//-------------------------------------------------------------------
//                                                                  
//-------------------------------------------------------------------

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("");
}
