McGinley_Dynamic_MTF

Author: Copyright 2018, MetaQuotes Software Corp.
Price Data Components
Series array that contains open time of each barSeries array that contains close prices for each bar
Indicators Used
Moving average indicator
11 Views
0 Downloads
0 Favorites
McGinley_Dynamic_MTF
ÿþ//+------------------------------------------------------------------+

//|                                         McGinley_Dynamic_MTF.mq5 |

//|                        Copyright 2018, MetaQuotes Software Corp. |

//|                                                 https://mql5.com |

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

#property copyright "Copyright 2018, MetaQuotes Software Corp."

#property link      "https://mql5.com"

#property version   "1.00"

#property description "Multitimeframe McGinley Dynamic average"

#property indicator_chart_window

#property indicator_buffers 9

#property indicator_plots   3

//--- plot MD1

#property indicator_label1  "MD 1"

#property indicator_type1   DRAW_LINE

#property indicator_color1  clrLimeGreen

#property indicator_style1  STYLE_SOLID

#property indicator_width1  1

//--- plot MD2

#property indicator_label2  "MD 2"

#property indicator_type2   DRAW_LINE

#property indicator_color2  clrOrangeRed

#property indicator_style2  STYLE_SOLID

#property indicator_width2  1

//--- plot MD3

#property indicator_label3  "MD 3"

#property indicator_type3   DRAW_LINE

#property indicator_color3  clrDodgerBlue

#property indicator_style3  STYLE_SOLID

#property indicator_width3  1

//--- enums

enum ENUM_DRAW_MODE

  {

   DRAW_MODE_STEPS,  // Steps

   DRAW_MODE_SLOPE   // Slope

  };

//--- input parameters

input uint              InpPeriod      =  9;                // MD period

input uint              InpSmoothing   =  125;              // MD smoothing

input ENUM_TIMEFRAMES   InpTimeframe1  =  PERIOD_H1;        // First MD timeframe

input ENUM_TIMEFRAMES   InpTimeframe2  =  PERIOD_H4;        // Second MD timeframe

input ENUM_TIMEFRAMES   InpTimeframe3  =  PERIOD_D1;        // Third MD timeframe

input ENUM_DRAW_MODE    InpDrawMode    =  DRAW_MODE_STEPS;  // Drawing mode

//--- indicator buffers

double            BufferMD1[];

double            BufferMD2[];

double            BufferMD3[];

double            BufferMD1tmp[];

double            BufferMD2tmp[];

double            BufferMD3tmp[];

double            BufferMA1[];

double            BufferMA2[];

double            BufferMA3[];

//--- global variables

ENUM_TIMEFRAMES   timeframe1;

ENUM_TIMEFRAMES   timeframe2;

ENUM_TIMEFRAMES   timeframe3;

int               period;

int               smoothing;

int               handle_ma1;

int               handle_ma2;

int               handle_ma3;

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

//| Custom indicator initialization function                         |

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

