mba_channel

Author: Copyright 2021, Yossy Nakata
0 Views
0 Downloads
0 Favorites
mba_channel
//+------------------------------------------------------------------+
//|                                                  mba_channel.mq5 |
//|                                     Copyright 2021, Yossy Nakata |
//|                                  https://yossy-nakata.hateblo.jp |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, Yossy Nakata"
#property link      "https://yossy-nakata.hateblo.jp"
#property version   "1.00"
#property strict
#property indicator_chart_window
#property indicator_buffers    7
#property indicator_plots   2

#property indicator_label1  "upper"
#property indicator_type1   DRAW_LINE
#property indicator_color1 clrRed
#property indicator_width1  1

#property indicator_label2  "lower"
#property indicator_type2   DRAW_LINE
#property indicator_color2 clrDodgerBlue
#property indicator_width2  1


const int FAST = 3; // Minimum Channel Period;
//--- input parameter
input int InpPeriod=20; // Channel Period
input double InpVFactor=0.5; // Volatility Factor
input int InpVEmaPeriod=200; // Volatility Smoothing
//--- buffers
double g_high[];
double g_low[];
double g_upper[];
double g_lower[];
double g_upper_i[];
double g_lower_i[];
double g_volat[];
static datetime g_start_time=0;


//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {

//--- indicator buffers mapping
   SetIndexBuffer(0,g_upper,INDICATOR_DATA);
   SetIndexBuffer(1,g_lower,INDICATOR_DATA);
   SetIndexBuffer(2,g_high,INDICATOR_CALCULATIONS);
   SetIndexBuffer(3,g_low,INDICATOR_CALCULATIONS);
   SetIndexBuffer(4,g_volat,INDICATOR_CALCULATIONS);
   SetIndexBuffer(5,g_upper_i,INDICATOR_CALCULATIONS);
   SetIndexBuffer(6,g_lower_i,INDICATOR_CALCULATIONS);


   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,EMPTY_VALUE);
   PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,EMPTY_VALUE);
   PlotIndexSetDouble(2,PLOT_EMPTY_VALUE,EMPTY_VALUE);
   PlotIndexSetDouble(3,PLOT_EMPTY_VALUE,EMPTY_VALUE);
   PlotIndexSetDouble(4,PLOT_EMPTY_VALUE,EMPTY_VALUE);
   PlotIndexSetDouble(5,PLOT_EMPTY_VALUE,EMPTY_VALUE);
   PlotIndexSetDouble(6,PLOT_EMPTY_VALUE,EMPTY_VALUE);

   ArrayInitialize(g_upper,EMPTY_VALUE);
   ArrayInitialize(g_lower,EMPTY_VALUE);
   ArrayInitialize(g_upper_i,EMPTY_VALUE);
   ArrayInitialize(g_lower_i,EMPTY_VALUE);
   ArrayInitialize(g_high,EMPTY_VALUE);
   ArrayInitialize(g_low,EMPTY_VALUE);
   ArrayInitialize(g_volat,EMPTY_VALUE);

   m_msv.init(InpVEmaPeriod);
   g_start_time=0;

