diff --git a/Include/MyIncludes/KAMA_Channel_Calculator.mqh b/Include/MyIncludes/KAMA_Channel_Calculator.mqh index f869ade..95b32b1 100644 --- a/Include/MyIncludes/KAMA_Channel_Calculator.mqh +++ b/Include/MyIncludes/KAMA_Channel_Calculator.mqh @@ -1,47 +1,63 @@ //+------------------------------------------------------------------+ //| KAMA_Channel_Calculator.mqh | -//| KAMA Middle Line + ATR Bands (Keltner Concept). | -//| Copyright 2026, xxxxxxxx | +//| KAMA Middle Line + ATR Bands (Keltner Volatility Channel) | +//| Copyright 2026, xxxxxxxx| //+------------------------------------------------------------------+ #property copyright "Copyright 2026, xxxxxxxx" +#property version "3.00" // Performance-optimized unified composition engine + +#ifndef KAMA_CHANNEL_CALCULATOR_MQH +#define KAMA_CHANNEL_CALCULATOR_MQH #include #include //+==================================================================+ -//| CLASS 1: CKamaChannelCalculator (Base) | +//| CLASS: CKamaChannelCalculator | //+==================================================================+ class CKamaChannelCalculator { -protected: +private: double m_multiplier; + int m_er_period; + int m_atr_period; - //--- Composition - CKamaCalculator *m_kama_calc; + //--- Composition Engines + CKamaCalculator m_kama_calc; CATRCalculator *m_atr_calc; - //--- Internal Buffer + //--- Internal State Buffers double m_atr_buffer[]; - virtual void CreateCalculators(void); - public: CKamaChannelCalculator(void); - virtual ~CKamaChannelCalculator(void); + ~CKamaChannelCalculator(void); - bool Init(int er_p, int fast_ema_p, int slow_ema_p, int atr_p, double mult, ENUM_ATR_SOURCE atr_src); + bool Init(const int er_p, const int fast_p, const int slow_p, const ENUM_APPLIED_PRICE_HA_ALL kama_price, + const int atr_p, const double multiplier, const ENUM_ATR_SOURCE atr_source); - 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[]); + void Calculate(const int rates_total, + const int prev_calculated, + const double &open[], + const double &high[], + const double &low[], + const double &close[], + double &middle_buffer[], + double &upper_buffer[], + double &lower_buffer[]); + + int GetRequiredWarmup(void) const { return MathMax(m_er_period, m_atr_period); } }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ -CKamaChannelCalculator::CKamaChannelCalculator(void) +CKamaChannelCalculator::CKamaChannelCalculator(void) : m_multiplier(2.0), + m_er_period(10), + m_atr_period(14), + m_atr_calc(NULL) { - m_kama_calc = NULL; - m_atr_calc = NULL; + ArraySetAsSeries(m_atr_buffer, false); } //+------------------------------------------------------------------+ @@ -49,76 +65,99 @@ CKamaChannelCalculator::CKamaChannelCalculator(void) //+------------------------------------------------------------------+ CKamaChannelCalculator::~CKamaChannelCalculator(void) { - if(CheckPointer(m_kama_calc) != POINTER_INVALID) - delete m_kama_calc; if(CheckPointer(m_atr_calc) != POINTER_INVALID) + { delete m_atr_calc; + m_atr_calc = NULL; + } } //+------------------------------------------------------------------+ -//| Factory Method | +//| Initialization | //+------------------------------------------------------------------+ -void CKamaChannelCalculator::CreateCalculators(void) +bool CKamaChannelCalculator::Init(const int er_p, const int fast_p, const int slow_p, const ENUM_APPLIED_PRICE_HA_ALL kama_price, + const int atr_p, const double multiplier, const ENUM_ATR_SOURCE atr_source) { - m_kama_calc = new CKamaCalculator(); - } + m_er_period = (er_p < 1) ? 1 : er_p; + m_atr_period = (atr_p < 1) ? 1 : atr_p; + m_multiplier = (multiplier <= 0.0) ? 2.0 : multiplier; -//+------------------------------------------------------------------+ -//| Init | -//+------------------------------------------------------------------+ -bool CKamaChannelCalculator::Init(int er_p, int fast_ema_p, int slow_ema_p, int atr_p, double mult, ENUM_ATR_SOURCE atr_src) - { - m_multiplier = (mult <= 0) ? 2.0 : mult; +// 1. Initialize KAMA Engine + if(!m_kama_calc.Init(m_er_period, fast_p, slow_p, kama_price)) + return false; - CreateCalculators(); // Creates KAMA Calculator +// 2. Initialize ATR Engine (Clean memory rebuild) + if(CheckPointer(m_atr_calc) != POINTER_INVALID) + { + delete m_atr_calc; + m_atr_calc = NULL; + } -// Create ATR Calculator - if(atr_src == ATR_SOURCE_HEIKIN_ASHI) + if(atr_source == ATR_SOURCE_HEIKIN_ASHI) m_atr_calc = new CATRCalculator_HA(); else m_atr_calc = new CATRCalculator(); - if(CheckPointer(m_kama_calc) == POINTER_INVALID || !m_kama_calc.Init(er_p, fast_ema_p, slow_ema_p)) - return false; - - if(CheckPointer(m_atr_calc) == POINTER_INVALID || !m_atr_calc.Init(atr_p, ATR_POINTS)) + if(CheckPointer(m_atr_calc) == POINTER_INVALID || !m_atr_calc.Init(m_atr_period, ATR_POINTS)) return false; return true; } //+------------------------------------------------------------------+ -//| Main Calculation | +//| Main Incremental Channel Calculation | //+------------------------------------------------------------------+ -void CKamaChannelCalculator::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[]) +void CKamaChannelCalculator::Calculate(const int rates_total, + const int prev_calculated, + const double &open[], + const double &high[], + const double &low[], + const double &close[], + double &middle_buffer[], + double &upper_buffer[], + double &lower_buffer[]) { - if(rates_total < 2) + int warmup = GetRequiredWarmup(); + if(rates_total <= warmup || CheckPointer(m_atr_calc) == POINTER_INVALID) return; -//--- Resize Internal Buffer +// Resize internal ATR buffer if(ArraySize(m_atr_buffer) != rates_total) + { ArrayResize(m_atr_buffer, rates_total); + ArraySetAsSeries(m_atr_buffer, false); + } -//--- 1. Calculate Middle Line (KAMA) - m_kama_calc.Calculate(rates_total, prev_calculated, price_type, open, high, low, close, middle_buffer); +// 1. Compute KAMA Middle Line + m_kama_calc.Calculate(rates_total, prev_calculated, open, high, low, close, middle_buffer); -//--- 2. Calculate ATR +// 2. Compute ATR Volatility Range m_atr_calc.Calculate(rates_total, prev_calculated, open, high, low, close, m_atr_buffer); -//--- 3. Calculate Bands - int start_index = (prev_calculated > 0) ? prev_calculated - 1 : 0; - int atr_period = m_atr_calc.GetPeriod(); - int kama_period = m_kama_calc.GetPeriod(); // ER Period - int loop_start = MathMax(MathMax(atr_period, kama_period), start_index); - - for(int i = loop_start; i < rates_total; i++) +// 3. Clean invalid initial range on fresh calculation + if(prev_calculated == 0) { - if(middle_buffer[i] != 0.0 && middle_buffer[i] != EMPTY_VALUE && - m_atr_buffer[i] != 0.0 && m_atr_buffer[i] != EMPTY_VALUE) + for(int i = 0; i < warmup; i++) { - upper_buffer[i] = middle_buffer[i] + (m_atr_buffer[i] * m_multiplier); - lower_buffer[i] = middle_buffer[i] - (m_atr_buffer[i] * m_multiplier); + middle_buffer[i] = EMPTY_VALUE; + upper_buffer[i] = EMPTY_VALUE; + lower_buffer[i] = EMPTY_VALUE; + } + } + + int start_index = (prev_calculated == 0) ? warmup : (prev_calculated - 1); + if(start_index < warmup) + start_index = warmup; + +// 4. Construct Upper and Lower Keltner Bands + for(int i = start_index; i < rates_total; i++) + { + if(middle_buffer[i] != EMPTY_VALUE && middle_buffer[i] > 0.0 && + m_atr_buffer[i] != EMPTY_VALUE && m_atr_buffer[i] > 0.0) + { + double channel_width = m_atr_buffer[i] * m_multiplier; + upper_buffer[i] = middle_buffer[i] + channel_width; + lower_buffer[i] = middle_buffer[i] - channel_width; } else { @@ -128,20 +167,5 @@ void CKamaChannelCalculator::Calculate(int rates_total, int prev_calculated, con } } -//+==================================================================+ -//| CLASS 2: CKamaChannelCalculator_HA | -//+==================================================================+ -class CKamaChannelCalculator_HA : public CKamaChannelCalculator - { -protected: - virtual void CreateCalculators(void) override; - }; - -//+------------------------------------------------------------------+ -//| Factory Override | -//+------------------------------------------------------------------+ -void CKamaChannelCalculator_HA::CreateCalculators(void) - { - m_kama_calc = new CKamaCalculator_HA(); - } +#endif // KAMA_CHANNEL_CALCULATOR_MQH //+------------------------------------------------------------------+