int OnInit()

  {

//--- timer

   EventSetTimer(90);

//--- set global variables

   period=int(InpPeriod<1 ? 1 : InpPeriod);

   smoothing=int(InpSmoothing<1 ? 1 : InpSmoothing);

   timeframe1=(InpTimeframe1>Period() ? InpTimeframe1 : Period());

   timeframe2=(InpTimeframe2>Period() ? InpTimeframe2 : Period());

   timeframe3=(InpTimeframe3>Period() ? InpTimeframe3 : Period());

//--- indicator buffers mapping

   SetIndexBuffer(0,BufferMD1,INDICATOR_DATA);

   SetIndexBuffer(1,BufferMD2,INDICATOR_DATA);

   SetIndexBuffer(2,BufferMD3,INDICATOR_DATA);

   SetIndexBuffer(3,BufferMD1tmp,INDICATOR_CALCULATIONS);

   SetIndexBuffer(4,BufferMD2tmp,INDICATOR_CALCULATIONS);

   SetIndexBuffer(5,BufferMD3tmp,INDICATOR_CALCULATIONS);

   SetIndexBuffer(6,BufferMA1,INDICATOR_CALCULATIONS);

   SetIndexBuffer(7,BufferMA2,INDICATOR_CALCULATIONS);

   SetIndexBuffer(8,BufferMA3,INDICATOR_CALCULATIONS);

//--- setting indicator parameters

   string label=TimeframeToString(timeframe1)+","+TimeframeToString(timeframe2)+","+TimeframeToString(timeframe3)+" McGinley Dynamic("+(string)period+","+(string)smoothing+")";

   IndicatorSetString(INDICATOR_SHORTNAME,label);

   IndicatorSetInteger(INDICATOR_DIGITS,Digits());

//--- setting plot buffer parameters

   PlotIndexSetString(0,PLOT_LABEL,TimeframeToString(timeframe1)+" MD ("+(string)period+","+(string)smoothing+")");

   PlotIndexSetString(1,PLOT_LABEL,TimeframeToString(timeframe2)+" MD ("+(string)period+","+(string)smoothing+")");

   PlotIndexSetString(2,PLOT_LABEL,TimeframeToString(timeframe3)+" MD ("+(string)period+","+(string)smoothing+")");

//--- setting buffer arrays as timeseries

   ArraySetAsSeries(BufferMD1,true);

   ArraySetAsSeries(BufferMD2,true);

   ArraySetAsSeries(BufferMD3,true);

   ArraySetAsSeries(BufferMD1tmp,true);

   ArraySetAsSeries(BufferMD2tmp,true);

   ArraySetAsSeries(BufferMD3tmp,true);

   ArraySetAsSeries(BufferMA1,true);

   ArraySetAsSeries(BufferMA2,true);

   ArraySetAsSeries(BufferMA3,true);

//--- create MA's handles

   ResetLastError();

   handle_ma1=iMA(NULL,timeframe1,period,0,MODE_EMA,PRICE_CLOSE);

   if(handle_ma1==INVALID_HANDLE)

     {

      Print("The iMA(",TimeframeToString(timeframe1),",",(string)period,") object was not created: Error ",GetLastError());

      return INIT_FAILED;

     }

   handle_ma2=iMA(NULL,timeframe2,period,0,MODE_EMA,PRICE_CLOSE);

   if(handle_ma2==INVALID_HANDLE)

     {

      Print("The iMA(",TimeframeToString(timeframe2),",",(string)period,") object was not created: Error ",GetLastError());

      return INIT_FAILED;

     }

   handle_ma3=iMA(NULL,timeframe3,period,0,MODE_EMA,PRICE_CLOSE);

   if(handle_ma3==INVALID_HANDLE)

     {

      Print("The iMA(",TimeframeToString(timeframe3),",",(string)period,") object was not created: Error ",GetLastError());

      return INIT_FAILED;

     }

//--- get timeframe

   Time(NULL,timeframe1,1);

   Time(NULL,timeframe2,1);

   Time(NULL,timeframe3,1);

//---

   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[])

  {

//--- @>25@:0 :>;8G5AB20 4>ABC?=KE 10@>2

   if(rates_total<4) return 0;

//--- @>25@:0 8 @0AGQB :>;8G5AB20 ?@>AG8BK205<KE 10@>2

   int limit=rates_total-prev_calculated;

   if(limit>1)

     {

      limit=rates_total-2;

      ArrayInitialize(BufferMD1,EMPTY_VALUE);

      ArrayInitialize(BufferMD2,EMPTY_VALUE);

      ArrayInitialize(BufferMD3,EMPTY_VALUE);

      ArrayInitialize(BufferMD1tmp,0);

      ArrayInitialize(BufferMD2tmp,0);

      ArrayInitialize(BufferMD3tmp,0);

      ArrayInitialize(BufferMA1,0);

      ArrayInitialize(BufferMA2,0);

      ArrayInitialize(BufferMA3,0);

     }

//--- >43>B>2:0 40==KE

   if(Time(NULL,timeframe1,1)==0 || Time(NULL,timeframe2,1)==0 || Time(NULL,timeframe3,1)==0)

      return 0;

   int bars1=(timeframe1==Period() ? rates_total : Bars(NULL,timeframe1));

   int bars2=(timeframe2==Period() ? rates_total : Bars(NULL,timeframe2));

   int bars3=(timeframe3==Period() ? rates_total : Bars(NULL,timeframe3));

   

   int count1=(limit>1 ? fmin(bars1,rates_total) : 1),copied=0;

   copied=CopyBuffer(handle_ma1,0,0,count1,BufferMA1);

   if(copied!=count1) return 0;

   

   int count2=(limit>1 ? fmin(bars2,rates_total) : 1);

   copied=CopyBuffer(handle_ma2,0,0,count2,BufferMA2);

   if(copied!=count2) return 0;

   

   int count3=(limit>1 ? fmin(bars3,rates_total) : 1);

   copied=CopyBuffer(handle_ma3,0,0,count3,BufferMA3);

   if(copied!=count3) return 0;

   

   for(int i=limit; i>=0 && !IsStopped(); i--)

     {

      double close0=Close(NULL,timeframe1,i);

      if(close0==0 || BufferMA1[i+1]==0)

         continue;

      BufferMD1tmp[i]=BufferMA1[i+1]+(close0-BufferMA1[i+1])/(BufferMA1[i+1]*smoothing);

      //---

      close0=Close(NULL,timeframe2,i);

      if(close0==0 || BufferMA2[i+1]==0)

         continue;

      BufferMD2tmp[i]=BufferMA2[i+1]+(close0-BufferMA2[i+1])/(BufferMA2[i+1]*smoothing);

      //---

      close0=Close(NULL,timeframe3,i);

      if(close0==0 || BufferMA3[i+1]==0)

         continue;

      BufferMD3tmp[i]=BufferMA3[i+1]+(close0-BufferMA3[i+1])/(BufferMA3[i+1]*smoothing);

     }



//---  0AGQB 8=48:0B>@0

   for(int i=limit; i>=0; i--)

     {

      DataConversion(rates_total,NULL,timeframe1,i,BufferMD1tmp,BufferMD1,InpDrawMode);

      DataConversion(rates_total,NULL,timeframe2,i,BufferMD2tmp,BufferMD2,InpDrawMode);

      DataConversion(rates_total,NULL,timeframe3,i,BufferMD3tmp,BufferMD3,InpDrawMode);

     }

   

//--- return value of prev_calculated for next call

   return(rates_total);

  }

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

