Hull Moving Average – indicator MetaTrader 5

I did not understand the source of other Hull MA implementations, so i decide to implement it myself. It has four input parameters:

  1. InpHmaPeriod = 20
  2. InpColorKind = single_color
  3. InpColorIndex = color_index_3
  4. InpMaxHistoryBars = 240

These parameters are self explanatory. The enumeration ENUM_COLOR_KIND switches between single and multi color, default is single color. In multi color, the  Hull MA has another color for rising and a different one for falling values. In single color mode, the ENUM_COLOR_INDEX sets the single color of the Hull MA. In multi color mode, the default color is grey. On upslope the color is green and on downslope it is red. You can see it in the following two pictures.

Available colors

The code:

//+------------------------------------------------------------------+
//|                                                     MelzHull.mq5 |
//|                                       Copyright 2022, wm1@gmx.de |
//|                                                 https://melz.one |
//+------------------------------------------------------------------+
/*
  === My Hull Moving Average implementation

  In my indicator you can choose between single- and multi-color for
  the indicator line.

*/

enum ENUM_COLOR_KIND {  // single or alternating color
  single_color,
  multi_color
};

enum ENUM_COLOR_INDEX { // index of indicator_color1 colors
  color_index_0,
  color_index_1,
  color_index_2,
  color_index_3,
  color_index_4,
  color_index_5,
  color_index_6
};

#property copyright   "Copyright 2022 by W. Melz, wm1@gmx.de"
#property link        "https://melz.one"
#property version     "1.00"
#property description "Implementation of my Hull Moving Average"
//--- indicator settings
#property indicator_chart_window              // draw in chart window
#property indicator_buffers 4                 // buffers for: fullWMA, halfWMA, vHull, cHull
#property indicator_plots   1                 // plot only one line
#property indicator_type1   DRAW_COLOR_LINE   // draw as color line
// color index to select from:    0        1      2       3              4             5            6, feel free to extend the list up to 64 colors
#property indicator_color1  clrGray,clrGreen,clrRed,clrBlue,clrGreenYellow,clrDodgerBlue,clrFireBrick
#property indicator_width1  1                 // line width
#property indicator_label1  "HMA"             // indicator name

//--- input parameters
input int                 InpHmaPeriod        = 20;             // indicator period, default 20
input ENUM_COLOR_KIND     InpColorKind        = single_color;   // kind of indicator color, single- or multi-color
input ENUM_COLOR_INDEX    InpColorIndex       = color_index_3;  // set color of single-color indicator
input int                 InpMaxHistoryBars   = 240;            // calculate historycally bars, default 240, not more

//--- indicator buffers
double valueBuffer[];           // store Hull indicator values
double colorBuffer[];           // store Hull indicator color at bar
double fullWMABuffer[];         // store calculation of WMA full period
double halfWMABuffer[];         // store calculation the WMA half period

//--- Indicator global variables
int hmaPeriod, fullPeriod, halfPeriod, sqrtPeriod, maxHistoryBars;  // store input value or default value

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit() {
  ENUM_INIT_RETCODE result = checkInput();                // check for correct input parameters

  SetIndexBuffer(0,valueBuffer,INDICATOR_DATA);           // store indicator buffer mapping
  SetIndexBuffer(1,colorBuffer,INDICATOR_COLOR_INDEX);    // store indicator candle color
  SetIndexBuffer(2,fullWMABuffer,INDICATOR_CALCULATIONS); // store result of fullWMA calculation
  SetIndexBuffer(3,halfWMABuffer,INDICATOR_CALCULATIONS); // store result of halfWMA calculation
  IndicatorSetInteger(INDICATOR_DIGITS,_Digits);          // set indicator digits
  string shortName = StringFormat("HMA(%d)",hmaPeriod);   // name for DataWindow and indicator subwindow label
  IndicatorSetString(INDICATOR_SHORTNAME,shortName);
  PlotIndexSetString(0,PLOT_LABEL,shortName);

// calculate global values for indicator
  fullPeriod = hmaPeriod;                             // period from input
  halfPeriod = fullPeriod / 2;                        // calculate half period
  sqrtPeriod = (int)round(sqrt((double)fullPeriod));  // calculate square root of period

  return(result);                                     // success or failure, init finished
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
ENUM_INIT_RETCODE checkInput(void) {      // change this function for your own indicator parameters
  if(InpHmaPeriod <= 0) {                 // check for correct input value range
    hmaPeriod = 14;                       // if invalid input set period to 14
    PrintFormat("Incorrect input parameter InpTestPeriod = %d. Indicator will use value %d for calculations.",InpHmaPeriod,hmaPeriod);
  } else
    hmaPeriod = InpHmaPeriod;             // set period from input

  maxHistoryBars = InpMaxHistoryBars;   // else use input value

  return(INIT_SUCCEEDED);                 // or INIT_FAILED
}

//------------------------------------------------------------------
// Custom indicator de-initialization function
//------------------------------------------------------------------
void OnDeinit(const int reason) {
  ArrayFree(valueBuffer);
  ArrayFree(colorBuffer);
  ArrayFree(fullWMABuffer);
  ArrayFree(halfWMABuffer);
}

//+------------------------------------------------------------------+
//| 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[]) {
  if(rates_total < maxHistoryBars + hmaPeriod)  // test for available bars, adjust for period when calculating other indicators
    return(0);                                  // when no bars available, do nothing on this tick.

  int startBar;                 // store index values
  if(prev_calculated == 0) {    // if no historical bar calculated before
    //Print("--- Calculating historically bars");
    // first tick, calculate all historical bars, oldest index 0, plus rates_total - InpMaxHistoryBars -1 for start at index
    startBar = rates_total - maxHistoryBars - hmaPeriod - 1;
    PlotIndexSetInteger(0,PLOT_DRAW_BEGIN, startBar + hmaPeriod);  // set plot begin from the bar with index of startBar + hmaPeriod
    // do calc
    CalcHma(startBar,rates_total,close);   // calculate the Ma's over the volume and compare to bar size
  }
  
  if(rates_total - prev_calculated == 1) {
    //Print("-- Calculating new bar");
    startBar = rates_total - 1; // calculate the actual new open bar
    // do calc
    CalcHma(startBar,rates_total,close);   // calculate the Ma's over the volume and compare to bar size
  }

  // do calc
  //Print("- Calculating every tick");
  return(rates_total);  // return value of prev_calculated for next call
}

