//+------------------------------------------------------------------+ //| CCI_Oscillator_Calculator.mqh| //| Calculation engine for Standard and Heikin Ashi CCI Oscillator. | //| (Self-contained version with duplicated logic) | //| Copyright 2025, xxxxxxxx | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, xxxxxxxx" #include //+==================================================================+ //| | //| CLASS 1: CCCI_OscillatorCalculator (Base Class) | //| | //+==================================================================+ class CCCI_OscillatorCalculator { protected: int m_cci_period; int m_ma_period; ENUM_MA_METHOD m_ma_method; //--- Internal buffer for the selected source price double m_price[]; //--- Virtual method for preparing the price series. virtual bool PreparePriceSeries(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], ENUM_APPLIED_PRICE price_type); public: CCCI_OscillatorCalculator(void) {}; virtual ~CCCI_OscillatorCalculator(void) {}; //--- Public methods bool Init(int cci_p, int ma_p, ENUM_MA_METHOD ma_m); void Calculate(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], ENUM_APPLIED_PRICE price_type, double &osc_buffer[]); }; //+------------------------------------------------------------------+ //| CCCI_OscillatorCalculator: Initialization | //+------------------------------------------------------------------+ bool CCCI_OscillatorCalculator::Init(int cci_p, int ma_p, ENUM_MA_METHOD ma_m) { m_cci_period = (cci_p < 1) ? 1 : cci_p; m_ma_period = (ma_p < 1) ? 1 : ma_p; m_ma_method = ma_m; return true; } //+------------------------------------------------------------------+ //| CCCI_OscillatorCalculator: Main Calculation Method | //+------------------------------------------------------------------+ void CCCI_OscillatorCalculator::Calculate(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], ENUM_APPLIED_PRICE price_type, double &osc_buffer[]) { int start_pos = m_cci_period + m_ma_period - 2; if(rates_total <= start_pos) return; //--- STEP 1: Prepare the source price array (delegated to virtual method) if(!PreparePriceSeries(rates_total, open, high, low, close, price_type)) return; //--- Internal calculation buffers double buffer_cci[], buffer_signal[]; ArrayResize(buffer_cci, rates_total); ArrayResize(buffer_signal, rates_total); double buffer_sma[], buffer_mad[]; ArrayResize(buffer_sma, rates_total); ArrayResize(buffer_mad, rates_total); const double CCI_CONSTANT = 0.015; //--- STEP 2: Calculate the Simple Moving Average of the price double sma_sum = 0; for(int i = 0; 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; } //--- STEP 3: Calculate the Mean Absolute Deviation (MAD) 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; } //--- STEP 4: Calculate the final CCI value for(int i = m_cci_period - 1; i < rates_total; i++) { if(buffer_mad[i] > 0) buffer_cci[i] = (m_price[i] - buffer_sma[i]) / (CCI_CONSTANT * buffer_mad[i]); } //--- STEP 5: Calculate the 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++) { switch(m_ma_method) { case MODE_EMA: case MODE_SMMA: if(i == ma_start_pos) { double sum=0; for(int j=0; j0) buffer_signal[i]=lwma_sum/weight_sum; } break; default: // MODE_SMA { double sum=0; for(int j=0; j