diff --git a/Include/MyIncludes/AMA_TrendActivity_Calculator.mqh b/Include/MyIncludes/AMA_TrendActivity_Calculator.mqh index 95065d5..25baceb 100644 --- a/Include/MyIncludes/AMA_TrendActivity_Calculator.mqh +++ b/Include/MyIncludes/AMA_TrendActivity_Calculator.mqh @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| AMA_TrendActivity_Calculator.mqh | -//| Calculation engine for Standard and Heikin Ashi AMA Activity. | +//| VERSION 2.10: Optimized for incremental calculation. | //| Copyright 2025, xxxxxxxx | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, xxxxxxxx" @@ -8,9 +8,7 @@ #include //+==================================================================+ -//| | //| CLASS 1: CActivityCalculator (Base Class) | -//| | //+==================================================================+ class CActivityCalculator { @@ -18,24 +16,28 @@ protected: int m_ama_period, m_fast_period, m_slow_period, m_atr_period, m_smoothing_period; double m_pi_div_2; - //--- Internal buffers for source data + //--- Persistent Buffers for Incremental Calculation double m_ama_price[]; double m_atr_high[], m_atr_low[], m_atr_close[]; - //--- Virtual method for preparing all necessary source data series. - virtual bool PrepareSourceData(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], ENUM_APPLIED_PRICE price_type); + //--- Intermediate Calculation Buffers (Must persist state) + double m_buffer_ama[]; + double m_buffer_atr[]; + double m_scaled_activity[]; + + //--- Virtual method for preparing source data + virtual bool PrepareSourceData(int rates_total, int start_index, const double &open[], const double &high[], const double &low[], const double &close[], ENUM_APPLIED_PRICE price_type); public: CActivityCalculator(void) {}; virtual ~CActivityCalculator(void) {}; - //--- Public methods bool Init(int ama_p, int fast_p, int slow_p, int atr_p, int smooth_p); - void Calculate(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], ENUM_APPLIED_PRICE price_type, double &activity_buffer[]); + void Calculate(int rates_total, int prev_calculated, const double &open[], const double &high[], const double &low[], const double &close[], ENUM_APPLIED_PRICE price_type, double &activity_buffer[]); }; //+------------------------------------------------------------------+ -//| CActivityCalculator: Initialization | +//| Init | //+------------------------------------------------------------------+ bool CActivityCalculator::Init(int ama_p, int fast_p, int slow_p, int atr_p, int smooth_p) { @@ -49,195 +51,225 @@ bool CActivityCalculator::Init(int ama_p, int fast_p, int slow_p, int atr_p, int } //+------------------------------------------------------------------+ -//| CActivityCalculator: Main Calculation Method (Shared Logic) | +//| Main Calculation (Optimized) | //+------------------------------------------------------------------+ -void CActivityCalculator::Calculate(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], ENUM_APPLIED_PRICE price_type, double &activity_buffer[]) +void CActivityCalculator::Calculate(int rates_total, int prev_calculated, const double &open[], const double &high[], const double &low[], const double &close[], ENUM_APPLIED_PRICE price_type, double &activity_buffer[]) { int start_pos = m_ama_period + m_atr_period + m_smoothing_period; if(rates_total <= start_pos) return; -//--- STEP 1: Prepare all source data (delegated to virtual method) - if(!PrepareSourceData(rates_total, open, high, low, close, price_type)) +//--- 1. Determine Start Index + int start_index; + if(prev_calculated == 0) + start_index = 0; + else + start_index = prev_calculated - 1; + +//--- 2. Resize Buffers + if(ArraySize(m_ama_price) != rates_total) + { + ArrayResize(m_ama_price, rates_total); + ArrayResize(m_atr_high, rates_total); + ArrayResize(m_atr_low, rates_total); + ArrayResize(m_atr_close, rates_total); + + ArrayResize(m_buffer_ama, rates_total); + ArrayResize(m_buffer_atr, rates_total); + ArrayResize(m_scaled_activity, rates_total); + } + +//--- 3. Prepare Source Data (Optimized) + if(!PrepareSourceData(rates_total, start_index, open, high, low, close, price_type)) return; -//--- STEP 2: Calculate AMA - double buffer_ama[]; - ArrayResize(buffer_ama, rates_total); +//--- 4. Calculate AMA (Incremental) double fast_sc = 2.0 / (m_fast_period + 1.0); double slow_sc = 2.0 / (m_slow_period + 1.0); - for(int i = 1; i < rates_total; i++) + + int loop_start_ama = MathMax(m_ama_period, start_index); + + for(int i = loop_start_ama; i < rates_total; i++) { if(i == m_ama_period) { - buffer_ama[i] = m_ama_price[i]; + m_buffer_ama[i] = m_ama_price[i]; continue; } - if(i > m_ama_period) - { - double direction = MathAbs(m_ama_price[i] - m_ama_price[i - m_ama_period]); - double volatility = 0; - for(int j = 0; j < m_ama_period; j++) - volatility += MathAbs(m_ama_price[i - j] - m_ama_price[i - j - 1]); - double er = (volatility > 0) ? direction / volatility : 0; - double ssc = er * (fast_sc - slow_sc) + slow_sc; - buffer_ama[i] = buffer_ama[i-1] + (ssc*ssc) * (m_ama_price[i] - buffer_ama[i-1]); - } + + double direction = MathAbs(m_ama_price[i] - m_ama_price[i - m_ama_period]); + double volatility = 0; + for(int j = 0; j < m_ama_period; j++) + volatility += MathAbs(m_ama_price[i - j] - m_ama_price[i - j - 1]); + + double er = (volatility > 0) ? direction / volatility : 0; + double ssc = er * (fast_sc - slow_sc) + slow_sc; + + // Recursive AMA using persistent buffer + m_buffer_ama[i] = m_buffer_ama[i-1] + (ssc*ssc) * (m_ama_price[i] - m_buffer_ama[i-1]); } -//--- STEP 3: Calculate ATR - double buffer_atr[], tr[]; - ArrayResize(buffer_atr, rates_total); - ArrayResize(tr, rates_total); - for(int i = 1; i < rates_total; i++) - tr[i] = MathMax(m_atr_high[i], m_atr_close[i-1]) - MathMin(m_atr_low[i], m_atr_close[i-1]); - for(int i = 1; i < rates_total; i++) +//--- 5. Calculate ATR (Incremental) + int loop_start_atr = MathMax(m_atr_period, start_index); + + for(int i = loop_start_atr; i < rates_total; i++) { + double tr = MathMax(m_atr_high[i], m_atr_close[i-1]) - MathMin(m_atr_low[i], m_atr_close[i-1]); + if(i == m_atr_period) { double sum_tr = 0; - for(int j = 1; j <= m_atr_period; j++) - sum_tr += tr[j]; - buffer_atr[i] = sum_tr / m_atr_period; + for(int k = 0; k < m_atr_period; k++) + { + int idx = i - k; + double t = MathMax(m_atr_high[idx], m_atr_close[idx-1]) - MathMin(m_atr_low[idx], m_atr_close[idx-1]); + sum_tr += t; + } + m_buffer_atr[i] = sum_tr / m_atr_period; } else - if(i > m_atr_period) - buffer_atr[i] = (buffer_atr[i-1] * (m_atr_period - 1) + tr[i]) / m_atr_period; - } - -//--- STEP 4: Calculate Raw Activity and Scale it using MathArctan - double scaled_activity[]; - ArrayResize(scaled_activity, rates_total); - for(int i = m_ama_period + 1; i < rates_total; i++) - { - if(buffer_atr[i] > 0) { - double raw_activity = MathAbs(buffer_ama[i] - buffer_ama[i-1]) / buffer_atr[i]; - scaled_activity[i] = MathArctan(raw_activity) / m_pi_div_2; + // RMA (Wilder's Smoothing) + m_buffer_atr[i] = (m_buffer_atr[i-1] * (m_atr_period - 1) + tr) / m_atr_period; } } -//--- STEP 5: Calculate Final Oscillator (SMA of Scaled Activity) - double sum = 0; +//--- 6. Calculate Raw Activity and Scale (Incremental) + int loop_start_act = MathMax(m_ama_period + 1, start_index); + + for(int i = loop_start_act; i < rates_total; i++) + { + if(m_buffer_atr[i] > 0) + { + double raw_activity = MathAbs(m_buffer_ama[i] - m_buffer_ama[i-1]) / m_buffer_atr[i]; + m_scaled_activity[i] = MathArctan(raw_activity) / m_pi_div_2; + } + else + { + m_scaled_activity[i] = 0; + } + } + +//--- 7. Calculate Final SMA (Incremental) int final_start_pos = m_ama_period + m_smoothing_period; - for(int i = m_ama_period + 1; i < rates_total; i++) + int loop_start_final = MathMax(final_start_pos, start_index); + + for(int i = loop_start_final; i < rates_total; i++) { - sum += scaled_activity[i]; - if(i >= final_start_pos) - { - if(i > final_start_pos) - sum -= scaled_activity[i - m_smoothing_period]; - activity_buffer[i] = sum / m_smoothing_period; - } + double sum = 0; + for(int j = 0; j < m_smoothing_period; j++) + sum += m_scaled_activity[i-j]; + + activity_buffer[i] = sum / m_smoothing_period; } } //+------------------------------------------------------------------+ -//| CActivityCalculator: Prepares the standard source data series. | +//| Prepare Source Data (Standard - Optimized) | //+------------------------------------------------------------------+ -bool CActivityCalculator::PrepareSourceData(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], ENUM_APPLIED_PRICE price_type) +bool CActivityCalculator::PrepareSourceData(int rates_total, int start_index, const double &open[], const double &high[], const double &low[], const double &close[], ENUM_APPLIED_PRICE price_type) { -//--- Prepare AMA source price - ArrayResize(m_ama_price, rates_total); - switch(price_type) + for(int i = start_index; i < rates_total; i++) { - case PRICE_OPEN: - ArrayCopy(m_ama_price, open, 0, 0, rates_total); - break; - case PRICE_HIGH: - ArrayCopy(m_ama_price, high, 0, 0, rates_total); - break; - case PRICE_LOW: - ArrayCopy(m_ama_price, low, 0, 0, rates_total); - break; - case PRICE_MEDIAN: - for(int i=0; i