//+------------------------------------------------------------------+
//|                                   hilbert transform adaptive EMA |
//+------------------------------------------------------------------+
#property copyright "www.forex-tsd.com"
#property link      "www.forex-tsd.com"

#property indicator_separate_window
#property indicator_buffers 8
#property indicator_color1  clrPaleVioletRed
#property indicator_color2  clrPaleVioletRed
#property indicator_color3  clrDeepSkyBlue
#property indicator_color4  clrDeepSkyBlue
#property indicator_color5  clrDarkGray
#property indicator_color6  clrGreen
#property indicator_color7  clrRed
#property indicator_color8  clrDimGray
#property indicator_width1  1
#property indicator_width2  2
#property indicator_width3  1
#property indicator_width4  2
#property indicator_width5  2
#property indicator_style8  STYLE_DOT
#property indicator_level1  0

//
//
//
//
//

#import "dynamicZone.dll"
   double dzBuyP(double& sourceArray[],double probabiltyValue, int lookBack, int bars, int i, double precision);
   double dzSellP(double& sourceArray[],double probabiltyValue, int lookBack, int bars, int i, double precision);
#import

//
//
//
//
//

extern ENUM_TIMEFRAMES    TimeFrame              = PERIOD_CURRENT;
extern string             ForSymbol              = "";
extern ENUM_APPLIED_PRICE price                  = PRICE_MEDIAN;
extern double             filter                 = 1;
extern double             cyclesFast             = 0.5;
extern double             cyclesSlow             = 1.0;
extern bool               inverted               = false;
extern int                DzLookBackBars         = 35;
extern double             DzStartBuyProbability  = 0.90;
extern double             DzStartSellProbability = 0.90;
extern bool               Interpolate            = true;

//
//
//
//
//

double macd[];
double macdhUpa[];
double macdhUpb[];
double macdhDna[];
double macdhDnb[];
double buffer1[];
double buffer2[];
double buffer3[];
double emaFast[];
double emaSlow[];
double trend[];
string indicatorFileName;
bool   returnBars;


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

int init() 
{
   IndicatorBuffers(11);
      SetIndexBuffer(0, macdhDna); SetIndexStyle(0,DRAW_HISTOGRAM);
      SetIndexBuffer(1, macdhDnb); SetIndexStyle(1,DRAW_HISTOGRAM);
      SetIndexBuffer(2, macdhUpa); SetIndexStyle(2,DRAW_HISTOGRAM);
      SetIndexBuffer(3, macdhUpb); SetIndexStyle(3,DRAW_HISTOGRAM);
      SetIndexBuffer(4, macd);
      SetIndexBuffer(5, buffer1);
      SetIndexBuffer(6, buffer2);
      SetIndexBuffer(7, buffer3); 
      SetIndexBuffer(8, emaFast); 
      SetIndexBuffer(9, emaSlow); 
      SetIndexBuffer(10,trend); 
         indicatorFileName = WindowExpertName();
         returnBars        = TimeFrame==-99;
         TimeFrame         = MathMax(TimeFrame,_Period);
            if (ForSymbol=="") ForSymbol = Symbol();

   IndicatorShortName(timeFrameToString(TimeFrame)+" "+ForSymbol+" Phase accumilation MACD ("+DoubleToStr(cyclesFast,2)+","+DoubleToStr(cyclesSlow,2)+","+DoubleToStr(filter,2)+")");
   return (0);
}
int deinit(){return (0);}

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

