Higher Timeframe Moving Average MQL5

 

Hi, 

I've been coding in MQL4 for a while, and am 'reasonably' good at it. Recently I have switched to MQL5 and having difficulty converting my higher timeframe indicators over.

This is a Higher Timeframe Moving average. I think the issue is I am referencing the shift from the curent timeframe but I cannot see how to fix it.

Any help you could offer would be greatly appreacisted as really racking my brains with this. 

This is what it looks like on the chart: 

https://screenrec.com/share/vDUFsz6J31


Thanks in Advance: 


//+------------------------------------------------------------------+
//|                                                          CB-.mq5 |
//|                                                            Chris |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Chris"
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#include <CustomFunctions.mqh>

//+------------------------------------------------------------------+
//| indicator properties                                             |
//+------------------------------------------------------------------+
#property indicator_buffers 2
#property indicator_plots 1

// main line properties
#property indicator_color1 clrRed
#property indicator_label1 "Main"
#property indicator_style1 STYLE_SOLID
#property indicator_type1 DRAW_LINE
#property indicator_width1 1

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

input int                  inpMAPeriod          =  50;               // Period
input ENUM_MA_METHOD       inpMAMethod          =  MODE_EMA;         // Method
input ENUM_APPLIED_PRICE   inpAppliedPrice      =  PRICE_CLOSE;      // Applied Price
input ENUM_TIMEFRAMES      inpTimeFrame         =  PERIOD_CURRENT;   // Timeframe

//+------------------------------------------------------------------+
//| buffers and handles                                              |
//+------------------------------------------------------------------+

// indicator data buffers
double   buffer[];
double   values[];

//handles
int      handle;

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0, buffer, INDICATOR_DATA);

   ArraySetAsSeries(buffer, true);
   ArraySetAsSeries(values, true);

   handle    =  iMA(Symbol(), inpTimeFrame, inpMAPeriod, 0, inpMAMethod, inpAppliedPrice);

   if(handle == INVALID_HANDLE)
     {
      printf("Failed to create Indicator handles");
      return(INIT_FAILED);
     }
   printf("handles created successfully");


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

//control statement
   int limit   =  rates_total - prev_calculated;
   if(prev_calculated > 0)
      limit++;


//for loop
   for(int i = limit; i < rates_total; i++)
     {
     
      int i_bar_shift = iBarShift(Symbol(), inpTimeFrame, time[i], false);
      datetime i_time = iTime(Symbol(), inpTimeFrame, i_bar_shift);

      double arr_ma[1];

      int copy_buffer = CopyBuffer(handle, 0, i_time, 1, arr_ma);

      buffer[i] = arr_ma[0];
     }

   return(rates_total);
  }
//+------------------------------------------------------------------+
07.01.2023_16.40.13_REC
07.01.2023_16.40.13_REC
  • screenrec.com
Recorded with ScreenRec
 
  1.    for(int i = limit; i < rates_total; i++)
    
          int i_bar_shift = iBarShift(Symbol(), inpTimeFrame, time[i], false);
    
          buffer[i] = arr_ma[0];
    You did not set the time[] array and your buffer[] to match your loop direction. In MT5, you must set the direction.
    To define the indexing direction in the time[], open[], high[], low[], close[], tick_volume[], volume[] and spread[] arrays, call the ArrayGetAsSeries() function. In order not to depend on defaults, call the ArraySetAsSeries() function for the arrays to work with.
              Event Handling / OnCalculate - Reference on algorithmic/automated trading language for MetaTrader 5
  2.    int limit   =  rates_total - prev_calculated;
       if(prev_calculated > 0) limit++;
       for(int i = limit; i < rates_total; i++)

    First run, prev_calculated is zero, therefor limit is rates_total+1 and your loop does nothing.
              How to do your lookbacks correctly #9#14 & #19 (2016)

 

Hi WIlliam, Thanks for your help, greatly appreciated.


I've set my time to ArraySetAsSeries(time, true) now. The Buffer was already set to ArraySeries 'true' at the top in the OnInit() funciton, was that what you were refering to? 

I see what you mean about the limit never being smaller than rates_total; 

If I understand the rest of your post correctly; these 2 components are counting in different directions is that the case?


