diff --git a/Include/MyIncludes/ADX_Calculator.mqh b/Include/MyIncludes/ADX_Calculator.mqh new file mode 100644 index 0000000..f578f43 --- /dev/null +++ b/Include/MyIncludes/ADX_Calculator.mqh @@ -0,0 +1,200 @@ +//+------------------------------------------------------------------+ +//| ADX_Calculator.mqh | +//| Calculation engine for Standard and Heikin Ashi ADX. | +//| Copyright 2025, xxxxxxxx | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2025, xxxxxxxx" + +#include + +//+==================================================================+ +//| | +//| CLASS 1: CADXCalculator (Base Class) | +//| | +//+==================================================================+ +class CADXCalculator + { +protected: + int m_adx_period; + + //--- Virtual method for preparing the raw directional movement values. + //--- CORRECTED: Added 'open' to the signature for the derived class. + virtual void PrepareDirectionalMovement(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], + double &pDM[], double &nDM[], double &TR[]); + +public: + CADXCalculator(void) {}; + virtual ~CADXCalculator(void) {}; + + //--- Public methods + bool Init(int period); + int GetPeriod(void) const { return m_adx_period; } + //--- CORRECTED: Added 'open' to the signature. + void Calculate(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], + double &adx_buffer[], double &pdi_buffer[], double &ndi_buffer[]); + }; + +//+------------------------------------------------------------------+ +//| CADXCalculator: Initialization | +//+------------------------------------------------------------------+ +bool CADXCalculator::Init(int period) + { + m_adx_period = (period < 1) ? 1 : period; + return true; + } + +//+------------------------------------------------------------------+ +//| CADXCalculator: Main Calculation Method (Shared Logic) | +//+------------------------------------------------------------------+ +void CADXCalculator::Calculate(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], + double &adx_buffer[], double &pdi_buffer[], double &ndi_buffer[]) + { + if(rates_total < m_adx_period * 2) + return; + +//--- STEP 1: Calculate raw +DM, -DM, and TR (delegated to virtual method) + double pDM[], nDM[], TR[]; + PrepareDirectionalMovement(rates_total, open, high, low, close, pDM, nDM, TR); + +//--- Intermediate calculation buffers + double smoothed_pdm[], smoothed_ndm[], smoothed_tr[], dx[]; + ArrayResize(smoothed_pdm, rates_total); + ArrayResize(smoothed_ndm, rates_total); + ArrayResize(smoothed_tr, rates_total); + ArrayResize(dx, rates_total); + +//--- STEP 2: Calculate Smoothed PDM, NDM, and TR + for(int i = m_adx_period; i < rates_total; i++) + { + if(i == m_adx_period) // First calculation is a simple sum + { + double sum_pdm=0, sum_ndm=0, sum_tr=0; + for(int j=1; j<=m_adx_period; j++) + { + sum_pdm += pDM[j]; + sum_ndm += nDM[j]; + sum_tr += TR[j]; + } + smoothed_pdm[i] = sum_pdm; + smoothed_ndm[i] = sum_ndm; + smoothed_tr[i] = sum_tr; + } + else // Subsequent calculations use Wilder's smoothing + { + smoothed_pdm[i] = smoothed_pdm[i-1] - (smoothed_pdm[i-1] / m_adx_period) + pDM[i]; + smoothed_ndm[i] = smoothed_ndm[i-1] - (smoothed_ndm[i-1] / m_adx_period) + nDM[i]; + smoothed_tr[i] = smoothed_tr[i-1] - (smoothed_tr[i-1] / m_adx_period) + TR[i]; + } + } + +//--- STEP 3: Calculate +DI, -DI, and DX + for(int i = m_adx_period; i < rates_total; i++) + { + if(smoothed_tr[i] != 0.0) + { + pdi_buffer[i] = (smoothed_pdm[i] / smoothed_tr[i]) * 100.0; + ndi_buffer[i] = (smoothed_ndm[i] / smoothed_tr[i]) * 100.0; + } + + double di_sum = pdi_buffer[i] + ndi_buffer[i]; + if(di_sum != 0.0) + dx[i] = MathAbs(pdi_buffer[i] - ndi_buffer[i]) / di_sum * 100.0; + else + dx[i] = 0.0; + } + +//--- STEP 4: Smooth DX to get the final ADX value + for(int i = m_adx_period * 2 - 1; i < rates_total; i++) + { + if(i == m_adx_period * 2 - 1) // First ADX value is a simple average + { + double sum_dx = 0; + for(int j=i-m_adx_period+1; j<=i; j++) + sum_dx += dx[j]; + adx_buffer[i] = sum_dx / m_adx_period; + } + else // Subsequent ADX values are smoothed + { + adx_buffer[i] = (adx_buffer[i-1] * (m_adx_period - 1) + dx[i]) / m_adx_period; + } + } + } + +//+------------------------------------------------------------------+ +//| CADXCalculator: Prepares raw DM and TR from standard prices. | +//+------------------------------------------------------------------+ +void CADXCalculator::PrepareDirectionalMovement(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], + double &pDM[], double &nDM[], double &TR[]) + { + ArrayResize(pDM, rates_total); + ArrayResize(nDM, rates_total); + ArrayResize(TR, rates_total); + + for(int i = 1; i < rates_total; i++) + { + pDM[i] = high[i] - high[i-1]; + nDM[i] = low[i-1] - low[i]; + + if(pDM[i] < 0 || pDM[i] < nDM[i]) + pDM[i] = 0; + if(nDM[i] < 0 || nDM[i] < pDM[i]) + nDM[i] = 0; + + TR[i] = MathMax(high[i], close[i-1]) - MathMin(low[i], close[i-1]); + } + } + +//+==================================================================+ +//| | +//| CLASS 2: CADXCalculator_HA (Heikin Ashi) | +//| | +//+==================================================================+ +class CADXCalculator_HA : public CADXCalculator + { +private: + CHeikinAshi_Calculator m_ha_calculator; // Instance of the HA calculator tool + +protected: + //--- Overridden method to prepare Heikin Ashi based DM and TR + //--- CORRECTED: Signature now matches the base class. + virtual void PrepareDirectionalMovement(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], + double &pDM[], double &nDM[], double &TR[]) override; + }; + +//+------------------------------------------------------------------+ +//| CADXCalculator_HA: Prepares raw DM and TR from HA prices. | +//+------------------------------------------------------------------+ +void CADXCalculator_HA::PrepareDirectionalMovement(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], + double &pDM[], double &nDM[], double &TR[]) + { +//--- Intermediate Heikin Ashi Buffers + 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); + +//--- Calculate the HA candles first +//--- CORRECTED: Removed invalid GetPointer() call and now passing 'open' correctly. + m_ha_calculator.Calculate(rates_total, open, high, low, close, ha_open, ha_high, ha_low, ha_close); + +//--- Now, calculate DM and TR using the HA candles + ArrayResize(pDM, rates_total); + ArrayResize(nDM, rates_total); + ArrayResize(TR, rates_total); + + for(int i = 1; i < rates_total; i++) + { + pDM[i] = ha_high[i] - ha_high[i-1]; + nDM[i] = ha_low[i-1] - ha_low[i]; + + if(pDM[i] < 0 || pDM[i] < nDM[i]) + pDM[i] = 0; + if(nDM[i] < 0 || nDM[i] < pDM[i]) + nDM[i] = 0; + + TR[i] = MathMax(ha_high[i], ha_close[i-1]) - MathMin(ha_low[i], ha_close[i-1]); + } + } +//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+