int start()
{
   int i,limit,counted_bars=IndicatorCounted();

   if(counted_bars<0) return(-1);
   if(counted_bars>0) counted_bars--;
         limit = MathMin(Bars-counted_bars,Bars-1);
         if (returnBars) { macdhDna[0] = limit+1; return(0); }

   //
   //
   //
   //
   //
            
   if (ForSymbol == Symbol() && TimeFrame == Period())
   {
      for(i=limit; i>=0; i--)
      {
         double prc = iMA(NULL,0,1,0,MODE_SMA,price,i);
         if (i==Bars-1)
         {
            emaFast[i] = prc;
            emaSlow[i] = prc;
            continue;
         }

      //
      //
      //
      //
      //
      
      double alphaFast = 2.0/(1.0+iHilbertPhase(prc,filter,cyclesFast,i,0));
      double alphaSlow = 2.0/(1.0+iHilbertPhase(prc,filter,cyclesSlow,i,1));

         emaFast[i]  = emaFast[i+1]+alphaFast*(prc-emaFast[i+1]);
         emaSlow[i]  = emaSlow[i+1]+alphaSlow*(prc-emaSlow[i+1]);
         if (inverted)
               macd[i] = emaSlow[i]-emaFast[i];
         else  macd[i] = emaFast[i]-emaSlow[i];
         macdhDna[i] = EMPTY_VALUE;
         macdhDnb[i] = EMPTY_VALUE;
         macdhUpa[i] = EMPTY_VALUE;
         macdhUpb[i] = EMPTY_VALUE;
         
      //
      //
      //
      //
      //
               
            trend[i] = trend[i+1];
               if (macd[i]>macd[i+1]) trend[i] =  1;
               if (macd[i]<macd[i+1]) trend[i] = -1;
               if (macd[i]>0)
                  if (trend[i] == 1) 
                        macdhUpb[i] = macd[i];
                  else  macdhUpa[i] = macd[i];
               if (macd[i]<0)
                  if (trend[i] == -1) 
                        macdhDnb[i] = macd[i];
                  else  macdhDna[i] = macd[i];
                  
                  //
                  //
                  //
                  //
                  //
                  
                  if (DzStartBuyProbability >0) buffer1[i] = dzBuyP (macd, DzStartBuyProbability,  DzLookBackBars, Bars, i, 0.0001);
                  if (DzStartSellProbability>0) buffer2[i] = dzSellP(macd, DzStartSellProbability, DzLookBackBars, Bars, i, 0.0001);
                                                buffer3[i] = dzSellP(macd, 0.5                   , DzLookBackBars, Bars, i, 0.0001);
      }
      return (0);
   }
   
   //
   //
   //
   //
   //
   
   limit = MathMax(limit,MathMin(Bars-1,iCustom(ForSymbol,TimeFrame,indicatorFileName,-99,0,0)*TimeFrame/Period()));
   for (i=limit; i>=0; i--)
   {
      int y = iBarShift(ForSymbol,TimeFrame,Time[i]);
         macdhDna[i] = iCustom(ForSymbol,TimeFrame,indicatorFileName,PERIOD_CURRENT,"",price,filter,cyclesFast,cyclesSlow,inverted,DzLookBackBars,DzStartBuyProbability,DzStartSellProbability,0,y);
         macdhDnb[i] = iCustom(ForSymbol,TimeFrame,indicatorFileName,PERIOD_CURRENT,"",price,filter,cyclesFast,cyclesSlow,inverted,DzLookBackBars,DzStartBuyProbability,DzStartSellProbability,1,y);
         macdhUpa[i] = iCustom(ForSymbol,TimeFrame,indicatorFileName,PERIOD_CURRENT,"",price,filter,cyclesFast,cyclesSlow,inverted,DzLookBackBars,DzStartBuyProbability,DzStartSellProbability,2,y);
         macdhUpb[i] = iCustom(ForSymbol,TimeFrame,indicatorFileName,PERIOD_CURRENT,"",price,filter,cyclesFast,cyclesSlow,inverted,DzLookBackBars,DzStartBuyProbability,DzStartSellProbability,3,y);
         macd[i]     = iCustom(ForSymbol,TimeFrame,indicatorFileName,PERIOD_CURRENT,"",price,filter,cyclesFast,cyclesSlow,inverted,DzLookBackBars,DzStartBuyProbability,DzStartSellProbability,4,y);
         buffer1[i]  = iCustom(ForSymbol,TimeFrame,indicatorFileName,PERIOD_CURRENT,"",price,filter,cyclesFast,cyclesSlow,inverted,DzLookBackBars,DzStartBuyProbability,DzStartSellProbability,5,y);
         buffer2[i]  = iCustom(ForSymbol,TimeFrame,indicatorFileName,PERIOD_CURRENT,"",price,filter,cyclesFast,cyclesSlow,inverted,DzLookBackBars,DzStartBuyProbability,DzStartSellProbability,6,y);
         buffer3[i]  = iCustom(ForSymbol,TimeFrame,indicatorFileName,PERIOD_CURRENT,"",price,filter,cyclesFast,cyclesSlow,inverted,DzLookBackBars,DzStartBuyProbability,DzStartSellProbability,7,y);

         //
         //
         //
         //
         //
      
         if (!Interpolate || y==iBarShift(NULL,TimeFrame,Time[i-1])) continue;

         //
         //
         //
         //
         //

         datetime time = iTime(NULL,TimeFrame,y);
            for(int n = 1; i+n < Bars && Time[i+n] >= time; n++) continue;	
            for(int k = 1; k < n; k++)
            {
               macd[i+k]    = macd[i]    + (macd[i+n]    - macd[i])   *k/n;
               buffer1[i+k] = buffer1[i] + (buffer1[i+n] - buffer1[i])*k/n;
               buffer2[i+k] = buffer2[i] + (buffer2[i+n] - buffer2[i])*k/n;
               buffer3[i+k] = buffer3[i] + (buffer3[i+n] - buffer3[i])*k/n;
               if (macdhDna[i+k]!=EMPTY_VALUE) macdhDna[i+k]=macd[i+k];
               if (macdhDnb[i+k]!=EMPTY_VALUE) macdhDnb[i+k]=macd[i+k];
               if (macdhUpa[i+k]!=EMPTY_VALUE) macdhUpa[i+k]=macd[i+k];
               if (macdhUpb[i+k]!=EMPTY_VALUE) macdhUpb[i+k]=macd[i+k];
            }               
   }
   return(0);
         
}


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

