diff --git a/Include/MyIncludes/CCI_Calculator.mqh b/Include/MyIncludes/CCI_Calculator.mqh index 6d40a60..8584d2e 100644 --- a/Include/MyIncludes/CCI_Calculator.mqh +++ b/Include/MyIncludes/CCI_Calculator.mqh @@ -1,132 +1,151 @@ //+------------------------------------------------------------------+ //| CCI_Calculator.mqh | -//| Calculation engine for CCI Pro (CCI, Signal Line, BBands). | +//| VERSION 2.00: Optimized for incremental calculation. | //| Copyright 2025, xxxxxxxx | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, xxxxxxxx" #include +#include //+==================================================================+ -//| | //| CLASS 1: CCCI_Calculator (Base Class) | -//| | //+==================================================================+ class CCCI_Calculator { protected: - int m_cci_period, m_ma_period, m_bands_period; - ENUM_MA_METHOD m_ma_method; + int m_cci_period, m_bands_period; double m_bands_dev; - double m_price[]; - virtual bool PreparePriceSeries(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], ENUM_APPLIED_PRICE price_type); + //--- Engine for Signal Line + CMovingAverageCalculator m_signal_engine; + + //--- Persistent Buffers + double m_price[]; + double m_sma_buffer[]; // Simple Moving Average of Price + double m_mad_buffer[]; // Mean Absolute Deviation + + //--- 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: CCCI_Calculator(void) {}; virtual ~CCCI_Calculator(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 + bool Init(int cci_p, int ma_p, ENUM_MA_TYPE ma_m, int bands_p, double bands_dev); + + //--- 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 &cci_out[], double &signal_out[], double &upper_out[], double &lower_out[]); }; //+------------------------------------------------------------------+ -//| CCCI_Calculator: Initialization | +//| Init | //+------------------------------------------------------------------+ -bool CCCI_Calculator::Init(int cci_p, int ma_p, ENUM_MA_METHOD ma_m, int bands_p, double bands_dev) +bool CCCI_Calculator::Init(int cci_p, int ma_p, ENUM_MA_TYPE ma_m, int bands_p, double bands_dev) { 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; + +// Initialize Signal Engine + if(!m_signal_engine.Init(ma_p, ma_m)) + return false; + return true; } //+------------------------------------------------------------------+ -//| CCCI_Calculator: Main Calculation Method (Shared Logic) | +//| Main Calculation (Optimized) | //+------------------------------------------------------------------+ -void CCCI_Calculator::Calculate(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], ENUM_APPLIED_PRICE price_type, +void CCCI_Calculator::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 &cci_out[], double &signal_out[], double &upper_out[], double &lower_out[]) { +// Minimum bars check if(rates_total <= m_cci_period + m_bands_period) return; - if(!PreparePriceSeries(rates_total, open, high, low, close, price_type)) + + int start_index; + if(prev_calculated == 0) + start_index = 0; + else + start_index = prev_calculated - 1; + +// Resize Buffers + if(ArraySize(m_price) != rates_total) + { + ArrayResize(m_price, rates_total); + ArrayResize(m_sma_buffer, rates_total); + ArrayResize(m_mad_buffer, rates_total); + } + + if(!PreparePriceSeries(rates_total, start_index, price_type, open, high, low, close)) return; - double buffer_sma[], buffer_mad[]; - ArrayResize(buffer_sma, rates_total); - ArrayResize(buffer_mad, rates_total); const double CCI_CONSTANT = 0.015; -//--- Calculate CCI --- - double sma_sum = 0; - for(int i = 0; i < rates_total; i++) +//--- 1. Calculate SMA of Price (Incremental) +// We can use a sliding window sum for O(1) SMA calculation, but standard loop is safer for now. +// Optimization: Only calculate for new bars. + int loop_start_sma = MathMax(m_cci_period - 1, start_index); + + for(int i = loop_start_sma; i < rates_total; i++) { - 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; + double sum = 0; + for(int j = 0; j < m_cci_period; j++) + sum += m_price[i-j]; + m_sma_buffer[i] = sum / m_cci_period; } - for(int i = m_cci_period - 1; i < rates_total; i++) + +//--- 2. Calculate Mean Absolute Deviation (MAD) + for(int i = loop_start_sma; 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; - } - for(int i = m_cci_period - 1; i < rates_total; i++) - { - if(buffer_mad[i] > 0) - cci_out[i] = (m_price[i] - buffer_sma[i]) / (CCI_CONSTANT * buffer_mad[i]); + deviation_sum += MathAbs(m_price[i - j] - m_sma_buffer[i]); + m_mad_buffer[i] = deviation_sum / m_cci_period; } -//--- Calculate Signal Line (MA of CCI) --- - int ma_start_pos = m_cci_period + m_ma_period - 2; - for(int i = ma_start_pos; i < rates_total; i++) +//--- 3. Calculate CCI + if(prev_calculated == 0) + ArrayInitialize(cci_out, EMPTY_VALUE); + + for(int i = loop_start_sma; i < rates_total; i++) { - switch(m_ma_method) - { - case MODE_EMA: - case MODE_SMMA: - if(i == ma_start_pos) - { - double sum=0; - for(int j=0; j0) signal_out[i]=sum/w_sum;} - break; - default: - {double sum=0; for(int j=0; j 0) + cci_out[i] = (m_price[i] - m_sma_buffer[i]) / (CCI_CONSTANT * m_mad_buffer[i]); + else + cci_out[i] = 0; } -//--- Calculate Bollinger Bands (on CCI, centered on Signal Line) --- - int bands_start_pos = m_cci_period + m_bands_period - 2; - for(int i = bands_start_pos; i < rates_total; i++) +//--- 4. Calculate Signal Line (Using Engine) +// CCI is valid from index: m_cci_period - 1 + int cci_offset = m_cci_period - 1; + m_signal_engine.CalculateOnArray(rates_total, prev_calculated, cci_out, signal_out, cci_offset); + +//--- 5. Calculate Bollinger Bands (Optimized) +// Bands are based on CCI and centered on Signal Line + int ma_period = m_signal_engine.GetPeriod(); + int bands_start_pos = cci_offset + ma_period - 1; // Where signal line starts + int loop_start_bands = MathMax(bands_start_pos, start_index); + + if(prev_calculated == 0) + { + ArrayInitialize(upper_out, EMPTY_VALUE); + ArrayInitialize(lower_out, EMPTY_VALUE); + } + + for(int i = loop_start_bands; i < rates_total; i++) { if(signal_out[i] == EMPTY_VALUE) continue; + double std_dev = 0, sum_sq = 0; + // Standard Deviation of CCI around the Signal Line for(int j = 0; j < m_bands_period; j++) sum_sq += MathPow(cci_out[i-j] - signal_out[i], 2); + std_dev = MathSqrt(sum_sq / m_bands_period); upper_out[i] = signal_out[i] + m_bands_dev * std_dev; lower_out[i] = signal_out[i] - m_bands_dev * std_dev; @@ -134,95 +153,98 @@ void CCCI_Calculator::Calculate(int rates_total, const double &open[], const dou } //+------------------------------------------------------------------+ -//| CCCI_Calculator: Prepares the standard source price series. | +//| Prepare Price (Standard - Optimized) | //+------------------------------------------------------------------+ -bool CCCI_Calculator::PreparePriceSeries(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], ENUM_APPLIED_PRICE price_type) +bool CCCI_Calculator::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_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