diff --git a/Include/MyIncludes/BandPass_Calculator.mqh b/Include/MyIncludes/BandPass_Calculator.mqh index 27c59b3..d7f8780 100644 --- a/Include/MyIncludes/BandPass_Calculator.mqh +++ b/Include/MyIncludes/BandPass_Calculator.mqh @@ -1,6 +1,6 @@ //+------------------------------------------------------------------+ //| BandPass_Calculator.mqh | -//| Calculation engine for the John Ehlers' Band-Pass Filter. | +//| VERSION 2.00: Optimized for incremental calculation. | //| Copyright 2025, xxxxxxxx | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, xxxxxxxx" @@ -8,27 +8,33 @@ #include //+==================================================================+ -//| | //| CLASS 1: CBandPassCalculator (Base Class) | -//| | //+==================================================================+ class CBandPassCalculator { protected: int m_lower_period; // For High-Pass int m_upper_period; // For SuperSmoother - double m_price[]; - virtual bool PreparePriceSeries(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]); + //--- Persistent Buffers for Incremental Calculation + double m_price[]; + double m_hp_buffer[]; // Intermediate High-Pass output + + //--- 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: CBandPassCalculator(void) {}; virtual ~CBandPassCalculator(void) {}; bool Init(int lower_period, int upper_period); - void Calculate(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[], double &bp_buffer[]); + + //--- 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 &bp_buffer[]); }; +//+------------------------------------------------------------------+ +//| Init | //+------------------------------------------------------------------+ bool CBandPassCalculator::Init(int lower_period, int upper_period) { @@ -38,19 +44,31 @@ bool CBandPassCalculator::Init(int lower_period, int upper_period) } //+------------------------------------------------------------------+ -void CBandPassCalculator::Calculate(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[], double &bp_buffer[]) +//| Main Calculation (Optimized) | +//+------------------------------------------------------------------+ +void CBandPassCalculator::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 &bp_buffer[]) { if(rates_total < 10) return; - if(!PreparePriceSeries(rates_total, price_type, open, high, low, close)) + + int start_index; + if(prev_calculated == 0) + start_index = 0; + else + start_index = prev_calculated - 1; + +// Resize internal buffers + if(ArraySize(m_price) != rates_total) + { + ArrayResize(m_price, rates_total); + ArrayResize(m_hp_buffer, rates_total); + } + + if(!PreparePriceSeries(rates_total, start_index, price_type, open, high, low, close)) return; -// --- Intermediate buffer for the High-Pass filter output --- - double hp_buffer[]; - ArrayResize(hp_buffer, rates_total); - // --- High-Pass Filter Coefficients (from LowerPeriod) --- - double arg_hp = 1.414 * M_PI / m_lower_period; + double arg_hp = M_SQRT2 * M_PI / m_lower_period; double a1_hp = exp(-arg_hp); double b1_hp = 2.0 * a1_hp * cos(arg_hp); double c2_hp = b1_hp; @@ -58,129 +76,141 @@ void CBandPassCalculator::Calculate(int rates_total, ENUM_APPLIED_PRICE price_ty double c1_hp = (1.0 + c2_hp - c3_hp) / 4.0; // --- SuperSmoother Filter Coefficients (from UpperPeriod) --- - double arg_ss = 1.414 * M_PI / m_upper_period; + double arg_ss = M_SQRT2 * M_PI / m_upper_period; double a1_ss = exp(-arg_ss); double b1_ss = 2.0 * a1_ss * cos(arg_ss); double c2_ss = b1_ss; double c3_ss = -a1_ss * a1_ss; double c1_ss = 1.0 - c2_ss - c3_ss; -// --- State variables for recursive calculations --- - double hp1=0, hp2=0; // High-Pass previous values - double bp1=0, bp2=0; // Band-Pass (SuperSmoother) previous values +// --- Incremental Loop --- + int loop_start = MathMax(4, start_index); -// --- Full recalculation loop --- - for(int i = 0; i < rates_total; i++) +// Initialization + if(loop_start == 4) { - // Initialization period - if(i < 4) - { - hp_buffer[i] = 0; - bp_buffer[i] = 0; - continue; - } + m_hp_buffer[0] = 0; + m_hp_buffer[1] = 0; + m_hp_buffer[2] = 0; + m_hp_buffer[3] = 0; + bp_buffer[0] = 0; + bp_buffer[1] = 0; + bp_buffer[2] = 0; + bp_buffer[3] = 0; + } + for(int i = loop_start; i < rates_total; i++) + { // --- Step 1: Calculate High-Pass filter value --- - double current_hp = c1_hp * (m_price[i] - 2.0 * m_price[i-1] + m_price[i-2]) + c2_hp * hp1 + c3_hp * hp2; - hp_buffer[i] = current_hp; + // Recursive: hp[i] depends on hp[i-1], hp[i-2] + double hp1 = m_hp_buffer[i-1]; + double hp2 = m_hp_buffer[i-2]; + + m_hp_buffer[i] = c1_hp * (m_price[i] - 2.0 * m_price[i-1] + m_price[i-2]) + c2_hp * hp1 + c3_hp * hp2; // --- Step 2: Calculate SuperSmoother on the High-Pass output --- - double current_bp = c1_ss * (hp_buffer[i] + hp_buffer[i-1]) / 2.0 + c2_ss * bp1 + c3_ss * bp2; - bp_buffer[i] = current_bp; + // Recursive: bp[i] depends on bp[i-1], bp[i-2] + double bp1 = bp_buffer[i-1]; + double bp2 = bp_buffer[i-2]; - // --- Update state variables for next iteration --- - hp2 = hp1; - hp1 = current_hp; - bp2 = bp1; - bp1 = current_bp; + bp_buffer[i] = c1_ss * (m_hp_buffer[i] + m_hp_buffer[i-1]) / 2.0 + c2_ss * bp1 + c3_ss * bp2; } } //+------------------------------------------------------------------+ -bool CBandPassCalculator::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 CBandPassCalculator::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); - switch(price_type) + for(int i = start_index; i < rates_total; i++) { - case PRICE_CLOSE: - ArrayCopy(m_price, close, 0, 0, rates_total); - break; - 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