double workHil[][18];
#define _price      0
#define _smooth     1
#define _detrender  2
#define _period     3
#define _instPeriod 4
#define _phase      5
#define _deltaPhase 6
#define _Q1         7
#define _I1         8

#define Pi 3.14159265358979323846264338327950288

//
//
//
//
//

double iHilbertPhase(double tprice, double tfilter, double cyclesToReach, int i, int s=0)
{
   if (ArrayRange(workHil,0)!=Bars) ArrayResize(workHil,Bars);
   int r = Bars-i-1; s = s*9;
      
   //
   //
   //
   //
   //
      
      workHil[r][s+_price]      = tprice;
      workHil[r][s+_smooth]     = (4.0*workHil[r][s+_price]+3.0*workHil[r-1][s+_price]+2.0*workHil[r-2][s+_price]+workHil[r-3][s+_price])/10.0;
      workHil[r][s+_detrender]  = calcComp(r,_smooth,s);
      workHil[r][s+_Q1]         = 0.15*calcComp(r,_detrender,s)  +0.85*workHil[r-1][s+_Q1];
      workHil[r][s+_I1]         = 0.15*workHil[r-3][s+_detrender]+0.85*workHil[r-1][s+_I1];
      workHil[r][s+_phase]      = workHil[r-1][s+_phase];
      workHil[r][s+_instPeriod] = workHil[r-1][s+_instPeriod];

      //
      //
      //
      //
      //
           
         if (MathAbs(workHil[r][s+_I1])>0)
                     workHil[r][s+_phase] = 180.0/Pi*MathArctan(MathAbs(workHil[r][s+_Q1]/workHil[r][s+_I1]));
           
         if (workHil[r][s+_I1]<0 && workHil[r][s+_Q1]>0) workHil[r][s+_phase] = 180-workHil[r][s+_phase];
         if (workHil[r][s+_I1]<0 && workHil[r][s+_Q1]<0) workHil[r][s+_phase] = 180+workHil[r][s+_phase];
         if (workHil[r][s+_I1]>0 && workHil[r][s+_Q1]<0) workHil[r][s+_phase] = 360-workHil[r][s+_phase];

      //
      //
      //
      //
      //
                        
      workHil[r][s+_deltaPhase] = workHil[r-1][s+_phase]-workHil[r][s+_phase];

         if (workHil[r-1][s+_phase]<90 && workHil[r][s+_phase]>270)
             workHil[r][s+_deltaPhase] = 360+workHil[r-1][s+_phase]-workHil[r][s+_phase];
             workHil[r][s+_deltaPhase] = MathMax(MathMin(workHil[r][s+_deltaPhase],60),7);
      
            //
            //
            //
            //
            //
                  
            double alpha    = 2.0/(1.0+MathMax(tfilter,1));
            double phaseSum = 0; for (int k=0; phaseSum<cyclesToReach*360 && (r-k)>0; k++) phaseSum += workHil[r-k][s+_deltaPhase];
         
               if (k>0) workHil[r][s+_instPeriod]= k;
                  workHil[r][s+_period] = workHil[r-1][s+_period]+alpha*(workHil[r][s+_instPeriod]-workHil[r-1][s+_period]);
   return (workHil[r][s+_period]);
}

//
//
//
//
//

double calcComp(int r, int from, int s)
{
   return((0.0962*workHil[r  ][s+from] + 
           0.5769*workHil[r-2][s+from] - 
           0.5769*workHil[r-4][s+from] - 
           0.0962*workHil[r-6][s+from]) * (0.075*workHil[r-1][s+_period] + 0.54));
}

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

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("");
}