From ee1dca2227a7a760048433fc3401a293d233d244 Mon Sep 17 00:00:00 2001 From: Toh4iem9 Date: Sun, 11 Jan 2026 11:29:25 +0100 Subject: [PATCH] refactor(indicators): Refactored to use DMI_Engine --- .../MyIncludes/DMIStochastic_Calculator.mqh | 212 +++++------------- 1 file changed, 51 insertions(+), 161 deletions(-) diff --git a/Include/MyIncludes/DMIStochastic_Calculator.mqh b/Include/MyIncludes/DMIStochastic_Calculator.mqh index f3deb18..4c0e52f 100644 --- a/Include/MyIncludes/DMIStochastic_Calculator.mqh +++ b/Include/MyIncludes/DMIStochastic_Calculator.mqh @@ -1,57 +1,39 @@ //+------------------------------------------------------------------+ //| DMIStochastic_Calculator.mqh | -//| VERSION 2.10: Separate MA type for Signal Line. | +//| VERSION 3.00: Refactored to use DMI_Engine. | //| Copyright 2025, xxxxxxxx | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, xxxxxxxx" -#include +#include #include -//--- Enum for selecting the candle source for calculation --- -enum ENUM_CANDLE_SOURCE - { - CANDLE_STANDARD, // Use standard OHLC data - CANDLE_HEIKIN_ASHI // Use Heikin Ashi smoothed data - }; +enum ENUM_CANDLE_SOURCE { CANDLE_STANDARD, CANDLE_HEIKIN_ASHI }; +enum ENUM_DMI_OSC_TYPE { OSC_PDI_MINUS_NDI, OSC_NDI_MINUS_PDI }; -//--- Enum for selecting the oscillator calculation formula --- -enum ENUM_DMI_OSC_TYPE - { - OSC_PDI_MINUS_NDI, // Intuitive: High value = Bullish pressure - OSC_NDI_MINUS_PDI // Original: High value = Bearish pressure - }; - -//+==================================================================+ -//| CLASS 1: CDMIStochasticCalculator | -//+==================================================================+ +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ class CDMIStochasticCalculator { protected: - int m_dmi_period; - int m_fast_k_period; - int m_slow_k_period; - int m_smooth_period; - ENUM_DMI_OSC_TYPE m_osc_type; - - //--- Engines for Smoothing + CDMIEngine *m_dmi_engine; CMovingAverageCalculator m_slow_k_engine; CMovingAverageCalculator m_smooth_d_engine; - //--- Persistent Buffers - double m_high[], m_low[], m_close[]; - double m_pDM[], m_nDM[], m_TR[]; - double m_smoothed_pDM[], m_smoothed_nDM[], m_smoothed_TR[]; - double m_dmiOsc[]; - double m_fastK[]; + int m_dmi_period, m_fast_k_period, m_slow_k_period, m_smooth_period; + ENUM_DMI_OSC_TYPE m_osc_type; - virtual bool PreparePriceSeries(int rates_total, int start_index, const double &open[], const double &high[], const double &low[], const double &close[]); + //--- Internal Buffers + double m_pDI[], m_nDI[]; + double m_dmiOsc[], m_fastK[]; + + virtual void CreateEngine(void); public: - CDMIStochasticCalculator(void) {}; - virtual ~CDMIStochasticCalculator(void) {}; + CDMIStochasticCalculator(void); + virtual ~CDMIStochasticCalculator(void); - //--- Init now takes separate MA types for K and D bool Init(int dmi_p, int fast_k, int slow_k, int smooth_p, ENUM_MA_TYPE k_method, ENUM_MA_TYPE d_method, ENUM_DMI_OSC_TYPE osc_type); void Calculate(int rates_total, int prev_calculated, const double &open[], const double &high[], const double &low[], const double &close[], @@ -59,120 +41,65 @@ public: }; //+------------------------------------------------------------------+ -//| Init | +//| | +//+------------------------------------------------------------------+ +CDMIStochasticCalculator::CDMIStochasticCalculator(void) { m_dmi_engine = NULL; } +CDMIStochasticCalculator::~CDMIStochasticCalculator(void) { if(CheckPointer(m_dmi_engine) != POINTER_INVALID) delete m_dmi_engine; } + +void CDMIStochasticCalculator::CreateEngine(void) { m_dmi_engine = new CDMIEngine(); } + +//+------------------------------------------------------------------+ +//| | //+------------------------------------------------------------------+ bool CDMIStochasticCalculator::Init(int dmi_p, int fast_k, int slow_k, int smooth_p, ENUM_MA_TYPE k_method, ENUM_MA_TYPE d_method, ENUM_DMI_OSC_TYPE osc_type) { - m_dmi_period = (dmi_p < 1) ? 1 : dmi_p; - m_fast_k_period = (fast_k < 1) ? 1 : fast_k; - m_slow_k_period = (slow_k < 1) ? 1 : slow_k; - m_smooth_period = (smooth_p < 1) ? 1 : smooth_p; - m_osc_type = osc_type; - -// Initialize Engines with separate methods + m_dmi_period = dmi_p; + m_fast_k_period = fast_k; + m_slow_k_period = slow_k; + m_smooth_period = smooth_p; + m_osc_type = osc_type; + CreateEngine(); + if(!m_dmi_engine.Init(m_dmi_period)) + return false; if(!m_slow_k_engine.Init(m_slow_k_period, k_method)) return false; if(!m_smooth_d_engine.Init(m_smooth_period, d_method)) return false; - return true; } //+------------------------------------------------------------------+ -//| Main Calculation (Optimized) | +//| | //+------------------------------------------------------------------+ void CDMIStochasticCalculator::Calculate(int rates_total, int prev_calculated, const double &open[], const double &high[], const double &low[], const double &close[], double &k_buffer[], double &d_buffer[]) { - int required_bars = m_dmi_period + m_fast_k_period + m_slow_k_period + m_smooth_period; - if(rates_total < required_bars) + if(rates_total < m_dmi_period + m_fast_k_period) return; - int start_index; - if(prev_calculated == 0) - start_index = 0; - else - start_index = prev_calculated - 1; - -// Resize Buffers - if(ArraySize(m_high) != rates_total) + if(ArraySize(m_pDI) != rates_total) { - ArrayResize(m_high, rates_total); - ArrayResize(m_low, rates_total); - ArrayResize(m_close, rates_total); - - ArrayResize(m_pDM, rates_total); - ArrayResize(m_nDM, rates_total); - ArrayResize(m_TR, rates_total); - - ArrayResize(m_smoothed_pDM, rates_total); - ArrayResize(m_smoothed_nDM, rates_total); - ArrayResize(m_smoothed_TR, rates_total); - + ArrayResize(m_pDI, rates_total); + ArrayResize(m_nDI, rates_total); ArrayResize(m_dmiOsc, rates_total); ArrayResize(m_fastK, rates_total); } - if(!PreparePriceSeries(rates_total, start_index, open, high, low, close)) - return; +// 1. Calculate DI values + m_dmi_engine.Calculate(rates_total, prev_calculated, open, high, low, close, m_pDI, m_nDI); -//--- 1. Calculate DM and TR (Incremental) - int loop_start_dm = MathMax(1, start_index); +// 2. Calculate DMI Oscillator & Fast %K + int start_index = (prev_calculated > 0) ? prev_calculated - 1 : 0; + int loop_start = MathMax(m_dmi_period, start_index); - for(int i = loop_start_dm; i < rates_total; i++) + for(int i = loop_start; i < rates_total; i++) { - double high_diff = m_high[i] - m_high[i-1]; - double low_diff = m_low[i-1] - m_low[i]; - m_pDM[i] = (high_diff > low_diff && high_diff > 0) ? high_diff : 0; - m_nDM[i] = (low_diff > high_diff && low_diff > 0) ? low_diff : 0; - m_TR[i] = MathMax(m_high[i], m_close[i-1]) - MathMin(m_low[i], m_close[i-1]); - } - -//--- 2. Calculate Smoothed DM/TR (Wilder's Smoothing) - int loop_start_smooth = MathMax(m_dmi_period, start_index); - - for(int i = loop_start_smooth; i < rates_total; i++) - { - if(i == m_dmi_period) - { - // Initial Sum - double sum_pDM = 0, sum_nDM = 0, sum_TR = 0; - for(int j = 1; j <= m_dmi_period; j++) - { - sum_pDM += m_pDM[j]; - sum_nDM += m_nDM[j]; - sum_TR += m_TR[j]; - } - m_smoothed_pDM[i] = sum_pDM; - m_smoothed_nDM[i] = sum_nDM; - m_smoothed_TR[i] = sum_TR; - } - else - { - // Wilder's Smoothing: Prev - (Prev/N) + Curr - m_smoothed_pDM[i] = m_smoothed_pDM[i-1] - (m_smoothed_pDM[i-1] / m_dmi_period) + m_pDM[i]; - m_smoothed_nDM[i] = m_smoothed_nDM[i-1] - (m_smoothed_nDM[i-1] / m_dmi_period) + m_nDM[i]; - m_smoothed_TR[i] = m_smoothed_TR[i-1] - (m_smoothed_TR[i-1] / m_dmi_period) + m_TR[i]; - } - } - -//--- 3. Calculate DI and DMI Oscillator - for(int i = loop_start_smooth; i < rates_total; i++) - { - double pDI = 0, nDI = 0; - if(m_smoothed_TR[i] != 0.0) - { - pDI = (m_smoothed_pDM[i] / m_smoothed_TR[i]) * 100.0; - nDI = (m_smoothed_nDM[i] / m_smoothed_TR[i]) * 100.0; - } - if(m_osc_type == OSC_PDI_MINUS_NDI) - m_dmiOsc[i] = pDI - nDI; + m_dmiOsc[i] = m_pDI[i] - m_nDI[i]; else - m_dmiOsc[i] = nDI - pDI; + m_dmiOsc[i] = m_nDI[i] - m_pDI[i]; } -//--- 4. Calculate Fast %K on DMI Oscillator int fast_k_start = m_dmi_period + m_fast_k_period - 1; int loop_start_k = MathMax(fast_k_start, start_index); @@ -180,62 +107,25 @@ void CDMIStochasticCalculator::Calculate(int rates_total, int prev_calculated, c { double highest = m_dmiOsc[i]; double lowest = m_dmiOsc[i]; - for(int j = 1; j < m_fast_k_period; j++) { highest = MathMax(highest, m_dmiOsc[i-j]); lowest = MathMin(lowest, m_dmiOsc[i-j]); } - double range = highest - lowest; m_fastK[i] = (range == 0.0) ? 50.0 : ((m_dmiOsc[i] - lowest) / range) * 100.0; } -//--- 5. Calculate Slow %K (Main Line) using Engine +// 3. Smooth K and D m_slow_k_engine.CalculateOnArray(rates_total, prev_calculated, m_fastK, k_buffer, fast_k_start); - -//--- 6. Calculate %D (Signal Line) using Engine - int d_start = fast_k_start + m_slow_k_engine.GetPeriod() - 1; + int d_start = fast_k_start + m_slow_k_period - 1; m_smooth_d_engine.CalculateOnArray(rates_total, prev_calculated, k_buffer, d_buffer, d_start); } -//+------------------------------------------------------------------+ -//| Prepare Price (Standard - Optimized) | -//+------------------------------------------------------------------+ -bool CDMIStochasticCalculator::PreparePriceSeries(int rates_total, int start_index, const double &open[], const double &high[], const double &low[], const double &close[]) - { - for(int i = start_index; i < rates_total; i++) - { - m_high[i] = high[i]; - m_low[i] = low[i]; - m_close[i] = close[i]; - } - return true; - } - -//+==================================================================+ -//| CLASS 2: CDMIStochasticCalculator_HA | -//+==================================================================+ +//--- HA Subclass class CDMIStochasticCalculator_HA : public CDMIStochasticCalculator { -private: - CHeikinAshi_Calculator m_ha_calculator; - // Internal HA buffers - double m_ha_open[]; - protected: - virtual bool PreparePriceSeries(int rates_total, int start_index, const double &open[], const double &high[], const double &low[], const double &close[]) override; + virtual void CreateEngine(void) override { m_dmi_engine = new CDMIEngine_HA(); } }; - -//+------------------------------------------------------------------+ -//| | -//+------------------------------------------------------------------+ -bool CDMIStochasticCalculator_HA::PreparePriceSeries(int rates_total, int start_index, const double &open[], const double &high[], const double &low[], const double &close[]) - { - if(ArraySize(m_ha_open) != rates_total) - ArrayResize(m_ha_open, rates_total); - - m_ha_calculator.Calculate(rates_total, start_index, open, high, low, close, m_ha_open, m_high, m_low, m_close); - return true; - } //+------------------------------------------------------------------+