//+------------------------------------------------------------------+ //| ZeroLag_EMA_Calculator.mqh | //| Copyright 2026, xxxxxxxx| //+------------------------------------------------------------------+ #property copyright "Copyright 2026, xxxxxxxx" #property version "3.10" // Upgraded with strict internal chronological sorting safeguards for recursive ZLEMA buffers #ifndef ZEROLAG_EMA_CALCULATOR_MQH #define ZEROLAG_EMA_CALCULATOR_MQH #include //+==================================================================+ //| CLASS 1: CZeroLagEMACalculator (Base Class) | //+==================================================================+ class CZeroLagEMACalculator { protected: int m_period; bool m_optimize_gain; double m_gain_limit; //--- Persistent Buffers for Incremental Calculation double m_price[]; //--- State Buffers for Standard Mode double m_ema1[]; double m_ema2[]; //--- State Buffers for Optimized Gain Mode double m_ema[]; double m_ec[]; 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: CZeroLagEMACalculator(void) {}; virtual ~CZeroLagEMACalculator(void) {}; bool Init(int period, bool optimize_gain, double gain_limit); 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 &zlema_buffer[]); }; //+------------------------------------------------------------------+ //| Init | //+------------------------------------------------------------------+ 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; } //+------------------------------------------------------------------+ //| Main Calculation (Optimized) | //+------------------------------------------------------------------+ void CZeroLagEMACalculator::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 &zlema_buffer[]) { if(rates_total < m_period * 2) return; int start_index = (prev_calculated == 0) ? 0 : prev_calculated - 1; // Resize Buffers and force strict chronological sorting if(ArraySize(m_price) != rates_total) { ArrayResize(m_price, rates_total); ArraySetAsSeries(m_price, false); if(!m_optimize_gain) { ArrayResize(m_ema1, rates_total); ArrayResize(m_ema2, rates_total); ArraySetAsSeries(m_ema1, false); ArraySetAsSeries(m_ema2, false); } else { ArrayResize(m_ema, rates_total); ArrayResize(m_ec, rates_total); ArraySetAsSeries(m_ema, false); ArraySetAsSeries(m_ec, false); } } if(!PreparePriceSeries(rates_total, start_index, price_type, open, high, low, close)) return; double alpha = 2.0 / (m_period + 1.0); if(!m_optimize_gain) { // --- Standard (Double EMA) Zero-Lag EMA Calculation --- int loop_start = MathMax(m_period, start_index); // Initialization if(loop_start == m_period) { double sum=0; for(int j=0; j