//| Custom indicator timer function                                  |

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

void OnTimer()

  {

   Time(NULL,timeframe1,1);

   Time(NULL,timeframe2,1);

   Time(NULL,timeframe3,1);

  }  

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

//| Transfering data from the source timeframe to current timeframe  |

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

void DataConversion(const int rates_total,

                    const string symbol_name,

                    const ENUM_TIMEFRAMES timeframe_src,

                    const int shift,

                    const double &buffer_src[],

                    double &buffer_dest[],

                    ENUM_DRAW_MODE mode=DRAW_MODE_STEPS

                   )

  {

   if(Time(symbol_name,timeframe_src,shift)==0)

      return;

   if(timeframe_src==Period())

     {

      buffer_dest[shift]=buffer_src[shift];

      return;

     }

   int bar_curr=BarToCurrent(symbol_name,timeframe_src,shift);

   if(bar_curr>rates_total-1)

      return;

   int bar_prev=BarToCurrent(symbol_name,timeframe_src,shift+1);

   int bar_next=(shift>0 ? BarToCurrent(symbol_name,timeframe_src,shift-1) : 0);

   if(bar_prev==WRONG_VALUE || bar_curr==WRONG_VALUE || bar_next==WRONG_VALUE)

      return;

   buffer_dest[bar_curr]=buffer_src[shift];

   if(mode==DRAW_MODE_STEPS)

      for(int j=bar_curr; j>=bar_next; j--)

         buffer_dest[j]=buffer_dest[bar_curr];

   else

     {

      if(bar_prev>rates_total-1) return;

      for(int j=bar_prev; j>=bar_curr; j--)

         buffer_dest[j]=EquationDirect(bar_prev,buffer_dest[bar_prev],bar_curr,buffer_dest[bar_curr],j);

      if(shift==0)

         for(int j=bar_curr; j>=0; j--)

            buffer_dest[j]=buffer_dest[bar_curr];

     }

  }

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

//| >72@0I05B 10@ 7040==>3> B09<D@59<0 :0: 10@ B5:CI53> B09<D@59<0  |

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

int BarToCurrent(const string symbol_name,const ENUM_TIMEFRAMES timeframe_src,const int shift,bool exact=false)

  {

   datetime time=Time(symbol_name,timeframe_src,shift);

   return(time!=0 ? BarShift(symbol_name,Period(),time,exact) : WRONG_VALUE);

  }  

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

//| >72@0I05B A<5I5=85 10@0 ?> 2@5<5=8                              |

//| https://www.mql5.com/ru/forum/743/page11#comment_7010041         |

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

int BarShift(const string symbol_name,const ENUM_TIMEFRAMES timeframe,const datetime time,bool exact=false)

  {

   int res=Bars(symbol_name,timeframe,time+1,UINT_MAX);

   if(exact) if((timeframe!=PERIOD_MN1 || time>TimeCurrent()) && res==Bars(symbol_name,timeframe,time-PeriodSeconds(timeframe)+1,UINT_MAX)) return(WRONG_VALUE);

   return res;

  }

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

//| >72@0I05B Close                                                 |

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

double Close(const string symbol_name,const ENUM_TIMEFRAMES timeframe,const int shift)

  {

   double array[];

   ArraySetAsSeries(array,true);

   return(CopyClose(symbol_name,timeframe,shift,1,array)==1 ? array[0] : 0);

  }

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

//| >72@0I05B Time                                                  |

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

datetime Time(const string symbol_name,const ENUM_TIMEFRAMES timeframe,const int shift)

  {

   datetime array[];

   ArraySetAsSeries(array,true);

   return(CopyTime(symbol_name,timeframe,shift,1,array)==1 ? array[0] : 0);

  }

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

//| #@02=5=85 ?@O<>9                                                 |

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

double EquationDirect(const int left_bar,const double left_price,const int right_bar,const double right_price,const int bar_to_search) 

  {

   return(right_bar==left_bar ? left_price : (right_price-left_price)/(right_bar-left_bar)*(bar_to_search-left_bar)+left_price);

  }

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

//| Timeframe to string                                              |

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

string TimeframeToString(const ENUM_TIMEFRAMES timeframe)

  {

   return StringSubstr(EnumToString(timeframe),7);

  }

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

Comments