Thanks 


   if(prev_calculated > 0)
      limit++;


//for loop
   for(int i = limit; i < rates_total; i++)
     {
 
Hi 

just starting out with mq5, got an version of HTF average working, leaving it here for anybody else looking for such

//+------------------------------------------------------------------+
//|                                                          CB-.mq5 |
//|                                                            Chris |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Chris"
#property link      "https://www.mql5.com"
#property version   "4.01"

#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots   1

#property indicator_color1 clrDodgerBlue
#property indicator_label1 "MTF MA (Manual)"
#property indicator_style1 STYLE_SOLID
#property indicator_type1  DRAW_LINE
#property indicator_width1 2

input int                inpMAPeriod     = 50;
input ENUM_MA_METHOD     inpMAMethod     = MODE_EMA;
input ENUM_APPLIED_PRICE inpAppliedPrice = PRICE_CLOSE;
input ENUM_TIMEFRAMES    inpTimeFrame    = PERIOD_H4;

double   buffer[];

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit()
  {
   SetIndexBuffer(0, buffer, INDICATOR_DATA);
   PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, 0.0);
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
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 htf_bars_available = (int)SeriesInfoInteger(Symbol(), inpTimeFrame, SERIES_BARS_COUNT);
   if(htf_bars_available < inpMAPeriod)
     {
      PlotIndexSetString(0, PLOT_LABEL, "Waiting for " + EnumToString(inpTimeFrame) + " data...");
      return(0);
     }
   PlotIndexSetString(0, PLOT_LABEL, "MTF MA (Manual)");

   int limit;
   if(prev_calculated == 0)
      limit = 0;
   else
      limit = prev_calculated - 1;

   for(int i = limit; i < rates_total; i++)
     {
      int htf_shift = iBarShift(Symbol(), inpTimeFrame, time[i]);
      int num_bars_to_copy = inpMAPeriod;
      int start_pos_to_copy = htf_shift + 1;

      double htf_close_prices[];
      ArraySetAsSeries(htf_close_prices, true);

      if(CopyClose(Symbol(), inpTimeFrame, start_pos_to_copy, num_bars_to_copy, htf_close_prices) == num_bars_to_copy)
        {
         double ma_value = CalculateEMA(htf_close_prices, inpMAPeriod);
         buffer[i] = ma_value;
        }
      else
        {
         if(i > 0)
            buffer[i] = buffer[i - 1];
         else
            buffer[i] = 0.0;
        }
     }
   return(rates_total);
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double CalculateEMA(const double &prices[], int period)
  {
   if(ArraySize(prices) < period)
      return 0.0;

   double multiplier = 2.0 / (period + 1.0);

   double ema = 0;
   for(int i = period - 1; i >= 0; i--)
     {
      ema += prices[i];
     }
   ema /= period;

   for(int i = period - 2; i >= 0; i--)
     {
      ema = (prices[i] - ema) * multiplier + ema;
     }

   return ema;
  }
//+------------------------------------------------------------------+


also an implementation with various average types (not using iMA and built ins)

//+------------------------------------------------------------------+
//|                                                          CB-.mq5 |
//|                                                            Chris |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Chris"
#property link      "https://www.mql5.com"
#property version   "5.04"

#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots   1

#property indicator_color1 clrDodgerBlue
#property indicator_label1 "MTF MA"
#property indicator_style1 STYLE_SOLID
#property indicator_type1  DRAW_LINE
#property indicator_width1 2

enum ENUM_CUSTOM_MA_METHOD
  {
   CUSTOM_MODE_SMA,
   CUSTOM_MODE_EMA,
   CUSTOM_MODE_SMMA,
   CUSTOM_MODE_WMA,
   CUSTOM_MODE_DEMA,
   CUSTOM_MODE_TEMA,
   CUSTOM_MODE_HMA,
   CUSTOM_MODE_VWMA
  };

input int                   inpMAPeriod     = 50;
input ENUM_CUSTOM_MA_METHOD inpMAMethod     = CUSTOM_MODE_HMA;
input ENUM_TIMEFRAMES       inpTimeFrame    = PERIOD_H4;

double buffer[];

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double CalculateSMA(const double &prices[], int period);
double CalculateWMA(const double &prices[], int period);
double CalculateEMA(const double &prices[], int period);
double CalculateDEMA(const double &prices[], int period);
double CalculateTEMA(const double &prices[], int period);
double CalculateHMA(const double &prices[], int period);

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit()
  {
   SetIndexBuffer(0, buffer, INDICATOR_DATA);
   PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, 0.0);
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
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 required_bars = inpMAPeriod * 3;

   int htf_bars_available = (int)SeriesInfoInteger(Symbol(), inpTimeFrame, SERIES_BARS_COUNT);
   if(htf_bars_available < required_bars)
     {
      PlotIndexSetString(0, PLOT_LABEL, "Waiting for " + EnumToString(inpTimeFrame) + " data...");
      return(0);
     }
   PlotIndexSetString(0, PLOT_LABEL, "MTF MA");

   int limit;
   if(prev_calculated == 0)
      limit = 0;
   else
      limit = prev_calculated - 1;

   for(int i = limit; i < rates_total; i++)
     {
      if(inpTimeFrame == Period() && i < required_bars)
        {
         buffer[i] = 0.0;
         continue;
        }

      int htf_shift = iBarShift(Symbol(), inpTimeFrame, time[i]);
      int start_pos;
      if(inpTimeFrame == Period())
         start_pos = htf_shift;
      else
         start_pos = htf_shift + 1;

      double htf_prices[];
      ArraySetAsSeries(htf_prices, true);

      long htf_volumes[];
      if(inpMAMethod == CUSTOM_MODE_VWMA)
        {
         ArraySetAsSeries(htf_volumes, true);
        }

      int copied_prices = CopyClose(Symbol(), inpTimeFrame, start_pos, required_bars, htf_prices);
      bool data_ready = (copied_prices > 0);

      if(data_ready && inpMAMethod == CUSTOM_MODE_VWMA)
        {
         data_ready = (CopyTickVolume(Symbol(), inpTimeFrame, start_pos, inpMAPeriod, htf_volumes) > 0);
        }

      if(data_ready)
        {
         double ma_value = 0;
         switch(inpMAMethod)
           {
            case CUSTOM_MODE_SMA:
               ma_value = CalculateSMA(htf_prices, inpMAPeriod);
               break;
            case CUSTOM_MODE_EMA:
               ma_value = CalculateEMA(htf_prices, inpMAPeriod);
               break;
            case CUSTOM_MODE_SMMA:
               ma_value = CalculateSMMA(htf_prices, inpMAPeriod);
               break;
            case CUSTOM_MODE_WMA:
               ma_value = CalculateWMA(htf_prices, inpMAPeriod);
               break;
            case CUSTOM_MODE_DEMA:
               ma_value = CalculateDEMA(htf_prices, inpMAPeriod);
               break;
            case CUSTOM_MODE_TEMA:
               ma_value = CalculateTEMA(htf_prices, inpMAPeriod);
               break;
            case CUSTOM_MODE_HMA:
               ma_value = CalculateHMA(htf_prices, inpMAPeriod);
               break;
            case CUSTOM_MODE_VWMA:
               ma_value = CalculateVWMA(htf_prices, htf_volumes, inpMAPeriod);
               break;
           }
         buffer[i] = ma_value;
        }
      else
        {
         if(i > 0)
            buffer[i] = buffer[i - 1];
         else
            buffer[i] = 0.0;
        }
     }
   return(rates_total);
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CalculateMA_Series(const double &src[], int period, ENUM_CUSTOM_MA_METHOD method, double &dest[])
  {
   int src_size = ArraySize(src);
   int dest_size = src_size - period + 1;
   if(dest_size <= 0)
      return;
   ArrayResize(dest, dest_size);
   ArraySetAsSeries(dest, true);

   for(int i = 0; i < dest_size; i++)
     {
      double temp_prices[];
      ArrayCopy(temp_prices, src, 0, i, period);
      ArraySetAsSeries(temp_prices, true);

      switch(method)
        {
         case CUSTOM_MODE_EMA:
            dest[i] = CalculateEMA(temp_prices, period);
            break;
         case CUSTOM_MODE_WMA:
            dest[i] = CalculateWMA(temp_prices, period);
            break;
        }
     }
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double CalculateSMA(const double &prices[], int period)
  {
   if(ArraySize(prices) < period)
      return 0.0;
   double sum = 0;
   for(int i = 0; i < period; i++)
      sum += prices[i];
   return sum / period;
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double CalculateWMA(const double &prices[], int period)
  {
   if(ArraySize(prices) < period)
      return 0.0;
   double sum_weights = 0, sum_weighted_prices = 0;
   for(int i = 0; i < period; i++)
     {
      double weight = period - i;
      sum_weighted_prices += prices[i] * weight;
      sum_weights += weight;
     }
   return (sum_weights > 0) ? sum_weighted_prices / sum_weights : 0.0;
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double CalculateEMA(const double &prices[], int period)
  {
   if(ArraySize(prices) < period)
      return 0.0;
   double multiplier = 2.0 / (period + 1.0);
   double ema = CalculateSMA(prices, period);
   for(int i = ArraySize(prices) - period - 1; i >= 0; i--)
     {
      ema = (prices[i] - ema) * multiplier + ema;
     }
   return ema;
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double CalculateSMMA(const double &prices[], int period)
  {
   if(ArraySize(prices) < period)
      return 0.0;
   double smma = CalculateSMA(prices, period);
   for(int i = period - 2; i >= 0; i--)
     {
      smma = (smma * (period - 1) + prices[i]) / period;
     }
   return smma;
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double CalculateDEMA(const double &prices[], int period)
  {
   if(ArraySize(prices) < 2 * period - 1)
      return 0.0;
   double ema1_series[];
   CalculateMA_Series(prices, period, CUSTOM_MODE_EMA, ema1_series);
   if(ArraySize(ema1_series) == 0)
      return 0.0;
   double ema2 = CalculateEMA(ema1_series, period);
   return 2 * ema1_series[0] - ema2;
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double CalculateTEMA(const double &prices[], int period)
  {
   if(ArraySize(prices) < 3 * period - 2)
      return 0.0;
   double ema1_series[], ema2_series[];
   CalculateMA_Series(prices, period, CUSTOM_MODE_EMA, ema1_series);
   if(ArraySize(ema1_series) == 0)
      return 0.0;
   CalculateMA_Series(ema1_series, period, CUSTOM_MODE_EMA, ema2_series);
   if(ArraySize(ema2_series) == 0)
      return 0.0;
   double ema3 = CalculateEMA(ema2_series, period);
   return 3 * ema1_series[0] - 3 * ema2_series[0] + ema3;
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double CalculateHMA(const double &prices[], int period)
  {
   if(period <= 1)
      return prices[0];
   int period_half = period / 2;
   int period_sqrt = (int)sqrt(period);
   if(ArraySize(prices) < period + period_sqrt)
      return 0.0;

   double wma_half_series[];
   CalculateMA_Series(prices, period_half, CUSTOM_MODE_WMA, wma_half_series);

   double wma_full_series[];
   CalculateMA_Series(prices, period, CUSTOM_MODE_WMA, wma_full_series);

   int size_half = ArraySize(wma_half_series);
   int size_full = ArraySize(wma_full_series);
   if(size_full == 0)
      return 0.0;

   double diff_series[];
   ArrayResize(diff_series, size_full);
   ArraySetAsSeries(diff_series, true);

   int offset = size_half - size_full;

   for(int i = 0; i < size_full; i++)
     {
      diff_series[i] = 2 * wma_half_series[i + offset] - wma_full_series[i];
     }

   return CalculateWMA(diff_series, period_sqrt);
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double CalculateVWMA(const double &prices[], const long &volumes[], int period)
  {
   if(ArraySize(prices) < period || ArraySize(volumes) < period)
      return 0.0;
   double sum_price_vol = 0, sum_vol = 0;
   for(int i = 0; i < period; i++)
     {
      sum_price_vol += prices[i] * volumes[i];
      sum_vol += (double)volumes[i];
     }
   return (sum_vol > 0) ? sum_price_vol / sum_vol : 0.0;
  }
//+------------------------------------------------------------------+