///---
   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[])
  {
//---
   int    i,pos;
//---
   ArraySetAsSeries(time,false);
   ArraySetAsSeries(high,false);
   ArraySetAsSeries(low,false);
   ArraySetAsSeries(g_upper,false);
   ArraySetAsSeries(g_lower,false);
   ArraySetAsSeries(g_upper_i,false);
   ArraySetAsSeries(g_lower_i,false);
   ArraySetAsSeries(g_high,false);
   ArraySetAsSeries(g_low,false);
   ArraySetAsSeries(g_volat,false);

   pos=(int)MathMax(prev_calculated-1,0);

   if(prev_calculated==0 || (rates_total>0 && g_start_time != time[0]))
     {
      ArrayInitialize(g_upper,EMPTY_VALUE);
      ArrayInitialize(g_lower,EMPTY_VALUE);
      ArrayInitialize(g_upper_i,EMPTY_VALUE);
      ArrayInitialize(g_lower_i,EMPTY_VALUE);
      ArrayInitialize(g_high,EMPTY_VALUE);
      ArrayInitialize(g_low,EMPTY_VALUE);
      ArrayInitialize(g_volat,EMPTY_VALUE);
      g_start_time=time[0];
      pos=0;
     }

//--- preliminary calculations

   double v;
//--- the main loop of calculations
   for(i=pos; i<rates_total && !IsStopped(); i++)
     {
      //---  volatility calculation
      if(!m_msv.calculate(close,i,rates_total,v))
         continue;
      g_volat[i]=v;

      if(i<InpPeriod+3)
        {

         g_high[i]=high[i];
         g_low[i]=low[i];
         g_upper[i]=high[i];
         g_lower[i]=low[i];
         g_upper_i[i]=i;
         g_lower_i[i]=i;
         continue;
        }

      //---  minimum channel calculation

      g_high[i]=(g_high[i-1] <= high[i]) ? high[i] :high[ArrayMaximum(high,i-(FAST-1),FAST)];
      g_low[i] =(g_low[i-1] >= low[i]) ? low[i] :low[ArrayMinimum(low,i-(FAST-1),FAST)];


      //---  upper side calculation

      double width = g_volat[i] * InpVFactor;

      if(g_upper[i-1]<=high[i])
        {
         g_upper[i]=high[i];
         g_upper_i[i] = i;

        }
      else
        {
         int h_pos= (int) g_upper_i[i-1];
         int lookback= 1+i-h_pos;

         // Euclidean distance
         double dist= distance(width, h_pos, i, g_high[h_pos],g_high[i]);
         if(InpPeriod * width < dist)
           {
            int len=MathMax(1,lookback-1);
            int max_i=ArrayMaximum(high,i-(len-1),len);
            g_upper[i]=high[max_i];
            g_upper_i[i] = max_i;

           }
         else
           {
            g_upper[i]=g_upper[i-1];
            g_upper_i[i] = g_upper_i[i-1];
           }
        }

      //---  lower side calculation
      if(g_lower[i-1] >= low[i])
        {
         g_lower[i]=low[i];
         g_lower_i[i]= i;

        }
      else
        {
         int l_pos= (int)g_lower_i[i-1];
         int lookback=1+i-l_pos;
         // Euclidean distance
         double dist= distance(width, l_pos, i, g_low[l_pos], g_low[i]);
         if(InpPeriod*width < dist)
           {
            int len=MathMax(1,lookback-1);
            int min_i=ArrayMinimum(low,i-(len-1),len);
            g_lower[i]=low[min_i];
            g_lower_i[i]= min_i;

           }
         else
           {
            g_lower[i]=g_lower[i-1];
            g_lower_i[i]= g_lower_i[i-1];

           }
        }

     }
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
double            distance(const double v,const double x1,const double x2,const double y1,const double y2)
  {
   return MathSqrt(MathPow(v*(x2-x1),2)+MathPow(y2-y1,2));
  }

//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
struct MsVolatItem
  {
   double            main;
   double            adf;
   double            df3;
   double            df4;
   double            df5;
   double            df6;
   double            df8;
   double            df10;
   double            df13;
  };


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class MsVolat
  {
private :
   int               _begin_plot;
   double            _alpha;
   double            _sq3;
   double            _sq4;
   double            _sq5;
   double            _sq6;
   double            _sq8;
   double            _sq10;
   double            _sq13;

   MsVolatItem       _buf[];
   int               _buf_size;
public :

                     MsVolat():
                     _begin_plot(0),
                     _alpha(0.),
                     _sq3(sqrt(3)),
                     _sq4(sqrt(4)),
                     _sq5(sqrt(5)),
                     _sq6(sqrt(6)),
                     _sq8(sqrt(8)),
                     _sq10(sqrt(10)),
                     _sq13(sqrt(13)) { return; }

                    ~MsVolat() { return; }

   void              init(int period)
     {
      //---
      _begin_plot = period+1+13;
      _alpha= 2.0/(period+1.0);

     }

   double            diff(const int lag,const double w, const double &value[],const int i)
     {
      return MathAbs(value[i-lag]-value[i])/w;
     }

   //+------------------------------------------------------------------+
   bool              calculate(const double &value[], int i, int bars,double &rslt)
     {
      if(_buf_size<bars)
         _buf_size=ArrayResize(_buf,bars+500,2000);

      if(_buf_size==-1)
         return false;

      if(i<=13)
        {
         _buf[i].main = EMPTY_VALUE;
         return false;
        }
      _buf[i].df3=MsVolat::diff(3,_sq3,value,i);
      _buf[i].df4=MsVolat::diff(4,_sq4,value,i);
      _buf[i].df5=MsVolat::diff(5,_sq5,value,i);
      _buf[i].df6=MsVolat::diff(6,_sq6,value,i);
      _buf[i].df8=MsVolat::diff(8,_sq8,value,i);
      _buf[i].df10=MsVolat::diff(10,_sq10,value,i);
      _buf[i].df13=MsVolat::diff(13,_sq13,value,i);

      _buf[i].adf=(_buf[i].df3+ _buf[i].df4+ _buf[i].df5+ _buf[i].df6
                   + _buf[i].df8+_buf[i].df10+ _buf[i].df13)/7.0;


      if(i<=14)
        {
         _buf[i].main = _buf[i].adf;
         return false;
        }

      _buf[i].main = _alpha * _buf[i].adf + (1.0-_alpha)*_buf[i-1].main;

      rslt=_buf[i].main;
      return (true);
     }


  };

//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
MsVolat m_msv;
//+------------------------------------------------------------------+

Comments