From e5aebc718428b389496249ddcfd39bf873f5733a Mon Sep 17 00:00:00 2001 From: Toh4iem9 Date: Thu, 23 Oct 2025 14:32:14 +0200 Subject: [PATCH] refactor: Advanced Settings --- Include/MyIncludes/ZeroLag_EMA_Calculator.mqh | 129 +++++++++++------- 1 file changed, 83 insertions(+), 46 deletions(-) diff --git a/Include/MyIncludes/ZeroLag_EMA_Calculator.mqh b/Include/MyIncludes/ZeroLag_EMA_Calculator.mqh index 02dd007..8064eca 100644 --- a/Include/MyIncludes/ZeroLag_EMA_Calculator.mqh +++ b/Include/MyIncludes/ZeroLag_EMA_Calculator.mqh @@ -1,6 +1,7 @@ //+------------------------------------------------------------------+ //| ZeroLag_EMA_Calculator.mqh | //| Calculation engine for the John Ehlers' Zero-Lag EMA. | +//| Supports standard (double EMA) and optimized gain modes. | //| Copyright 2025, xxxxxxxx | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, xxxxxxxx" @@ -16,6 +17,8 @@ class CZeroLagEMACalculator { protected: int m_period; + bool m_optimize_gain; + double m_gain_limit; double m_price[]; virtual bool PreparePriceSeries(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]); @@ -24,14 +27,16 @@ public: CZeroLagEMACalculator(void) {}; virtual ~CZeroLagEMACalculator(void) {}; - bool Init(int period); + bool Init(int period, bool optimize_gain, double gain_limit); void Calculate(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[], double &zlema_buffer[]); }; //+------------------------------------------------------------------+ -bool CZeroLagEMACalculator::Init(int period) +bool CZeroLagEMACalculator::Init(int period, bool optimize_gain, double gain_limit) { m_period = (period < 1) ? 1 : period; + m_optimize_gain = optimize_gain; + m_gain_limit = gain_limit; return true; } @@ -45,56 +50,88 @@ void CZeroLagEMACalculator::Calculate(int rates_total, ENUM_APPLIED_PRICE price_ double alpha = 2.0 / (m_period + 1.0); -// --- Intermediate buffers for the two EMA stages --- - double ema1_buffer[], ema2_buffer[]; - ArrayResize(ema1_buffer, rates_total); - ArrayResize(ema2_buffer, rates_total); - -// --- State variables for recursive calculations --- - double ema1_prev = 0; - double ema2_prev = 0; - -// --- Full recalculation loop for stability --- - for(int i = 0; i < rates_total; i++) + if(!m_optimize_gain) { - // Initialize first value with a simple average - if(i == m_period - 1) - { - double sum = 0; - for(int j=0; j= m_period) + for(int i = 0; i < rates_total; i++) { - // Step 1: Calculate first EMA on price - double ema1 = m_price[i] * alpha + (1.0 - alpha) * ema1_prev; - ema1_buffer[i] = ema1; - - // Initialize second EMA - if(i == m_period * 2 - 2) + if(i == m_period - 1) { - double sum = 0; + double sum=0; for(int j=0; j= m_period * 2 - 1) + if(i >= m_period) { - // Step 2: Calculate second EMA on the first EMA - double ema2 = ema1_buffer[i] * alpha + (1.0 - alpha) * ema2_prev; - ema2_buffer[i] = ema2; + double ema1 = m_price[i] * alpha + (1.0 - alpha) * ema1_prev; + ema1_buffer[i] = ema1; + if(i == m_period * 2 - 2) + { + double sum=0; + for(int j=0; j= m_period * 2 - 1) + { + double ema2 = ema1_buffer[i] * alpha + (1.0 - alpha) * ema2_prev; + zlema_buffer[i] = 2.0 * ema1 - ema2; + ema2_prev = ema2; + } + ema1_prev = ema1; + } + } + } + else + { + // --- Ehlers' Optimized Gain (Error Correcting) Calculation --- + double ema_buffer[]; + ArrayResize(ema_buffer, rates_total); + double ema_prev = 0; + double ec_prev = 0; - // Step 3 & 4: Calculate the difference (error) and add it back to the first EMA - double diff = ema1_buffer[i] - ema2_buffer[i]; - zlema_buffer[i] = ema1_buffer[i] + diff; + for(int i = 0; i < rates_total; i++) + { + // Calculate standard EMA first + if(i > 0) + ema_buffer[i] = m_price[i] * alpha + (1.0 - alpha) * ema_prev; + else + ema_buffer[i] = m_price[i]; + ema_prev = ema_buffer[i]; - ema2_prev = ema2; + if(i < 1) + { + zlema_buffer[i] = m_price[i]; + ec_prev = m_price[i]; + continue; } - ema1_prev = ema1; + // Find the BestGain for the current bar + double least_error = 1e10; + double best_gain = 0; + int gain_steps = (int)(m_gain_limit * 10); + + for(int j = -gain_steps; j <= gain_steps; j++) + { + double current_gain = j / 10.0; + double ec_trial = alpha * (ema_buffer[i] + current_gain * (m_price[i] - ec_prev)) + (1.0 - alpha) * ec_prev; + double error = m_price[i] - ec_trial; + if(fabs(error) < least_error) + { + least_error = fabs(error); + best_gain = current_gain; + } + } + + // Calculate the final ZLEMA (EC) with the BestGain + zlema_buffer[i] = alpha * (ema_buffer[i] + best_gain * (m_price[i] - ec_prev)) + (1.0 - alpha) * ec_prev; + ec_prev = zlema_buffer[i]; } } } @@ -134,8 +171,9 @@ bool CZeroLagEMACalculator::PreparePriceSeries(int rates_total, ENUM_APPLIED_PRI } return true; } - -//+==================================================================+ +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ class CZeroLagEMACalculator_HA : public CZeroLagEMACalculator { private: @@ -143,7 +181,8 @@ private: protected: virtual bool PreparePriceSeries(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]) override; }; - +//+------------------------------------------------------------------+ +//| | //+------------------------------------------------------------------+ bool CZeroLagEMACalculator_HA::PreparePriceSeries(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]) { @@ -185,5 +224,3 @@ bool CZeroLagEMACalculator_HA::PreparePriceSeries(int rates_total, ENUM_APPLIED_ } return true; } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+