//+------------------------------------------------------------------+
//|                                   hilbert transform adaptive EMA |
//+------------------------------------------------------------------+
#property copyright "www.forex-station.com"
#property link      "www.forex-station.com"

#property indicator_separate_window
#property indicator_buffers 11
#property indicator_color9  clrDeepSkyBlue
#property indicator_color10 clrDimGray
#property indicator_color11 clrSandyBrown
#property indicator_style9  STYLE_DOT
#property indicator_style10 STYLE_DOT
#property indicator_style11 STYLE_DOT
#property indicator_level1  0

//
//
//
//
//

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                MinMaxPeriod = 50;
extern double             LevelUp      = 90;
extern double             LevelDn      = 10;
input color               ColorNu      = clrLightSteelBlue;  // Neutral color
input color               ColorUp      = clrLime;            // Bullish color
input color               ColorDn      = clrRed;             // Bearish color
input int                 LinesWidth   = 2;                  // Lines width
input int                 HistoWidth   = 2;                  // Histogram width
extern bool               Interpolate  = true;

double histu[],histd[],histm[],val[],valUa[],valUb[],valDa[],valDb[],levUp[],levMi[],levDn[],emaFast[],emaSlow[],valc[];
string indicatorFileName;
bool   returnBars;

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+

int OnInit() 
{
   IndicatorBuffers(14);
   SetIndexBuffer(0, histu,INDICATOR_DATA);  SetIndexStyle(0, DRAW_HISTOGRAM,EMPTY,HistoWidth,ColorUp); 
   SetIndexBuffer(1, histd,INDICATOR_DATA);  SetIndexStyle(1, DRAW_HISTOGRAM,EMPTY,HistoWidth,ColorDn); 
   SetIndexBuffer(2, histm,INDICATOR_DATA);  SetIndexStyle(2, DRAW_HISTOGRAM,EMPTY,HistoWidth);      
   SetIndexBuffer(3, val,  INDICATOR_DATA);  SetIndexStyle(3, DRAW_LINE,EMPTY,LinesWidth,ColorNu);      
   SetIndexBuffer(4, valUa,INDICATOR_DATA);  SetIndexStyle(4, DRAW_LINE,EMPTY,LinesWidth,ColorUp);     
   SetIndexBuffer(5, valUb,INDICATOR_DATA);  SetIndexStyle(5, DRAW_LINE,EMPTY,LinesWidth,ColorUp);    
   SetIndexBuffer(6, valDa,INDICATOR_DATA);  SetIndexStyle(6, DRAW_LINE,EMPTY,LinesWidth,ColorDn);     
   SetIndexBuffer(7, valDb,INDICATOR_DATA);  SetIndexStyle(7, DRAW_LINE,EMPTY,LinesWidth,ColorDn); 
   SetIndexBuffer(8, levUp,INDICATOR_DATA);  SetIndexStyle(8, DRAW_LINE);
   SetIndexBuffer(9, levMi,INDICATOR_DATA);  SetIndexStyle(9, DRAW_LINE);
   SetIndexBuffer(10,levDn,INDICATOR_DATA);  SetIndexStyle(10,DRAW_LINE); 
   SetIndexBuffer(11,emaFast); 
   SetIndexBuffer(12,emaSlow); 
   SetIndexBuffer(13,valc); 
      indicatorFileName = WindowExpertName();
      returnBars        = TimeFrame==-99;
      TimeFrame         = MathMax(TimeFrame,_Period);
      if (ForSymbol=="") ForSymbol = Symbol();

   IndicatorShortName(timeFrameToString(TimeFrame)+" "+ForSymbol+" Phase accumilation MACD");
return(INIT_SUCCEEDED);
}
void OnDeinit(const int reason){ }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+

