From 09ecef928b85857c33e3273b8084b945e4701f23 Mon Sep 17 00:00:00 2001 From: Toh4iem9 Date: Wed, 13 Aug 2025 12:37:18 +0200 Subject: [PATCH] refactor: brute force LinearWeightedMA calculation --- Indicators/MyIndicators/HMA.mq5 | 86 +++++++++++++++++---------------- 1 file changed, 44 insertions(+), 42 deletions(-) diff --git a/Indicators/MyIndicators/HMA.mq5 b/Indicators/MyIndicators/HMA.mq5 index 4a7c941..fb8866e 100644 --- a/Indicators/MyIndicators/HMA.mq5 +++ b/Indicators/MyIndicators/HMA.mq5 @@ -5,9 +5,11 @@ //+------------------------------------------------------------------+ #property copyright "Copyright 2025, xxxxxxxx" #property link "" -#property version "1.00" +#property version "2.00" // Refactored to use direct calculation, no handles #property description "Hull Moving Average (HMA)" +#include + //--- Indicator Window and Plot Properties --- #property indicator_chart_window #property indicator_buffers 4 // HMA, and 3 calculation buffers @@ -21,49 +23,38 @@ #property indicator_width1 2 //--- Input Parameters --- -input int InpPeriodHMA = 14; // HMA Period -input ENUM_APPLIED_PRICE InpAppliedPrice = PRICE_CLOSE; // Applied Price +input int InpPeriodHMA = 14; +input ENUM_APPLIED_PRICE InpAppliedPrice = PRICE_CLOSE; //--- Indicator Buffers --- -double BufferHMA[]; // Final HMA line -double BufferWMA_Half[]; // WMA(period/2) -double BufferWMA_Full[]; // WMA(period) -double BufferRawHMA[]; // Raw HMA (2*WMA_Half - WMA_Full) +double BufferHMA[]; +double BufferWMA_Half[]; +double BufferWMA_Full[]; +double BufferRawHMA[]; +double BufferPrice[]; // Buffer for the source price data //--- Global Variables --- int ExtPeriodHMA; -int handle_wma_half; -int handle_wma_full; - -//--- Include for WMA calculation --- -#include //+------------------------------------------------------------------+ //| Custom indicator initialization function. | //+------------------------------------------------------------------+ void OnInit() { -//--- Validate and store input period ExtPeriodHMA = (InpPeriodHMA < 1) ? 1 : InpPeriodHMA; -//--- Map the buffers SetIndexBuffer(0, BufferHMA, INDICATOR_DATA); SetIndexBuffer(1, BufferWMA_Half, INDICATOR_CALCULATIONS); SetIndexBuffer(2, BufferWMA_Full, INDICATOR_CALCULATIONS); SetIndexBuffer(3, BufferRawHMA, INDICATOR_CALCULATIONS); + SetIndexBuffer(4, BufferPrice, INDICATOR_CALCULATIONS); -//--- Create handles to the standard iWMA indicator - int period_half = (int)MathMax(1, MathRound(ExtPeriodHMA / 2.0)); - handle_wma_half = iMA(_Symbol, _Period, period_half, 0, MODE_LWMA, InpAppliedPrice); - handle_wma_full = iMA(_Symbol, _Period, ExtPeriodHMA, 0, MODE_LWMA, InpAppliedPrice); + ArraySetAsSeries(BufferHMA, false); + ArraySetAsSeries(BufferWMA_Half, false); + ArraySetAsSeries(BufferWMA_Full, false); + ArraySetAsSeries(BufferRawHMA, false); + ArraySetAsSeries(BufferPrice, false); - if(handle_wma_half == INVALID_HANDLE || handle_wma_full == INVALID_HANDLE) - { - Print("Error creating iWMA handles."); - return; - } - -//--- Set indicator display properties IndicatorSetInteger(INDICATOR_DIGITS, _Digits); PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, ExtPeriodHMA + (int)MathFloor(MathSqrt(ExtPeriodHMA)) - 1); IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HMA(%d)", ExtPeriodHMA)); @@ -83,35 +74,46 @@ int OnCalculate(const int rates_total, const long &volume[], const int &spread[]) { -//--- Check if there is enough data if(rates_total < ExtPeriodHMA) return(0); -//--- Check if the source WMA indicators have calculated their data - if(BarsCalculated(handle_wma_half) < rates_total || BarsCalculated(handle_wma_full) < rates_total) - return(0); - -//--- STEP 1 & 2: Get the two WMA values - if(CopyBuffer(handle_wma_half, 0, 0, rates_total, BufferWMA_Half) <= 0 || - CopyBuffer(handle_wma_full, 0, 0, rates_total, BufferWMA_Full) <= 0) +//--- STEP 1: Get the source price data --- +// This replaces the iMA handle logic + switch(InpAppliedPrice) { - return(0); + case PRICE_OPEN: + ArrayCopy(BufferPrice, open); + break; + case PRICE_HIGH: + ArrayCopy(BufferPrice, high); + break; + case PRICE_LOW: + ArrayCopy(BufferPrice, low); + break; + default: + ArrayCopy(BufferPrice, close); + break; + } + +//--- STEP 2: Calculate the two base WMAs + int period_half = (int)MathMax(1, MathRound(ExtPeriodHMA / 2.0)); + for(int i = 0; i < rates_total; i++) + { + if(i >= period_half - 1) + BufferWMA_Half[i] = LinearWeightedMA(i, period_half, BufferPrice); + if(i >= ExtPeriodHMA - 1) + BufferWMA_Full[i] = LinearWeightedMA(i, ExtPeriodHMA, BufferPrice); } //--- STEP 3: Calculate the raw HMA data - for(int i = 0; i < rates_total; i++) + for(int i = ExtPeriodHMA - 1; i < rates_total; i++) { BufferRawHMA[i] = 2 * BufferWMA_Half[i] - BufferWMA_Full[i]; } -//--- STEP 4: Smooth the raw HMA with another WMA to get the final HMA +//--- STEP 4: Smooth the raw HMA with the final WMA int period_sqrt = (int)MathMax(1, MathRound(MathSqrt(ExtPeriodHMA))); - -// We use our stable, manual calculation loop for the final smoothing - ArraySetAsSeries(BufferRawHMA, false); // WMA function needs non-timeseries - ArraySetAsSeries(BufferHMA, false); - - for(int i = ExtPeriodHMA - 1; i < rates_total; i++) + for(int i = ExtPeriodHMA + period_sqrt - 2; i < rates_total; i++) { BufferHMA[i] = LinearWeightedMA(i, period_sqrt, BufferRawHMA); }