From 3940eadb8125f10e35c75e063cec4d48fbf4514d Mon Sep 17 00:00:00 2001 From: Toh4iem9 Date: Thu, 1 Jan 2026 13:41:59 +0100 Subject: [PATCH] refactor(indicators): Restored Trend/Level outputs --- Include/MyIncludes/Holt_Engine.mqh | 220 +++++++++++++++++------------ 1 file changed, 133 insertions(+), 87 deletions(-) diff --git a/Include/MyIncludes/Holt_Engine.mqh b/Include/MyIncludes/Holt_Engine.mqh index 5c4e2ec..ab94cea 100644 --- a/Include/MyIncludes/Holt_Engine.mqh +++ b/Include/MyIncludes/Holt_Engine.mqh @@ -1,6 +1,7 @@ //+------------------------------------------------------------------+ //| Holt_Engine.mqh | //| Core calculation engine for all Holt-based indicators. | +//| VERSION 2.10: Restored Trend/Level outputs. | //| Copyright 2025, xxxxxxxx | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, xxxxxxxx" @@ -8,9 +9,7 @@ #include //+==================================================================+ -//| | //| CLASS 1: CHoltEngine (Base Class) | -//| | //+==================================================================+ class CHoltEngine { @@ -20,16 +19,21 @@ protected: double m_beta; int m_forecast_period; + //--- Persistent Buffers double m_price[]; + double m_level[]; + double m_trend[]; - virtual bool PreparePriceSeries(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]); + virtual bool PreparePriceSeries(int rates_total, int start_index, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]); public: CHoltEngine(void); virtual ~CHoltEngine(void) {}; bool Init(int period, double alpha, double beta, int forecast_p); - void Calculate(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[], + + //--- Updated: Added trend_out and level_out back to signature + void Calculate(int rates_total, int prev_calculated, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[], double &forecast_out[], double &trend_out[], double &level_out[], double &upper_band_out[], double &lower_band_out[]); }; @@ -45,9 +49,9 @@ CHoltEngine::CHoltEngine(void) : m_period(0), m_alpha(0.1), m_beta(0.05), m_fore //+------------------------------------------------------------------+ bool CHoltEngine::Init(int period, double alpha, double beta, int forecast_p) { - m_period = (period < 2) ? 2 : period; - m_alpha = (alpha <= 0) ? 0.0001 : (alpha >= 1) ? 0.9999 : alpha; - m_beta = (beta <= 0) ? 0.0001 : (beta >= 1) ? 0.9999 : beta; + m_period = 10; // Safe minimum + m_alpha = (alpha <= 0) ? 0.1 : (alpha > 1) ? 1.0 : alpha; + m_beta = (beta <= 0) ? 0.05 : (beta > 1) ? 1.0 : beta; m_forecast_period = (forecast_p < 1) ? 1 : forecast_p; return true; } @@ -55,121 +59,163 @@ bool CHoltEngine::Init(int period, double alpha, double beta, int forecast_p) //+------------------------------------------------------------------+ //| CHoltEngine: Main Calculation Method | //+------------------------------------------------------------------+ -void CHoltEngine::Calculate(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[], +void CHoltEngine::Calculate(int rates_total, int prev_calculated, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[], double &forecast_out[], double &trend_out[], double &level_out[], double &upper_band_out[], double &lower_band_out[]) { - if(rates_total < m_period) + if(rates_total < 2) return; - ArrayResize(m_price, rates_total); - if(!PreparePriceSeries(rates_total, price_type, open, high, low, close)) - return; + int start_index; + if(prev_calculated == 0) + start_index = 0; + else + start_index = prev_calculated - 1; - level_out[0] = m_price[0]; - trend_out[0] = m_price[1] - m_price[0]; - forecast_out[0] = level_out[0] + trend_out[0]; - level_out[1] = m_price[1]; - trend_out[1] = m_beta * (level_out[1] - level_out[0]) + (1 - m_beta) * trend_out[0]; - forecast_out[1] = level_out[1] + trend_out[1]; - - for(int i = 2; i < rates_total; i++) + if(ArraySize(m_price) != rates_total) { - level_out[i] = m_alpha * m_price[i] + (1 - m_alpha) * (level_out[i-1] + trend_out[i-1]); - trend_out[i] = m_beta * (level_out[i] - level_out[i-1]) + (1 - m_beta) * trend_out[i-1]; - forecast_out[i] = level_out[i] + trend_out[i]; - upper_band_out[i] = level_out[i] + m_forecast_period * trend_out[i]; - lower_band_out[i] = level_out[i] - m_forecast_period * trend_out[i]; + ArrayResize(m_price, rates_total); + ArrayResize(m_level, rates_total); + ArrayResize(m_trend, rates_total); + } + + if(!PreparePriceSeries(rates_total, start_index, price_type, open, high, low, close)) + return; + + int loop_start = MathMax(2, start_index); + + if(loop_start == 2) + { + m_level[0] = m_price[0]; + m_trend[0] = m_price[1] - m_price[0]; + forecast_out[0] = m_level[0] + m_trend[0]; + + m_level[1] = m_price[1]; + m_trend[1] = m_beta * (m_level[1] - m_level[0]) + (1 - m_beta) * m_trend[0]; + forecast_out[1] = m_level[1] + m_trend[1]; + + // Fill outputs for first bars + trend_out[0] = m_trend[0]; + level_out[0] = m_level[0]; + upper_band_out[0] = forecast_out[0]; + lower_band_out[0] = forecast_out[0]; + + trend_out[1] = m_trend[1]; + level_out[1] = m_level[1]; + upper_band_out[1] = forecast_out[1]; + lower_band_out[1] = forecast_out[1]; + } + + for(int i = loop_start; i < rates_total; i++) + { + m_level[i] = m_alpha * m_price[i] + (1.0 - m_alpha) * (m_level[i-1] + m_trend[i-1]); + m_trend[i] = m_beta * (m_level[i] - m_level[i-1]) + (1.0 - m_beta) * m_trend[i-1]; + + forecast_out[i] = m_level[i] + m_trend[i]; + + // Copy internal state to output buffers + trend_out[i] = m_trend[i]; + level_out[i] = m_level[i]; + + double width = m_forecast_period * MathAbs(m_trend[i]); + upper_band_out[i] = forecast_out[i] + width; + lower_band_out[i] = forecast_out[i] - width; } } //+------------------------------------------------------------------+ -//| CHoltEngine: Prepares the standard source price series. | +//| Prepare Price (Standard - Optimized) | //+------------------------------------------------------------------+ -bool CHoltEngine::PreparePriceSeries(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]) +bool CHoltEngine::PreparePriceSeries(int rates_total, int start_index, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]) { - switch(price_type) + for(int i = start_index; i < rates_total; i++) { - case PRICE_OPEN: - ArrayCopy(m_price, open, 0, 0, rates_total); - break; - case PRICE_HIGH: - ArrayCopy(m_price, high, 0, 0, rates_total); - break; - case PRICE_LOW: - ArrayCopy(m_price, low, 0, 0, rates_total); - break; - case PRICE_MEDIAN: - for(int i=0; i