int start()
{
   SetIndexStyle(2,EMPTY,EMPTY,HistoWidth,(color)ChartGetInteger(0,CHART_COLOR_BACKGROUND));
   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) { histu[0] = limit+1; return(0); }

   //
   //
   //
   //
   //
            
   if (ForSymbol == _Symbol && TimeFrame == _Period)
   {
      if (valc[limit]== 1) { iCleanPoint(limit,Bars,valUa,valUb); histu[limit] = EMPTY_VALUE; histm[limit] = EMPTY_VALUE; }
      if (valc[limit]==-1) { iCleanPoint(limit,Bars,valDa,valDb); histd[limit] = EMPTY_VALUE; histm[limit] = EMPTY_VALUE; }
      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]);
         val[i] = (inverted) ? emaSlow[i]-emaFast[i] :  emaFast[i]-emaSlow[i];
                  
         double min = val[ArrayMinimum(val,MinMaxPeriod,i)];
         double max = val[ArrayMaximum(val,MinMaxPeriod,i)];
         double rng = max-min;
         levUp[i] = min+rng*LevelUp/100.0;
         levMi[i] = min+rng*0.5;
         levDn[i] = min+rng*LevelDn/100.0;
         valUa[i] = valUb[i] = valDa[i] = valDb[i] = EMPTY_VALUE;
         histu[i] = histd[i] = histm[i] = EMPTY_VALUE;
         valc[i]  = (i<Bars-1) ? (val[i]>levUp[i]) ? 1 : (val[i]<levDn[i]) ? -1 : (val[i]<levUp[i] && val[i]>levDn[i]) ? 0 : valc[i+1] : 0; 
         if (valc[i] ==  1) { iPlotPoint(i,Bars,valUa,valUb,val); histu[i] = val[i]; histm[i] = levUp[i]; }
         if (valc[i] == -1) { iPlotPoint(i,Bars,valDa,valDb,val); histd[i] = val[i]; histm[i] = levDn[i]; }    
      }
      return (0);
   }
   
   //
   //
   //
   
   limit = fmax(limit,fmin(Bars-1,iCustom(ForSymbol,TimeFrame,indicatorFileName,-99,0,0)*TimeFrame/_Period));
   if (valc[limit]== 1) { iCleanPoint(limit,Bars,valUa,valUb); histu[limit] = EMPTY_VALUE; histm[limit] = EMPTY_VALUE; }
   if (valc[limit]==-1) { iCleanPoint(limit,Bars,valDa,valDb); histd[limit] = EMPTY_VALUE; histm[limit] = EMPTY_VALUE; }
   for (i=limit; i>=0; i--)
   {
      int y = iBarShift(ForSymbol,TimeFrame,Time[i]);
         val[i]   = iCustom(ForSymbol,TimeFrame,indicatorFileName,PERIOD_CURRENT,"",price,filter,cyclesFast,cyclesSlow,inverted,MinMaxPeriod,LevelUp,LevelDn,ColorNu,ColorUp,ColorDn,LinesWidth,HistoWidth,3,y);
         valUa[i] = valUb[i] = valDa[i] = valDb[i] = EMPTY_VALUE;
         histu[i] = histd[i] = histm[i] = EMPTY_VALUE;
         levUp[i] = iCustom(ForSymbol,TimeFrame,indicatorFileName,PERIOD_CURRENT,"",price,filter,cyclesFast,cyclesSlow,inverted,MinMaxPeriod,LevelUp,LevelDn,ColorNu,ColorUp,ColorDn,LinesWidth,HistoWidth,8,y);
         levMi[i] = iCustom(ForSymbol,TimeFrame,indicatorFileName,PERIOD_CURRENT,"",price,filter,cyclesFast,cyclesSlow,inverted,MinMaxPeriod,LevelUp,LevelDn,ColorNu,ColorUp,ColorDn,LinesWidth,HistoWidth,9,y);
         levDn[i] = iCustom(ForSymbol,TimeFrame,indicatorFileName,PERIOD_CURRENT,"",price,filter,cyclesFast,cyclesSlow,inverted,MinMaxPeriod,LevelUp,LevelDn,ColorNu,ColorUp,ColorDn,LinesWidth,HistoWidth,10,y);
         valc[i]  = iCustom(ForSymbol,TimeFrame,indicatorFileName,PERIOD_CURRENT,"",price,filter,cyclesFast,cyclesSlow,inverted,MinMaxPeriod,LevelUp,LevelDn,ColorNu,ColorUp,ColorDn,LinesWidth,HistoWidth,13,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++)
            {
               val[i+k]   = val[i]   + (val[i+n]   - val[i])  *k/n;
               levUp[i+k] = levUp[i] + (levUp[i+n] - levUp[i])*k/n;
               levMi[i+k] = levMi[i] + (levMi[i+n] - levMi[i])*k/n;
               levDn[i+k] = levDn[i] + (levDn[i+n] - levDn[i])*k/n;
            }               
    }
    for (i=limit; i >= 0; i--)
    {
       if (valc[i] ==  1) { iPlotPoint(i,Bars,valUa,valUb,val); histu[i] = val[i]; histm[i] = levUp[i]; }
       if (valc[i] == -1) { iPlotPoint(i,Bars,valDa,valDb,val); histd[i] = val[i]; histm[i] = levDn[i]; } 
	 }      
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));
}

//
//
//

void iCleanPoint(int i,int bars,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 iPlotPoint(int i,int bars,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; }
}


//-------------------------------------------------------------------
//
//-------------------------------------------------------------------
//
//
//
//
//

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("");
}