diff --git a/Include/MyIncludes/CCI_PercentB_Calculator.mqh b/Include/MyIncludes/CCI_PercentB_Calculator.mqh index 0b688a3..3ed7ff3 100644 --- a/Include/MyIncludes/CCI_PercentB_Calculator.mqh +++ b/Include/MyIncludes/CCI_PercentB_Calculator.mqh @@ -5,236 +5,120 @@ //+------------------------------------------------------------------+ #property copyright "Copyright 2025, xxxxxxxx" -#include +#include //+==================================================================+ -//| | -//| CLASS 1: CCCI_PercentBCalculator (Base Class) | -//| | +//| CLASS: CCCI_PercentBCalculator | //+==================================================================+ class CCCI_PercentBCalculator { protected: - int m_cci_period, m_ma_period, m_bands_period; - ENUM_MA_METHOD m_ma_method; - double m_bands_dev; - double m_price[]; + //--- Composition: Use the main CCI Calculator + CCCI_Calculator *m_cci_engine; - virtual bool PreparePriceSeries(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], ENUM_APPLIED_PRICE price_type); + //--- Persistent Buffers for Incremental Calculation + double m_cci_buffer[]; + double m_signal_buffer[]; + double m_upper_buffer[]; + double m_lower_buffer[]; + + int m_cci_period; + int m_ma_period; + int m_bands_period; public: - CCCI_PercentBCalculator(void) {}; - virtual ~CCCI_PercentBCalculator(void) {}; + CCCI_PercentBCalculator(void); + virtual ~CCCI_PercentBCalculator(void); - bool Init(int cci_p, int ma_p, ENUM_MA_METHOD ma_m, int bands_p, double bands_dev); - void Calculate(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], ENUM_APPLIED_PRICE price_type, + //--- Init now takes ENUM_MA_TYPE and HA flag + bool Init(int cci_p, int ma_p, ENUM_MA_TYPE ma_m, int bands_p, double bands_dev, bool use_ha); + + 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 &percent_b_out[]); }; //+------------------------------------------------------------------+ -//| CCCI_PercentBCalculator: Initialization | +//| Constructor | //+------------------------------------------------------------------+ -bool CCCI_PercentBCalculator::Init(int cci_p, int ma_p, ENUM_MA_METHOD ma_m, int bands_p, double bands_dev) +CCCI_PercentBCalculator::CCCI_PercentBCalculator(void) : m_cci_engine(NULL) { - m_cci_period = (cci_p < 1) ? 1 : cci_p; - m_ma_period = (ma_p < 1) ? 1 : ma_p; - m_ma_method = ma_m; - m_bands_period = (bands_p < 1) ? 1 : bands_p; - m_bands_dev = (bands_dev <= 0) ? 2.0 : bands_dev; - return true; } //+------------------------------------------------------------------+ -//| CCCI_PercentBCalculator: Main Calculation Method | +//| Destructor | //+------------------------------------------------------------------+ -void CCCI_PercentBCalculator::Calculate(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], ENUM_APPLIED_PRICE price_type, +CCCI_PercentBCalculator::~CCCI_PercentBCalculator(void) + { + if(CheckPointer(m_cci_engine) != POINTER_INVALID) + delete m_cci_engine; + } + +//+------------------------------------------------------------------+ +//| Init | +//+------------------------------------------------------------------+ +bool CCCI_PercentBCalculator::Init(int cci_p, int ma_p, ENUM_MA_TYPE ma_m, int bands_p, double bands_dev, bool use_ha) + { + m_cci_period = cci_p; + m_ma_period = ma_p; + m_bands_period = bands_p; + +// Instantiate correct engine + if(use_ha) + m_cci_engine = new CCCI_Calculator_HA(); + else + m_cci_engine = new CCCI_Calculator(); + +// Initialize engine + return m_cci_engine.Init(cci_p, ma_p, ma_m, bands_p, bands_dev); + } + +//+------------------------------------------------------------------+ +//| Main Calculation | +//+------------------------------------------------------------------+ +void CCCI_PercentBCalculator::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 &percent_b_out[]) { - if(rates_total <= m_cci_period + m_bands_period) - return; - if(!PreparePriceSeries(rates_total, open, high, low, close, price_type)) + if(CheckPointer(m_cci_engine) == POINTER_INVALID) return; - double cci_buffer[], signal_buffer[], upper_buffer[], lower_buffer[]; - ArrayResize(cci_buffer, rates_total); - ArrayResize(signal_buffer, rates_total); - ArrayResize(upper_buffer, rates_total); - ArrayResize(lower_buffer, rates_total); - - double buffer_sma[], buffer_mad[]; - ArrayResize(buffer_sma, rates_total); - ArrayResize(buffer_mad, rates_total); - const double CCI_CONSTANT = 0.015; - - double sma_sum = 0; - for(int i = 0; i < rates_total; i++) +// Resize internal buffers + if(ArraySize(m_cci_buffer) != rates_total) { - sma_sum += m_price[i]; - if(i >= m_cci_period) - sma_sum -= m_price[i - m_cci_period]; - if(i >= m_cci_period - 1) - buffer_sma[i] = sma_sum / m_cci_period; + ArrayResize(m_cci_buffer, rates_total); + ArrayResize(m_signal_buffer, rates_total); + ArrayResize(m_upper_buffer, rates_total); + ArrayResize(m_lower_buffer, rates_total); } - for(int i = m_cci_period - 1; i < rates_total; i++) - { - double deviation_sum = 0; - for(int j = 0; j < m_cci_period; j++) - deviation_sum += MathAbs(m_price[i - j] - buffer_sma[i]); - buffer_mad[i] = deviation_sum / m_cci_period; - } +// Calculate CCI, Signal and Bands (Incremental) +// The CCI engine handles its own incremental logic + m_cci_engine.Calculate(rates_total, prev_calculated, price_type, open, high, low, close, + m_cci_buffer, m_signal_buffer, m_upper_buffer, m_lower_buffer); - for(int i = m_cci_period - 1; i < rates_total; i++) - { - if(buffer_mad[i] > 0) - cci_buffer[i] = (m_price[i] - buffer_sma[i]) / (CCI_CONSTANT * buffer_mad[i]); - } +// Calculate %B +// Valid from: CCI Period + Bands Period - 2 + int start_pos = m_cci_period + m_bands_period - 2; - int ma_start_pos = m_cci_period + m_ma_period - 2; - for(int i = ma_start_pos; i < rates_total; i++) + int start_index = (prev_calculated > 0) ? prev_calculated - 1 : 0; + int loop_start = MathMax(start_pos, start_index); + + if(prev_calculated == 0) + ArrayInitialize(percent_b_out, 50.0); // Default to mid-point (50%) + + for(int i = loop_start; i < rates_total; i++) { - switch(m_ma_method) + double band_width = m_upper_buffer[i] - m_lower_buffer[i]; + + if(band_width != 0) { - case MODE_EMA: - case MODE_SMMA: - if(i == ma_start_pos) - { - double sum=0; - for(int j=0; j0) signal_buffer[i]=sum/w_sum;} - break; - default: - {double sum=0; for(int j=0; j 0) - percent_b_out[i] = (cci_buffer[i] - lower_buffer[i]) / range * 100.0; - } - } - -//+------------------------------------------------------------------+ -//| CCCI_PercentBCalculator: Prepares the standard source price. | -//+------------------------------------------------------------------+ -bool CCCI_PercentBCalculator::PreparePriceSeries(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], ENUM_APPLIED_PRICE price_type) - { - ArrayResize(m_price, rates_total); - switch(price_type) - { - 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