// calculate Ma from startBar to rates_total on array buf
void CalcHma(int startBar, const int rates_total, const double &buf[]) {
  for(int bar = startBar; bar < rates_total && !IsStopped(); bar++) { // Loop over bars
  
    // (1) Indicator calculations, WMA full period
    double sum = 0.0;                                       // store period sum value for later division
    double wMA = 0.0;                                       // store calculated value for that bar
    int wf = 1;                                             // set start weighting factor to 1
    int sumWf = 0;                                          // set sum of weighting factors to 0
    for(int i = fullPeriod - 1; i >= 0 ; i--) {             // loop over full period for actual bar
//      sum += getPrice(open,high,low,close,(bar - i)) * wf;  // get price applied and add prices over n bars, start at oldest bar, lowest index
      sum += buf[(bar - i)] * wf;                           // get price applied and add prices over n bars, start at oldest bar, lowest index
      sumWf += wf;                                          // add all weighting factors for division
      wf += 1;                                              // increase weighting factors for linear weighting of next newer bar
    }
    wMA = sum / sumWf;                                      // calculate linear weighted averaged value for full MA period
    fullWMABuffer[bar] = wMA;                               // save value to buffer for later use

    // (2) Indicator calculations, WMA half period
    sum = 0.0;                                              // store period sum value for later division
    wMA = 0.0;                                              // store calculated value for that bar
    wf = 1;                                                 // set start weighting factor to 1
    sumWf = 0;                                              // set sum of weighting factors to 0
    for(int i = halfPeriod - 1; i >= 0 ; i--) {             // loop over half period for actual bar
//      sum += getPrice(open,high,low,close,(bar - i)) * wf;  // get price applied and add prices over n bars, start at oldest bar, lowest index
      sum += buf[(bar - i)] * wf;                           // get price applied and add prices over n bars, start at oldest bar, lowest index
      sumWf += wf;                                          // add all weighting factors for division
      wf += 1;                                              // increase weighting factors for linear weighting of next newer bar
    }
    wMA = sum / sumWf;                                      // calculate linear weighted averaged value for half MA period
    halfWMABuffer[bar] = wMA;                               // save value to buffer for later use

    // (3) Indicator calculations, calculate Hull
    sum = 0.0;                                              // store period sum value for later division
    wf = 1;                                                 // set start weighting factor to 1
    sumWf = 0;                                              // set sum of weighting factors to 0
    for(int i = sqrtPeriod - 1; i >= 0 ; i--) {             // loop over half period for actual bar
      sum += (2 * halfWMABuffer[bar - i] - fullWMABuffer[bar - i]) * wf;// calculate sum of sqrt(period) and multiply by weighting factor
      sumWf += wf;                                          // add all weighting factors for division
      wf += 1;                                              // increase weighting factors for linear weighting of next newer bar
    }
    wMA = sum / sumWf;                                      // calculate linear weighted averaged value for half MA period
    valueBuffer[bar] = wMA;                                 // store the HMA for displaying

    // (4) Indicator color calculations, adjust to your needs
    colorBuffer[bar] = getColor(bar);
  }
}

// calculate color for every bar, adjust to your needs
double getColor(int bar) {
  double retval;                                  // store return value
  if(InpColorKind == single_color)                // set single_color
    retval = InpColorIndex;                       // blue
//    retval = InpHullColor;
  else {                                          // set multi_color, default is grey
    retval = 0;                                   // grey
    if(valueBuffer[bar - 1] < valueBuffer[bar])   // if indicator upslope, then green
      retval = 1;                                 // green
    if(valueBuffer[bar - 1] > valueBuffer[bar])   // if indicator downslope, then red
      retval = 2;                                 // red
  }
  return(retval);                                   // return calculated color
}

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

Enjoy to use it.

Alternative:  Pending orders UP - script MetaTrader 5
    📈 ROBOTFX MetaTrader Expert Advisors and Indicators to maximize profits and minimize the risks