I did not understand the source of other Hull MA implementations, so i decide to implement it myself. It has four input parameters:
- InpHmaPeriod = 20
- InpColorKind = single_color
- InpColorIndex = color_index_3
- 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.
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.