diff --git a/Include/MyIncludes/Laguerre_Engine.mqh b/Include/MyIncludes/Laguerre_Engine.mqh index 8261fe6..c422afa 100644 --- a/Include/MyIncludes/Laguerre_Engine.mqh +++ b/Include/MyIncludes/Laguerre_Engine.mqh @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| Laguerre_Engine.mqh | -//| VERSION 1.10: Corrected state management for stability. | +//| VERSION 1.20: Optimized for incremental calculation. | //| Copyright 2025, xxxxxxxx | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, xxxxxxxx" @@ -15,20 +15,24 @@ class CLaguerreEngine protected: double m_gamma; ENUM_INPUT_SOURCE m_source_type; + + //--- Persistent Buffers for Incremental Calculation double m_price[]; + double m_L0[], m_L1[], m_L2[], m_L3[]; // Internal state buffers - //--- State variables for the recursive filter (CRITICAL FIX) --- - double m_L0_prev, m_L1_prev, m_L2_prev, m_L3_prev; - - virtual bool PreparePriceSeries(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]); + //--- 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: CLaguerreEngine(void) {}; virtual ~CLaguerreEngine(void) {}; bool Init(double gamma, ENUM_INPUT_SOURCE source_type); - void CalculateFilter(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[], - double &L0_buffer[], double &L1_buffer[], double &L2_buffer[], double &L3_buffer[], double &filt_buffer[]); + + //--- Updated: Accepts prev_calculated + void CalculateFilter(int rates_total, int prev_calculated, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[], + double &filt_buffer[]); + void GetPriceBuffer(double &dest_array[]); }; @@ -37,24 +41,17 @@ public: //+==================================================================+ //+------------------------------------------------------------------+ -//| | +//| Init | //+------------------------------------------------------------------+ bool CLaguerreEngine::Init(double gamma, ENUM_INPUT_SOURCE source_type) { m_gamma = fmax(0.0, fmin(1.0, gamma)); m_source_type = source_type; - -//--- Reset state variables on initialization --- - m_L0_prev = 0; - m_L1_prev = 0; - m_L2_prev = 0; - m_L3_prev = 0; - return true; } //+------------------------------------------------------------------+ -//| | +//| Get Price Buffer (Helper for FIR filter) | //+------------------------------------------------------------------+ void CLaguerreEngine::GetPriceBuffer(double &dest_array[]) { @@ -67,157 +64,177 @@ void CLaguerreEngine::GetPriceBuffer(double &dest_array[]) } //+------------------------------------------------------------------+ -//| | +//| Main Calculation (Optimized) | //+------------------------------------------------------------------+ -void CLaguerreEngine::CalculateFilter(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[], - double &L0_buffer[], double &L1_buffer[], double &L2_buffer[], double &L3_buffer[], double &filt_buffer[]) +void CLaguerreEngine::CalculateFilter(int rates_total, int prev_calculated, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[], + double &filt_buffer[]) { if(rates_total < 2) return; - if(!PreparePriceSeries(rates_total, price_type, open, high, low, close)) - return; - ArrayResize(L0_buffer, rates_total); - ArrayResize(L1_buffer, rates_total); - ArrayResize(L2_buffer, rates_total); - ArrayResize(L3_buffer, rates_total); - ArrayResize(filt_buffer, rates_total); +//--- 1. Determine Start Index + int start_index; + if(prev_calculated == 0) + start_index = 0; + else + start_index = prev_calculated - 1; -//--- Robust initialization on first run --- - if(m_L0_prev == 0 && m_L1_prev == 0) // A simple check for first run +//--- 2. Resize Internal Buffers + if(ArraySize(m_price) != rates_total) { - m_L0_prev = m_price[0]; - m_L1_prev = m_price[0]; - m_L2_prev = m_price[0]; - m_L3_prev = m_price[0]; + ArrayResize(m_price, rates_total); + ArrayResize(m_L0, rates_total); + ArrayResize(m_L1, rates_total); + ArrayResize(m_L2, rates_total); + ArrayResize(m_L3, rates_total); } - for(int i = 0; i < rates_total; i++) +//--- 3. Prepare Price (Optimized) + if(!PreparePriceSeries(rates_total, start_index, price_type, open, high, low, close)) + return; + +//--- 4. Calculate Laguerre Filter +// We need to handle the very first bar separately for initialization + int i = start_index; + + if(i == 0) { - // For the very first bar, output is just the price - if(i == 0) - { - L0_buffer[i] = m_price[i]; - L1_buffer[i] = m_price[i]; - L2_buffer[i] = m_price[i]; - L3_buffer[i] = m_price[i]; - } - else - { - L0_buffer[i] = (1.0 - m_gamma) * m_price[i] + m_gamma * m_L0_prev; - L1_buffer[i] = -m_gamma * L0_buffer[i] + m_L0_prev + m_gamma * m_L1_prev; - L2_buffer[i] = -m_gamma * L1_buffer[i] + m_L1_prev + m_gamma * m_L2_prev; - L3_buffer[i] = -m_gamma * L2_buffer[i] + m_L2_prev + m_gamma * m_L3_prev; - } + m_L0[0] = m_price[0]; + m_L1[0] = m_price[0]; + m_L2[0] = m_price[0]; + m_L3[0] = m_price[0]; + filt_buffer[0] = (m_L0[0] + 2.0 * m_L1[0] + 2.0 * m_L2[0] + m_L3[0]) / 6.0; + i = 1; + } - filt_buffer[i] = (L0_buffer[i] + 2.0 * L1_buffer[i] + 2.0 * L2_buffer[i] + L3_buffer[i]) / 6.0; + for(; i < rates_total; i++) + { + // Recursive calculation uses [i-1] from persistent buffers + // This is safe even if we recalculate the last bar multiple times + double L0_prev = m_L0[i-1]; + double L1_prev = m_L1[i-1]; + double L2_prev = m_L2[i-1]; + double L3_prev = m_L3[i-1]; - //--- Update state variables for the next iteration --- - m_L0_prev = L0_buffer[i]; - m_L1_prev = L1_buffer[i]; - m_L2_prev = L2_buffer[i]; - m_L3_prev = L3_buffer[i]; + m_L0[i] = (1.0 - m_gamma) * m_price[i] + m_gamma * L0_prev; + m_L1[i] = -m_gamma * m_L0[i] + L0_prev + m_gamma * L1_prev; + m_L2[i] = -m_gamma * m_L1[i] + L1_prev + m_gamma * L2_prev; + m_L3[i] = -m_gamma * m_L2[i] + L2_prev + m_gamma * L3_prev; + + filt_buffer[i] = (m_L0[i] + 2.0 * m_L1[i] + 2.0 * m_L2[i] + m_L3[i]) / 6.0; } } //+------------------------------------------------------------------+ -bool CLaguerreEngine::PreparePriceSeries(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]) +//| Prepare Price (Standard - Optimized) | +//+------------------------------------------------------------------+ +bool CLaguerreEngine::PreparePriceSeries(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_price, rates_total); - if(m_source_type == SOURCE_PRICE) +// Optimized copy loop + for(int i = start_index; i < rates_total; i++) { - switch(price_type) + if(m_source_type == SOURCE_PRICE) { - 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