From c6e6d768375358589efb88e997a2c0b5a5e8d602 Mon Sep 17 00:00:00 2001 From: Toh4iem9 Date: Mon, 1 Dec 2025 15:39:59 +0100 Subject: [PATCH] refactor: Optimized for incremental calculation --- Include/MyIncludes/ATR_Calculator.mqh | 138 ++++++++++++++++---------- 1 file changed, 83 insertions(+), 55 deletions(-) diff --git a/Include/MyIncludes/ATR_Calculator.mqh b/Include/MyIncludes/ATR_Calculator.mqh index e1d3450..6fad3ad 100644 --- a/Include/MyIncludes/ATR_Calculator.mqh +++ b/Include/MyIncludes/ATR_Calculator.mqh @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| ATR_Calculator.mqh | -//| VERSION 2.10: Added Percent mode. | +//| VERSION 2.21: Fixed ATR Percent incremental bug. | //| Copyright 2025, xxxxxxxx | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, xxxxxxxx" @@ -14,9 +14,7 @@ enum ENUM_CANDLE_SOURCE { CANDLE_STANDARD, CANDLE_HEIKIN_ASHI }; enum ENUM_ATR_DISPLAY_MODE { ATR_POINTS, ATR_PERCENT }; //+==================================================================+ -//| | //| CLASS 1: CATRCalculator (Base Class) | -//| | //+==================================================================+ class CATRCalculator { @@ -24,21 +22,26 @@ protected: int m_atr_period; ENUM_ATR_DISPLAY_MODE m_display_mode; - //--- Virtual method for preparing the raw True Range values. - virtual void PrepareTrueRange(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], double &tr_buffer[]); + //--- Persistent Buffer for True Range and Raw ATR + double m_tr[]; + double m_atr_raw[]; // Stores ATR in points for recursion + + //--- Updated: Accepts start_index + virtual bool PrepareTrueRange(int rates_total, int start_index, const double &open[], const double &high[], const double &low[], const double &close[]); public: CATRCalculator(void) {}; virtual ~CATRCalculator(void) {}; - //--- Public methods bool Init(int period, ENUM_ATR_DISPLAY_MODE mode); int GetPeriod(void) const { return m_atr_period; } - void Calculate(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], double &atr_buffer[]); + + //--- Updated: Accepts prev_calculated + void Calculate(int rates_total, int prev_calculated, const double &open[], const double &high[], const double &low[], const double &close[], double &atr_buffer[]); }; //+------------------------------------------------------------------+ -//| CATRCalculator: Initialization | +//| Init | //+------------------------------------------------------------------+ bool CATRCalculator::Init(int period, ENUM_ATR_DISPLAY_MODE mode) { @@ -48,100 +51,125 @@ bool CATRCalculator::Init(int period, ENUM_ATR_DISPLAY_MODE mode) } //+------------------------------------------------------------------+ -//| CATRCalculator: Main Calculation Method (Shared Logic) | +//| Main Calculation (Optimized) | //+------------------------------------------------------------------+ -void CATRCalculator::Calculate(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], double &atr_buffer[]) +void CATRCalculator::Calculate(int rates_total, int prev_calculated, const double &open[], const double &high[], const double &low[], const double &close[], double &atr_buffer[]) { if(rates_total <= m_atr_period) return; -//--- STEP 1: Calculate True Range (delegated to virtual method) - double tr[]; - PrepareTrueRange(rates_total, open, high, low, close, tr); +//--- 1. Determine Start Index + int start_index; + if(prev_calculated == 0) + start_index = 0; + else + start_index = prev_calculated - 1; -//--- STEP 2: Calculate ATR (Wilder's Smoothing) - for(int i = 1; i < rates_total; i++) +//--- 2. Resize Buffers + if(ArraySize(m_tr) != rates_total) { - if(i == m_atr_period) // Initialization with a simple average of TR + ArrayResize(m_tr, rates_total); + ArrayResize(m_atr_raw, rates_total); + } + +//--- 3. Prepare True Range (Optimized) + if(!PrepareTrueRange(rates_total, start_index, open, high, low, close)) + return; + +//--- 4. Calculate ATR (Wilder's Smoothing) using Internal Raw Buffer + int loop_start = MathMax(m_atr_period, start_index); + + for(int i = loop_start; i < rates_total; i++) + { + if(i == m_atr_period) // Initialization { double sum_tr = 0; for(int j = 1; j <= m_atr_period; j++) - sum_tr += tr[j]; - atr_buffer[i] = sum_tr / m_atr_period; + sum_tr += m_tr[j]; + m_atr_raw[i] = sum_tr / m_atr_period; } else - if(i > m_atr_period) // Recursive calculation - { - atr_buffer[i] = (atr_buffer[i-1] * (m_atr_period - 1) + tr[i]) / m_atr_period; - } + // Recursive calculation uses m_atr_raw[i-1] which is always in POINTS + m_atr_raw[i] = (m_atr_raw[i-1] * (m_atr_period - 1) + m_tr[i]) / m_atr_period; } -//--- Step 3: Convert to percentage if requested --- - if(m_display_mode == ATR_PERCENT) +//--- 5. Output to Buffer (Convert if needed) +// We must update the output buffer from loop_start + for(int i = loop_start; i < rates_total; i++) { - for(int i = m_atr_period; i < rates_total; i++) + if(m_display_mode == ATR_PERCENT) { if(close[i] > 0) - atr_buffer[i] = (atr_buffer[i] / close[i]) * 100.0; + atr_buffer[i] = (m_atr_raw[i] / close[i]) * 100.0; else atr_buffer[i] = 0; } + else + { + atr_buffer[i] = m_atr_raw[i]; + } } } //+------------------------------------------------------------------+ -//| CATRCalculator: Prepares raw TR from standard prices. | +//| Prepare True Range (Standard - Optimized) | //+------------------------------------------------------------------+ -void CATRCalculator::PrepareTrueRange(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], double &tr_buffer[]) +bool CATRCalculator::PrepareTrueRange(int rates_total, int start_index, const double &open[], const double &high[], const double &low[], const double &close[]) { - ArrayResize(tr_buffer, rates_total); - for(int i = 1; i < rates_total; i++) + int i = (start_index < 1) ? 1 : start_index; + + for(; i < rates_total; i++) { double range1 = high[i] - low[i]; double range2 = MathAbs(high[i] - close[i-1]); double range3 = MathAbs(low[i] - close[i-1]); - tr_buffer[i] = MathMax(range1, MathMax(range2, range3)); + m_tr[i] = MathMax(range1, MathMax(range2, range3)); } + return true; } //+==================================================================+ -//| | //| CLASS 2: CATRCalculator_HA (Heikin Ashi) | -//| | //+==================================================================+ class CATRCalculator_HA : public CATRCalculator { private: CHeikinAshi_Calculator m_ha_calculator; + // Internal HA buffers + double m_ha_open[], m_ha_high[], m_ha_low[], m_ha_close[]; + protected: - //--- Overridden method to prepare Heikin Ashi based TR - virtual void PrepareTrueRange(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], double &tr_buffer[]) override; + virtual bool PrepareTrueRange(int rates_total, int start_index, const double &open[], const double &high[], const double &low[], const double &close[]) override; }; //+------------------------------------------------------------------+ -//| CATRCalculator_HA: Prepares raw TR from HA prices. | +//| Prepare True Range (Heikin Ashi - Optimized) | //+------------------------------------------------------------------+ -void CATRCalculator_HA::PrepareTrueRange(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], double &tr_buffer[]) +bool CATRCalculator_HA::PrepareTrueRange(int rates_total, int start_index, const double &open[], const double &high[], const double &low[], const double &close[]) { -//--- Intermediate Heikin Ashi Buffers - double ha_open[], ha_high[], ha_low[], ha_close[]; - ArrayResize(ha_open, rates_total); - ArrayResize(ha_high, rates_total); - ArrayResize(ha_low, rates_total); - ArrayResize(ha_close, rates_total); - -//--- Calculate the HA candles first - m_ha_calculator.Calculate(rates_total, open, high, low, close, ha_open, ha_high, ha_low, ha_close); - -//--- Now, calculate TR using the HA candles - ArrayResize(tr_buffer, rates_total); - for(int i = 1; i < rates_total; i++) +// Resize internal HA buffers + if(ArraySize(m_ha_open) != rates_total) { - double range1 = ha_high[i] - ha_low[i]; - double range2 = MathAbs(ha_high[i] - ha_close[i-1]); - double range3 = MathAbs(ha_low[i] - ha_close[i-1]); - tr_buffer[i] = MathMax(range1, MathMax(range2, range3)); + ArrayResize(m_ha_open, rates_total); + ArrayResize(m_ha_high, rates_total); + ArrayResize(m_ha_low, rates_total); + ArrayResize(m_ha_close, rates_total); } + +//--- STRICT CALL: Use the optimized 10-param HA calculation + m_ha_calculator.Calculate(rates_total, start_index, open, high, low, close, + m_ha_open, m_ha_high, m_ha_low, m_ha_close); + +//--- Calculate TR using HA candles (Optimized loop) + int i = (start_index < 1) ? 1 : start_index; + + for(; i < rates_total; i++) + { + double range1 = m_ha_high[i] - m_ha_low[i]; + double range2 = MathAbs(m_ha_high[i] - m_ha_close[i-1]); + double range3 = MathAbs(m_ha_low[i] - m_ha_close[i-1]); + m_tr[i] = MathMax(range1, MathMax(range2, range3)); + } + return true; } //+------------------------------------------------------------------+ -//+------------------------------------------------------------------+