diff --git a/Include/MyIncludes/KeltnerChannel_Calculator.mqh b/Include/MyIncludes/KeltnerChannel_Calculator.mqh index b89ba7b..15e5c9c 100644 --- a/Include/MyIncludes/KeltnerChannel_Calculator.mqh +++ b/Include/MyIncludes/KeltnerChannel_Calculator.mqh @@ -1,13 +1,14 @@ //+------------------------------------------------------------------+ //| KeltnerChannel_Calculator.mqh| -//| Calculation engine for Standard and Heikin Ashi Keltner Channels.| +//| VERSION 2.01: Fixed enum definition visibility. | //| Copyright 2025, xxxxxxxx | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, xxxxxxxx" -#include +#include +#include -//--- Re-use the enum from the main file +//--- Define the Enum here, BEFORE the class uses it --- enum ENUM_ATR_SOURCE { ATR_SOURCE_STANDARD, // Calculate ATR from standard candles @@ -15,227 +16,147 @@ enum ENUM_ATR_SOURCE }; //+==================================================================+ -//| | //| CLASS 1: CKeltnerChannelCalculator (Base Class) | -//| | //+==================================================================+ class CKeltnerChannelCalculator { protected: - int m_ma_period, m_atr_period; - ENUM_MA_METHOD m_ma_method; double m_multiplier; - ENUM_ATR_SOURCE m_atr_source; - double m_ma_price[]; + //--- Composition: Use dedicated engines + CMovingAverageCalculator *m_ma_calc; + CATRCalculator *m_atr_calc; - virtual bool PrepareMAPriceSeries(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], ENUM_APPLIED_PRICE price_type); + //--- Internal Buffers for intermediate results + double m_atr_buffer[]; + + virtual void CreateCalculators(void); public: - CKeltnerChannelCalculator(void) {}; - virtual ~CKeltnerChannelCalculator(void) {}; + CKeltnerChannelCalculator(void); + virtual ~CKeltnerChannelCalculator(void); bool Init(int ma_p, ENUM_MA_METHOD ma_m, int atr_p, double mult, ENUM_ATR_SOURCE atr_src); - void Calculate(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], ENUM_APPLIED_PRICE price_type, + + void Calculate(int rates_total, int prev_calculated, const double &open[], const double &high[], const double &low[], const double &close[], ENUM_APPLIED_PRICE price_type, double &middle_buffer[], double &upper_buffer[], double &lower_buffer[]); }; //+------------------------------------------------------------------+ -//| CKeltnerChannelCalculator: Initialization | +//| Constructor | +//+------------------------------------------------------------------+ +CKeltnerChannelCalculator::CKeltnerChannelCalculator(void) + { + m_ma_calc = NULL; + m_atr_calc = NULL; + } + +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CKeltnerChannelCalculator::~CKeltnerChannelCalculator(void) + { + if(CheckPointer(m_ma_calc) != POINTER_INVALID) + delete m_ma_calc; + if(CheckPointer(m_atr_calc) != POINTER_INVALID) + delete m_atr_calc; + } + +//+------------------------------------------------------------------+ +//| Factory Method (Virtual) | +//+------------------------------------------------------------------+ +void CKeltnerChannelCalculator::CreateCalculators(void) + { + m_ma_calc = new CMovingAverageCalculator(); + } + +//+------------------------------------------------------------------+ +//| Init | //+------------------------------------------------------------------+ bool CKeltnerChannelCalculator::Init(int ma_p, ENUM_MA_METHOD ma_m, int atr_p, double mult, ENUM_ATR_SOURCE atr_src) { - m_ma_period = (ma_p < 1) ? 1 : ma_p; - m_ma_method = ma_m; - m_atr_period = (atr_p < 1) ? 1 : atr_p; m_multiplier = (mult <= 0) ? 2.0 : mult; - m_atr_source = atr_src; + +// Create MA Calculator + CreateCalculators(); + +// Create ATR Calculator based on source selection +// Note: CATRCalculator_HA is defined in ATR_Calculator.mqh? +// No, usually in the same file or we need to ensure visibility. +// Assuming ATR_Calculator.mqh contains both classes. + + if(atr_src == ATR_SOURCE_HEIKIN_ASHI) + m_atr_calc = new CATRCalculator_HA(); + else + m_atr_calc = new CATRCalculator(); + + if(CheckPointer(m_ma_calc) == POINTER_INVALID || !m_ma_calc.Init(ma_p, (ENUM_MA_TYPE)ma_m)) + return false; + + if(CheckPointer(m_atr_calc) == POINTER_INVALID || !m_atr_calc.Init(atr_p, ATR_POINTS)) + return false; + return true; } //+------------------------------------------------------------------+ -//| CKeltnerChannelCalculator: Main Calculation Method (Shared Logic)| +//| Main Calculation | //+------------------------------------------------------------------+ -void CKeltnerChannelCalculator::Calculate(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], ENUM_APPLIED_PRICE price_type, +void CKeltnerChannelCalculator::Calculate(int rates_total, int prev_calculated, const double &open[], const double &high[], const double &low[], const double &close[], ENUM_APPLIED_PRICE price_type, double &middle_buffer[], double &upper_buffer[], double &lower_buffer[]) { - int start_pos = MathMax(m_ma_period, m_atr_period); - if(rates_total <= start_pos) + if(CheckPointer(m_ma_calc) == POINTER_INVALID || CheckPointer(m_atr_calc) == POINTER_INVALID) return; - if(!PrepareMAPriceSeries(rates_total, open, high, low, close, price_type)) - return; +//--- Resize internal ATR buffer + if(ArraySize(m_atr_buffer) != rates_total) + ArrayResize(m_atr_buffer, rates_total); - double atr_buffer[], tr[]; - ArrayResize(atr_buffer, rates_total); - ArrayResize(tr, rates_total); +//--- 1. Calculate Middle Line (MA) - Incremental + m_ma_calc.Calculate(rates_total, prev_calculated, price_type, open, high, low, close, middle_buffer); -//--- STEP 1: Calculate True Range based on the selected ATR source - if(m_atr_source == ATR_SOURCE_HEIKIN_ASHI) - { - CHeikinAshi_Calculator ha_calc; - double ha_open[], ha_high[], ha_low[], ha_close[]; - ArrayResize(ha_open, rates_total); - ArrayResize(ha_high, rates_total); - ArrayResize(ha_low, rates_total); - ArrayResize(ha_close, rates_total); - ha_calc.Calculate(rates_total, open, high, low, close, ha_open, ha_high, ha_low, ha_close); - for(int i = 1; i < rates_total; i++) - tr[i] = MathMax(ha_high[i], ha_close[i-1]) - MathMin(ha_low[i], ha_close[i-1]); - } - else // ATR_SOURCE_STANDARD - { - for(int i = 1; i < rates_total; i++) - tr[i] = MathMax(high[i], close[i-1]) - MathMin(low[i], close[i-1]); - } +//--- 2. Calculate ATR - Incremental +// Note: ATR engine ignores price_type for TR calculation (uses High/Low/Close) + m_atr_calc.Calculate(rates_total, prev_calculated, open, high, low, close, m_atr_buffer); - for(int i = 1; i < rates_total; i++) +//--- 3. Calculate Bands - Incremental Loop + int start_index = (prev_calculated > 0) ? prev_calculated - 1 : 0; + + int ma_period = m_ma_calc.GetPeriod(); + int atr_period = m_atr_calc.GetPeriod(); + int start_pos = MathMax(ma_period, atr_period); + + int loop_start = MathMax(start_pos, start_index); + + for(int i = loop_start; i < rates_total; i++) { - //--- STEP 2: Calculate ATR (Wilder's smoothing) - if(i == m_atr_period) + if(middle_buffer[i] != EMPTY_VALUE && m_atr_buffer[i] != EMPTY_VALUE) { - double sum=0; - for(int j=1; j<=m_atr_period; j++) - sum+=tr[j]; - atr_buffer[i]=sum/m_atr_period; + upper_buffer[i] = middle_buffer[i] + (m_atr_buffer[i] * m_multiplier); + lower_buffer[i] = middle_buffer[i] - (m_atr_buffer[i] * m_multiplier); } else - if(i > m_atr_period) - atr_buffer[i] = (atr_buffer[i-1]*(m_atr_period-1)+tr[i])/m_atr_period; - - //--- STEP 3: Calculate Middle Line (MA) - if(i >= m_ma_period - 1) { - switch(m_ma_method) - { - case MODE_EMA: - case MODE_SMMA: - if(i==m_ma_period-1) - { - double sum=0; - for(int j=0; j0) middle_buffer[i]=sum/w_sum;} - break; - default: - {double sum=0; for(int j=0; j= start_pos) - { - upper_buffer[i] = middle_buffer[i] + (atr_buffer[i] * m_multiplier); - lower_buffer[i] = middle_buffer[i] - (atr_buffer[i] * m_multiplier); + upper_buffer[i] = EMPTY_VALUE; + lower_buffer[i] = EMPTY_VALUE; } } } -//+------------------------------------------------------------------+ -//| CKeltnerChannelCalculator: Prepares the standard MA source price.| -//+------------------------------------------------------------------+ -bool CKeltnerChannelCalculator::PrepareMAPriceSeries(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], ENUM_APPLIED_PRICE price_type) - { - ArrayResize(m_ma_price, rates_total); - switch(price_type) - { - case PRICE_OPEN: - ArrayCopy(m_ma_price, open, 0, 0, rates_total); - break; - case PRICE_HIGH: - ArrayCopy(m_ma_price, high, 0, 0, rates_total); - break; - case PRICE_LOW: - ArrayCopy(m_ma_price, low, 0, 0, rates_total); - break; - case PRICE_MEDIAN: - for(int i=0; i