From 2fd752774dbacdca5bce8d5bbf2eab617cfcd0ad Mon Sep 17 00:00:00 2001 From: Toh4iem9 Date: Mon, 5 Jan 2026 08:54:20 +0100 Subject: [PATCH] refactor(indicators): Optimized for incremental calculation --- Include/MyIncludes/Windowed_MA_Calculator.mqh | 255 ++++++++++-------- 1 file changed, 149 insertions(+), 106 deletions(-) diff --git a/Include/MyIncludes/Windowed_MA_Calculator.mqh b/Include/MyIncludes/Windowed_MA_Calculator.mqh index 261e5c0..6102cec 100644 --- a/Include/MyIncludes/Windowed_MA_Calculator.mqh +++ b/Include/MyIncludes/Windowed_MA_Calculator.mqh @@ -1,182 +1,225 @@ //+------------------------------------------------------------------+ //| Windowed_MA_Calculator.mqh | -//| Calculation engine for Windowed FIR filters (SMA, HWMA). | +//| Calculation engine for Hann Windowed FIR filter. | +//| VERSION 2.00: Optimized for incremental calculation. | //| Copyright 2025, xxxxxxxx | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, xxxxxxxx" #include -enum ENUM_WINDOW_TYPE { W_SMA, W_TRIANGULAR, W_HANN }; enum ENUM_INPUT_SOURCE { SOURCE_PRICE, SOURCE_MOMENTUM }; // Price or (Close-Open) +//+==================================================================+ +//| CLASS 1: CWindowedMACalculator (Base Class) | //+==================================================================+ class CWindowedMACalculator { protected: int m_period; - ENUM_WINDOW_TYPE m_window_type; ENUM_INPUT_SOURCE m_source_type; + + //--- Persistent Buffer for Incremental Calculation double m_source_data[]; - virtual bool PrepareSourceData(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]); + //--- Pre-calculated Weights + double m_weights[]; + double m_weight_sum; + + //--- Updated: Accepts start_index + virtual bool PrepareSourceData(int rates_total, int start_index, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]); public: CWindowedMACalculator(void) {}; virtual ~CWindowedMACalculator(void) {}; - bool Init(int period, ENUM_WINDOW_TYPE window_type, ENUM_INPUT_SOURCE source_type); - void Calculate(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[], double &output_buffer[]); + bool Init(int period, ENUM_INPUT_SOURCE source_type); + + //--- 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 &output_buffer[]); }; //+------------------------------------------------------------------+ -bool CWindowedMACalculator::Init(int period, ENUM_WINDOW_TYPE window_type, ENUM_INPUT_SOURCE source_type) +//| Init | +//+------------------------------------------------------------------+ +bool CWindowedMACalculator::Init(int period, ENUM_INPUT_SOURCE source_type) { - m_period = (period < 1) ? 1 : period; - m_window_type = window_type; + m_period = (period < 2) ? 2 : period; m_source_type = source_type; - return true; + +// Pre-calculate Hann Weights + ArrayResize(m_weights, m_period); + m_weight_sum = 0; + + for(int j = 0; j < m_period; j++) + { + // Hann Window Formula: 0.5 * (1 - cos(2*pi*j / (N-1))) + // Note: j goes from 0 to N-1. + // j=0 -> weight=0 + // j=N-1 -> weight=0 + // Peak is at j=(N-1)/2 + + double weight = 0.5 * (1.0 - cos(2.0 * M_PI * j / (m_period - 1.0))); + m_weights[j] = weight; + m_weight_sum += weight; + } + + return (m_weight_sum > 0); } //+------------------------------------------------------------------+ -void CWindowedMACalculator::Calculate(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[], double &output_buffer[]) +//| Main Calculation (Optimized) | +//+------------------------------------------------------------------+ +void CWindowedMACalculator::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 &output_buffer[]) { if(rates_total < m_period) return; - if(!PrepareSourceData(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_source_data) != rates_total) + ArrayResize(m_source_data, rates_total); + +//--- 3. Prepare Source Data (Optimized) + if(!PrepareSourceData(rates_total, start_index, price_type, open, high, low, close)) return; - for(int i = m_period - 1; i < rates_total; i++) +//--- 4. Calculate Windowed MA (Incremental Loop) + int loop_start = MathMax(m_period - 1, start_index); + + for(int i = loop_start; i < rates_total; i++) { double sum = 0; - double weight_sum = 0; + // Convolution: Sum(Price[i-j] * Weight[j]) + // Optimization: Weights are pre-calculated for(int j = 0; j < m_period; j++) { - double weight = 1.0; - switch(m_window_type) - { - case W_TRIANGULAR: - weight = (m_period/2.0) - fabs(j - (m_period-1.0)/2.0); - break; - case W_HANN: - if(m_period > 1) - weight = 0.5 * (1.0 - cos(2.0 * M_PI * j / (m_period - 1.0))); - else - weight = 1.0; - break; - } - - sum += m_source_data[i-j] * weight; - weight_sum += weight; + sum += m_source_data[i-j] * m_weights[j]; } - if(weight_sum > 0) - output_buffer[i] = sum / weight_sum; + output_buffer[i] = sum / m_weight_sum; } } //+------------------------------------------------------------------+ -bool CWindowedMACalculator::PrepareSourceData(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]) +//| Prepare Source Data (Standard - Optimized) | +//+------------------------------------------------------------------+ +bool CWindowedMACalculator::PrepareSourceData(int rates_total, int start_index, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]) { - ArrayResize(m_source_data, rates_total); - if(m_source_type == SOURCE_PRICE) + for(int i = start_index; i < rates_total; i++) { - // Use the selected price type for the calculation - switch(price_type) + if(m_source_type == SOURCE_PRICE) { - case PRICE_OPEN: - ArrayCopy(m_source_data, open, 0, 0, rates_total); - break; - case PRICE_HIGH: - ArrayCopy(m_source_data, high, 0, 0, rates_total); - break; - case PRICE_LOW: - ArrayCopy(m_source_data, low, 0, 0, rates_total); - break; - case PRICE_MEDIAN: - for(int i=0; i