From b1d0b12f56fe0c82c7d518afaed2701d31146a4d Mon Sep 17 00:00:00 2001 From: Toh4iem9 Date: Tue, 16 Dec 2025 21:37:15 +0100 Subject: [PATCH] refactor: Optimized for incremental calculation --- Include/MyIncludes/KAMA_Calculator.mqh | 242 ++++++++++++++----------- 1 file changed, 136 insertions(+), 106 deletions(-) diff --git a/Include/MyIncludes/KAMA_Calculator.mqh b/Include/MyIncludes/KAMA_Calculator.mqh index a0cd9ba..955138d 100644 --- a/Include/MyIncludes/KAMA_Calculator.mqh +++ b/Include/MyIncludes/KAMA_Calculator.mqh @@ -1,177 +1,207 @@ //+------------------------------------------------------------------+ //| KAMA_Calculator.mqh| -//| Calculation engine for Kaufman's Adaptive Moving Average. | +//| VERSION 2.00: Optimized for incremental calculation. | //| Copyright 2025, xxxxxxxx | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, xxxxxxxx" #include +//+==================================================================+ +//| CLASS 1: CKamaCalculator (Base Class) | //+==================================================================+ class CKamaCalculator { protected: int m_er_period; double m_fastest_sc, m_slowest_sc; - double m_price[]; - double m_prev_kama; - virtual bool PreparePriceSeries(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]); + //--- Persistent Buffer for Incremental Calculation + double m_price[]; + + //--- Updated: Accepts start_index + 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: - CKamaCalculator(void) : m_prev_kama(0) {}; + CKamaCalculator(void) {}; virtual ~CKamaCalculator(void) {}; bool Init(int er_p, int fast_ema_p, int slow_ema_p); - void Calculate(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[], double &kama_buffer[]); + int GetPeriod(void) const { return m_er_period; } + + //--- Updated: Accepts prev_calculated + 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 &kama_buffer[]); }; //+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -class CKamaCalculator_HA : public CKamaCalculator - { -private: - CHeikinAshi_Calculator m_ha_calculator; -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; - }; - -//+==================================================================+ -//| METHOD IMPLEMENTATIONS | -//+==================================================================+ - -//+------------------------------------------------------------------+ -//| | +//| Init | //+------------------------------------------------------------------+ bool CKamaCalculator::Init(int er_p, int fast_ema_p, int slow_ema_p) { m_er_period = (er_p < 1) ? 1 : er_p; m_fastest_sc = 2.0 / ((fast_ema_p < 1 ? 1 : fast_ema_p) + 1.0); m_slowest_sc = 2.0 / ((slow_ema_p < 1 ? 1 : slow_ema_p) + 1.0); - m_prev_kama = 0; return true; } //+------------------------------------------------------------------+ -//| | +//| Main Calculation (Optimized) | //+------------------------------------------------------------------+ -void CKamaCalculator::Calculate(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[], double &kama_buffer[]) +void CKamaCalculator::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 &kama_buffer[]) { if(rates_total <= m_er_period) return; - if(!PreparePriceSeries(rates_total, price_type, open, high, low, close)) + +//--- 1. Determine Start Index + int start_index; + if(prev_calculated == 0) + start_index = 0; + else + start_index = prev_calculated - 1; + +//--- 2. Resize Buffer + if(ArraySize(m_price) != rates_total) + ArrayResize(m_price, rates_total); + +//--- 3. Prepare Price (Optimized) + if(!PreparePriceSeries(rates_total, start_index, price_type, open, high, low, close)) return; - int start_pos = m_er_period; +//--- 4. Calculate KAMA (Incremental Loop) + int loop_start = MathMax(m_er_period, start_index); - if(ArraySize(kama_buffer) == 0 || kama_buffer[start_pos-1] == 0) + for(int i = loop_start; i < rates_total; i++) { - m_prev_kama = m_price[start_pos-1]; - } + // --- Initialization Step --- + if(i == m_er_period) + { + kama_buffer[i] = m_price[i]; + continue; + } - for(int i = start_pos; i < rates_total; i++) - { + // --- Calculate Efficiency Ratio (ER) --- + // We need m_price[i - m_er_period], which is safe due to persistent buffer double direction = MathAbs(m_price[i] - m_price[i - m_er_period]); double volatility = 0; + for(int j = 0; j < m_er_period; j++) + { volatility += MathAbs(m_price[i - j] - m_price[i - j - 1]); + } double er = (volatility > 0.000001) ? direction / volatility : 0; + + // --- Calculate Scaled Smoothing Constant (SSC) --- double sc = pow(er * (m_fastest_sc - m_slowest_sc) + m_slowest_sc, 2); - kama_buffer[i] = m_prev_kama + sc * (m_price[i] - m_prev_kama); - m_prev_kama = kama_buffer[i]; + // --- Calculate Final AMA --- + // Recursive calculation uses kama_buffer[i-1] which is persistent (from indicator) + kama_buffer[i] = kama_buffer[i-1] + sc * (m_price[i] - kama_buffer[i-1]); } } //+------------------------------------------------------------------+ -//| | +//| Prepare Price (Standard - Optimized) | //+------------------------------------------------------------------+ -bool CKamaCalculator::PreparePriceSeries(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]) +bool CKamaCalculator::PreparePriceSeries(int rates_total, int start_index, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]) { - if(ArraySize(m_price) != rates_total) - if(ArrayResize(m_price, rates_total) != rates_total) - return false; - - switch(price_type) +// Optimized copy loop + for(int i = start_index; i < rates_total; i++) { - case PRICE_CLOSE: - ArrayCopy(m_price, close, 0, 0, rates_total); - break; - 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