//+------------------------------------------------------------------+
//|                                      Instantaneous_Trendline.mq4 |
//|                        Copyright 2019, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
//+---------------------------------+
//---Instantaneous_Trendline.mq4
//---Tony Thompson
//+---------------------------------+
#property version "1.00"
#property strict
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots 1

//--- plot iTrendline
#property indicator_label1 "Trendline"
#property indicator_type1 DRAW_LINE
#property indicator_color1 clrBlue
#property indicator_style1 STYLE_SOLID
#property indicator_width1 2

//---Input Parameters
input double CycPart = 1;

//--- indicator buffers
double Trendline[];

//---working indcator/buffers
double price[];
double smooth[];
double detrender[];
double i1[];
double q1[];
double i2[];
double q2[];
double re[];
double im[];
double period[];
double smoothPeriod[];
double iTrend[];

//-----------------------------------------------------+
//---custom indicator initialization function
//-----------------------------------------------------+
int Onint()
{
   //---indicator buffers mapping
   IndicatorBuffers (13);
   SetIndexStyle(0, DRAW_LINE);
   SetIndexBuffer(0, Trendline);
   SetIndexDrawBegin(0, DRAW_LINE);
   SetIndexStyle(1, DRAW_NONE);
   SetIndexBuffer(1, price);
   SetIndexStyle(2, DRAW_NONE);
   SetIndexBuffer(2, smooth);
   SetIndexStyle(3, DRAW_NONE);
   SetIndexBuffer(3, detrender);
   SetIndexStyle(4, DRAW_NONE);
   SetIndexBuffer(4, i1);
   SetIndexStyle(5, DRAW_NONE);
   SetIndexBuffer(5, q1);
   SetIndexStyle(6, DRAW_NONE);
   SetIndexBuffer(6, i2);
   SetIndexStyle(7, DRAW_NONE);
   SetIndexBuffer(7, q2);
   SetIndexStyle(8, DRAW_NONE);
   SetIndexBuffer(8, re);
   SetIndexStyle(9, DRAW_NONE);
   SetIndexBuffer(9, im);
   SetIndexStyle(10, DRAW_NONE);
   SetIndexBuffer(10, period);
   SetIndexStyle(11, DRAW_NONE);
   SetIndexBuffer(11, smoothPeriod);
   SetIndexStyle(12, DRAW_LINE);
   SetIndexBuffer(12, iTrend);
   return(INIT_SUCCEEDED);
}

//----Custom indicator iteration function
int OnCalculate(const int rates_total,
   const int prev_calculated,
   const datetime &time[],
   const double &open[],
   const double &high[],
   const double &low[],
   const double &close[],
   const long &tick_volume[],
   const long &volume[],
   const int &spread[])
{
   //---set arrays as series
   ArraySetAsSeries(Trendline, true);
   ArraySetAsSeries(price, true);
   ArraySetAsSeries(smooth, true);
   ArraySetAsSeries(detrender, true);
   ArraySetAsSeries(i1, true);
   ArraySetAsSeries(q1, true);
   ArraySetAsSeries(i2, true);
   ArraySetAsSeries(q2, true);
   ArraySetAsSeries(re, true);
   ArraySetAsSeries(im, true);
   ArraySetAsSeries(period, true);
   ArraySetAsSeries(smoothPeriod, true);
   ArraySetAsSeries(iTrend, true);
   ArraySetAsSeries(low, true);
   ArraySetAsSeries(high, true);

   int bars = rates_total - 1;
   if(prev_calculated > 0)
     bars = rates_total - prev_calculated;
   for(int i = bars; i >= 0; i--)
   {
     //----Calculate price to be used
     price[i] = ((high[i] + low[i]) * .5);

     if(rates_total > 5)
     {
       smooth[i] = (4 * price[i] + 3 * price[i+1] + 2 * price[i+2] + price[i+3]) / 10;
       detrender[i] = HilTransFilt(smooth[i], smooth[i+2], smooth[i+4], smooth[i+6], period[i+1]);

       //---Compute inphase and quadrature components
       q1[i] = HilTransFilt(detrender[i], detrender[i+2], detrender[i+4], detrender[i+6], period[i+1]);
       i1[i] = detrender[i+3];

       //---Advance the phase of i1 and q1 by 90 degrees
       double jI = HilTransFilt(i1[i], i1[i+2], i1[i+4], i1[i+6], period[i+1]);
       double jQ = HilTransFilt(q1[i], q1[i+2], q1[i+4], q1[i+6], period[i+1]);

       //---Phasor addition for 3 bar averaging
       i2[i] = i1[i] - jQ;
       q2[i] = q1[i] + jI;

       //--- smooth the i and q components
       i2[i] = .2 * i2[i] + .8 * i2[i+1];
       q2[i] = .2 * q2[i] + .8 * q2[i+1];

       //---HomodyneDiscriminator
       re[i] = i2[i] * i2[i+1] + q2[i] * q2[i+1];
       im[i] = i2[i] * q2[i+1] - q2[i] * i2[i+1];
       re[i] = .2 * re[i] + .8 * re[i+1];
       im[i] = .2 * im[i] + .8 * im[i+1];
       if(im[i] != 0 && re[i] != 0) period[i] = 360 / MathArctan(im[i] / re[i]);
       if(period[i] > 1.5 * period[i+1]) period[i] = 1.5 * period[i+1];
       if(period[i] < .67 * period[i+1]) period[i] = .67 * period[i+1];
       if(period[i] < 6) period [i] = 6;
       if(period[i] > 50) period[i] = 50;
       period[i] = .2 * period[i] + .8 * period[i+1];
       smoothPeriod[i] = .33 * period[i] + .67 * smoothPeriod[i+1];

       //---compute Trendline as simple avg over the measure dominant cycle
       iTrend[i] = 0;
       int dcPeriod = CycPart * smoothPeriod[i] + .5;
       for(int count = 0; count <= dcPeriod - 1; count++)
       {
          iTrend[i] = iTrend[i] + price[i+count];
       }
       if(dcPeriod > 0) iTrend[i] = iTrend[i] / dcPeriod;
       Trendline[i] = (4 * iTrend[i] + 3 * iTrend[i+1] + 2 * iTrend[i+2] + iTrend[i+3]) / 10;
   
       if(rates_total < 12) Trendline[i] = price[i];
     }   //end if <5
   }     //end for loop

//---return value of prev_calculated for next call
     return(rates_total);
}       //---end on_calculate

//+------------------------------------------+
//---functions
//+------------------------------------------+

//---Hilbert Transform Function
double HilTransFilt(double pVal0, double pVal2, double pVal4, double pVal6, double pPeriod)
   {
     return((.0962 * pVal0 + .5769 * pVal2 - .5769 * pVal4 - .0962 * pVal6) * (.075 * pPeriod + .54));
   }