From da4a8b3cf7bc0ee687f48a521c53877c235ef6dd Mon Sep 17 00:00:00 2001 From: Toh4iem9 Date: Sun, 28 Dec 2025 08:32:01 +0100 Subject: [PATCH] refactor: Optimized for incremental calculation --- Include/MyIncludes/Aroon_Calculator.mqh | 147 ++++++++++++------------ 1 file changed, 72 insertions(+), 75 deletions(-) diff --git a/Include/MyIncludes/Aroon_Calculator.mqh b/Include/MyIncludes/Aroon_Calculator.mqh index a756fcf..19d8484 100644 --- a/Include/MyIncludes/Aroon_Calculator.mqh +++ b/Include/MyIncludes/Aroon_Calculator.mqh @@ -1,39 +1,42 @@ //+------------------------------------------------------------------+ //| Aroon_Calculator.mqh | //| Calculation engine for Standard and Heikin Ashi Aroon. | -//| Copyright 2025, xxxxxxxx| +//| VERSION 2.00: Optimized for incremental calculation. | +//| Copyright 2025, xxxxxxxx | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, xxxxxxxx" #include //+==================================================================+ -//| | //| CLASS 1: CAroonCalculator (Base Class) | -//| | //+==================================================================+ class CAroonCalculator { protected: int m_aroon_period; - //--- Virtual method for preparing the source high/low data. - virtual void PrepareSourceData(int rates_total, const double &high[], const double &low[], - double &source_high[], double &source_low[]); + //--- Persistent Buffers for Incremental Calculation + double m_high_buffer[]; + double m_low_buffer[]; + + //--- Updated: Accepts start_index and all price arrays + virtual bool PrepareSourceData(int rates_total, int start_index, const double &open[], const double &high[], const double &low[], const double &close[]); public: CAroonCalculator(void) {}; virtual ~CAroonCalculator(void) {}; - //--- Public methods bool Init(int period); int GetPeriod(void) const { return m_aroon_period; } - void Calculate(int rates_total, const double &high[], const double &low[], + + //--- 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 &aroon_up_buffer[], double &aroon_down_buffer[]); }; //+------------------------------------------------------------------+ -//| CAroonCalculator: Initialization | +//| Init | //+------------------------------------------------------------------+ bool CAroonCalculator::Init(int period) { @@ -42,124 +45,118 @@ bool CAroonCalculator::Init(int period) } //+------------------------------------------------------------------+ -//| CAroonCalculator: Main Calculation Method (Shared Logic) | +//| Main Calculation (Optimized) | //+------------------------------------------------------------------+ -void CAroonCalculator::Calculate(int rates_total, const double &high[], const double &low[], +void CAroonCalculator::Calculate(int rates_total, int prev_calculated, const double &open[], const double &high[], const double &low[], const double &close[], double &aroon_up_buffer[], double &aroon_down_buffer[]) { if(rates_total < m_aroon_period) return; -//--- STEP 1: Get the source high/low data (standard or HA) - double source_high[], source_low[]; - PrepareSourceData(rates_total, high, low, source_high, source_low); +//--- 1. Determine Start Index + int start_index; + if(prev_calculated == 0) + start_index = 0; + else + start_index = prev_calculated - 1; -//--- STEP 2: Calculate Aroon Up and Aroon Down for each bar -// Start from the first bar where a full period is available. - for(int i = m_aroon_period - 1; i < rates_total; i++) +//--- 2. Resize Internal Buffers + if(ArraySize(m_high_buffer) != rates_total) + { + ArrayResize(m_high_buffer, rates_total); + ArrayResize(m_low_buffer, rates_total); + } + +//--- 3. Prepare Source Data (Optimized) + if(!PrepareSourceData(rates_total, start_index, open, high, low, close)) + return; + +//--- 4. Calculate Aroon (Incremental Loop) + int loop_start = MathMax(m_aroon_period - 1, start_index); + + for(int i = loop_start; i < rates_total; i++) { double highest_val = -DBL_MAX; int highest_idx = -1; double lowest_val = DBL_MAX; int lowest_idx = -1; - // Inner loop: Look back over the defined period to find the highest high and lowest low. - // The period is from [i - period + 1] to [i]. + // Inner loop: Look back over the defined period + // Optimization: For very large periods, this inner loop is O(N*M). + // For standard periods (14-25), it's fast enough. for(int j = i - m_aroon_period + 1; j <= i; j++) { - // Use '>=' to ensure that if multiple bars have the same high, - // the most recent one is chosen. This is crucial for the "time since" concept. - if(source_high[j] >= highest_val) + if(m_high_buffer[j] >= highest_val) { - highest_val = source_high[j]; + highest_val = m_high_buffer[j]; highest_idx = j; } - // Use '<=' for the same reason for the low. - if(source_low[j] <= lowest_val) + if(m_low_buffer[j] <= lowest_val) { - lowest_val = source_low[j]; + lowest_val = m_low_buffer[j]; lowest_idx = j; } } - // STEP 3: Calculate the number of bars that have passed since these extremes occurred. - // If the extreme was on the current bar (i), the result is 0. - // If it was on the previous bar (i-1), the result is 1, and so on. int bars_since_high = i - highest_idx; int bars_since_low = i - lowest_idx; - // STEP 4: Apply the original Aroon formula by Tushar Chande. - // The formula converts the "bars since" value into a percentage scale from 0 to 100. - // A value of 100 means the extreme occurred on the current bar (0 bars ago). - // A value of 0 means the extreme occurred 'period' or more bars ago. aroon_up_buffer[i] = (double)(m_aroon_period - bars_since_high) / m_aroon_period * 100.0; aroon_down_buffer[i] = (double)(m_aroon_period - bars_since_low) / m_aroon_period * 100.0; } } //+------------------------------------------------------------------+ -//| CAroonCalculator: Prepares source data from standard prices. | +//| Prepare Source Data (Standard - Optimized) | //+------------------------------------------------------------------+ -void CAroonCalculator::PrepareSourceData(int rates_total, const double &high[], const double &low[], - double &source_high[], double &source_low[]) +bool CAroonCalculator::PrepareSourceData(int rates_total, int start_index, const double &open[], const double &high[], const double &low[], const double &close[]) { - ArrayResize(source_high, rates_total); - ArrayResize(source_low, rates_total); - ArrayCopy(source_high, high, 0, 0, rates_total); - ArrayCopy(source_low, low, 0, 0, rates_total); + for(int i = start_index; i < rates_total; i++) + { + m_high_buffer[i] = high[i]; + m_low_buffer[i] = low[i]; + } + return true; } //+==================================================================+ -//| | //| CLASS 2: CAroonCalculator_HA (Heikin Ashi) | -//| | //+==================================================================+ class CAroonCalculator_HA : public CAroonCalculator { private: - CHeikinAshi_Calculator m_ha_calculator; // Instance of the HA calculator tool + 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 source data - virtual void PrepareSourceData(int rates_total, const double &high[], const double &low[], - double &source_high[], double &source_low[]) override; + virtual bool PrepareSourceData(int rates_total, int start_index, const double &open[], const double &high[], const double &low[], const double &close[]) override; }; //+------------------------------------------------------------------+ -//| CAroonCalculator_HA: Prepares source data from HA prices. | +//| Prepare Source Data (Heikin Ashi - Optimized) | //+------------------------------------------------------------------+ -void CAroonCalculator_HA::PrepareSourceData(int rates_total, const double &high[], const double &low[], - double &source_high[], double &source_low[]) +bool CAroonCalculator_HA::PrepareSourceData(int rates_total, int start_index, const double &open[], const double &high[], const double &low[], const double &close[]) { -//--- We need open and close to calculate HA candles - MqlRates rates[]; - if(CopyRates(_Symbol, _Period, 0, rates_total, rates) <= 0) - return; - - double open[], close[]; - ArrayResize(open, rates_total); - ArrayResize(close, rates_total); - for(int i=0; i