//+------------------------------------------------------------------+
//|                                     Empirical Mode Decomposition |
//|                                                                  |
//| John Ehlers and Ric Way, TASC March 2010                         |
//| www.forex-tsd.com elite section only                             |
//+------------------------------------------------------------------+
#property copyright "mladen"
#property link      "mladenfx@gmail.com"

#property indicator_separate_window
#property indicator_buffers 3
#property indicator_color1  DeepSkyBlue
#property indicator_color2  LimeGreen
#property indicator_color3  Red
#property indicator_width1  2

//
//
//
//
//

extern int    EmdPrice               = PRICE_MEDIAN;
extern int    EmdPeriod              = 20;
extern double EmdDelta               = 0.5;
extern double EmdFraction            = 0.1;
extern bool   DrawTrendExtractorOnly = false;

//
//
//
//
//

double emdBuffer[];
double peak[];
double valley[];
double fracPeak[];
double fracValley[];
double bp[];
double prices[];

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

#define Pi 3.14159265358979323846264338327950288419716939937

   double Beta;
   double Gamma;
   double Alpha;
   double HalfAlphaDiff;
   double BetaPlusAlpha;
   int    DoublePeriod;

//
//
//
//
//

int init()
{
   DoublePeriod = 2*EmdPeriod;   
   int drawBegin = MathMax(50,2*DoublePeriod);
      IndicatorBuffers(7);
         SetIndexBuffer(0,emdBuffer);  SetIndexDrawBegin(0,drawBegin);
         SetIndexBuffer(1,fracPeak);   SetIndexDrawBegin(1,drawBegin);
         SetIndexBuffer(2,fracValley); SetIndexDrawBegin(2,drawBegin);
         SetIndexBuffer(3,peak);
         SetIndexBuffer(4,valley);
         SetIndexBuffer(5,bp);
         SetIndexBuffer(6,prices);
   
      //
      //
      //
      //
      //

      Beta          = MathCos(2.0*Pi/EmdPeriod);
      Gamma         = 1.0 / MathCos(4.0*Pi*EmdDelta/EmdPeriod);
      Alpha         = Gamma - MathSqrt(Gamma*Gamma-1.0);
      HalfAlphaDiff = 0.5 * (1.0 - Alpha);
      BetaPlusAlpha = Beta * (1.0 + Alpha);

      //
      //
      //
      //
      //
   
      string PriceType;
      switch(EmdPrice)
      {
         case PRICE_CLOSE:    PriceType = "Close";    break;
         case PRICE_OPEN:     PriceType = "Open";     break;
         case PRICE_HIGH:     PriceType = "High";     break;
         case PRICE_LOW:      PriceType = "Low";      break;
         case PRICE_MEDIAN:   PriceType = "Median";   break;
         case PRICE_TYPICAL:  PriceType = "Typical";  break;
         case PRICE_WEIGHTED: PriceType = "Weighted"; break;
      }      
          
   //
   //
   //
   //
   //
             
   if (DrawTrendExtractorOnly) 
         IndicatorShortName("Extracting The Trend ("+PriceType+","+EmdPeriod+","+DoubleToStr(EmdDelta,3)+")");
   else  IndicatorShortName("Empirical Mode Decomposition ("+PriceType+","+EmdPeriod+","+DoubleToStr(EmdDelta,3)+","+DoubleToStr(EmdFraction,3)+")");
   return(0);
}
int deinit() { return(0); }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//
//
//
//
//

int start()
{
   int counted_bars=IndicatorCounted();
   int i,k,limit;

   if(counted_bars<0) return(-1);
   if(counted_bars>0) counted_bars--;
         limit = MathMin(Bars-counted_bars,Bars-1);

   //
   //
   //
   //
   //

   for(i=limit; i >= 0; i--)
   {
      prices[i] = iMA(NULL,0,1,0,MODE_SMA,EmdPrice,i);
      bp[i]     = HalfAlphaDiff*(prices[i]-prices[i+2]) + BetaPlusAlpha*bp[i+1] - Alpha*bp[i+2];

      //
      //
      //
      //
      //
               
         double average = bp[i];
         for (k=1; k<DoublePeriod; k++) average += bp[i+k];
                                        average /= DoublePeriod;
                         emdBuffer[i] = average;
         if (DrawTrendExtractorOnly) continue;
         
         //
         //
         //
         //
         //
         
         peak[i]      = peak[i+1];
         valley[i]    = valley[i+1];
            if (bp[i+1]>bp[i] && bp[i+1]>bp[i+2]) peak[i]   = bp[i+1];
            if (bp[i+1]<bp[i] && bp[i+1]<bp[i+2]) valley[i] = bp[i+1];
            
            double avgPeak   = peak[i];
            double avgValley = valley[i];
               for (k=1; k<50; k++)
               {
                  avgPeak   += peak[i+k];
                  avgValley += valley[i+k];
               }
            avgPeak   /= 50;
            avgValley /= 50;
            
         fracPeak[i]   = EmdFraction*avgPeak;
         fracValley[i] = EmdFraction*avgValley;
   }
   
   //
   //
   //
   //
   //
   
   return(0);
}