From 3f76d541776f17048e1e2c7533adb3f45fdf8cf3 Mon Sep 17 00:00:00 2001 From: Toh4iem9 Date: Mon, 5 Jan 2026 12:02:20 +0100 Subject: [PATCH] new files added --- Include/MyIncludes/CyclePeriod_Calculator.mqh | 146 ++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 Include/MyIncludes/CyclePeriod_Calculator.mqh diff --git a/Include/MyIncludes/CyclePeriod_Calculator.mqh b/Include/MyIncludes/CyclePeriod_Calculator.mqh new file mode 100644 index 0000000..335ab67 --- /dev/null +++ b/Include/MyIncludes/CyclePeriod_Calculator.mqh @@ -0,0 +1,146 @@ +//+------------------------------------------------------------------+ +//| CyclePeriod_Calculator.mqh | +//| Calculation engine for John Ehlers' Dominant Cycle Period. | +//| Method: Homodyne Discriminator. | +//| Copyright 2025, xxxxxxxx | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2025, xxxxxxxx" + +#include + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +class CCyclePeriodCalculator + { +protected: + //--- Persistent Buffers + double m_price[]; + double m_smooth[]; + double m_detrender[]; + double m_q1[]; + double m_i1[]; + double m_q2[]; + double m_i2[]; + double m_period[]; + double m_smooth_period[]; // Final output + + virtual bool PreparePriceSeries(int rates_total, int start_index, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]); + +public: + CCyclePeriodCalculator(void) {}; + virtual ~CCyclePeriodCalculator(void) {}; + + bool Init(); + void Calculate(int rates_total, int prev_calculated, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[], double &period_buffer[]); + }; + +//+------------------------------------------------------------------+ +//| Init | +//+------------------------------------------------------------------+ +bool CCyclePeriodCalculator::Init() + { + return true; + } + +//+------------------------------------------------------------------+ +//| Main Calculation (Homodyne Discriminator) | +//+------------------------------------------------------------------+ +void CCyclePeriodCalculator::Calculate(int rates_total, int prev_calculated, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[], double &period_buffer[]) + { + if(rates_total < 10) + return; + + int start_index = (prev_calculated > 0) ? prev_calculated - 1 : 0; + +// Resize buffers + if(ArraySize(m_price) != rates_total) + { + ArrayResize(m_price, rates_total); + ArrayResize(m_smooth, rates_total); + ArrayResize(m_detrender, rates_total); + ArrayResize(m_q1, rates_total); + ArrayResize(m_i1, rates_total); + ArrayResize(m_q2, rates_total); + ArrayResize(m_i2, rates_total); + ArrayResize(m_period, rates_total); + ArrayResize(m_smooth_period, rates_total); + } + + if(!PreparePriceSeries(rates_total, start_index, price_type, open, high, low, close)) + return; + +// Ehlers' Homodyne Discriminator Logic + int loop_start = MathMax(6, start_index); + + for(int i = loop_start; i < rates_total; i++) + { + // 1. Smooth Price (4-bar WMA) + m_smooth[i] = (4*m_price[i] + 3*m_price[i-1] + 2*m_price[i-2] + m_price[i-3]) / 10.0; + + // 2. Detrend (Hilbert Transform component) + // Amplitude correction factor: 0.0962 for 6-bar period, 0.5769 for 3-bar + // Ehlers standard detrender: + double c1 = 0.0962; + double c2 = 0.5769; + + double detrender_raw = (c1*m_smooth[i] + c2*m_smooth[i-2] - c2*m_smooth[i-4] - c1*m_smooth[i-6]) * (0.075*m_period[i-1] + 0.54); + m_detrender[i] = detrender_raw; + + // 3. Compute InPhase and Quadrature components + // Q1 is the detrender delayed by 3 bars (90 degrees of a typical bar cycle) + m_q1[i] = (c1*m_detrender[i] + c2*m_detrender[i-2] - c2*m_detrender[i-4] - c1*m_detrender[i-6]) * (0.075*m_period[i-1] + 0.54); + m_i1[i] = m_detrender[i-3]; + + // 4. Advance the phase of I1 and Q1 by 90 degrees + double jI = (c1*m_i1[i] + c2*m_i1[i-2] - c2*m_i1[i-4] - c1*m_i1[i-6]) * (0.075*m_period[i-1] + 0.54); + double jQ = (c1*m_q1[i] + c2*m_q1[i-2] - c2*m_q1[i-4] - c1*m_q1[i-6]) * (0.075*m_period[i-1] + 0.54); + + // 5. Phasor addition for Homodyne + m_i2[i] = m_i1[i] - jQ; + m_q2[i] = m_q1[i] + jI; + + // 6. Smooth the I2 and Q2 components + m_i2[i] = 0.2*m_i2[i] + 0.8*m_i2[i-1]; + m_q2[i] = 0.2*m_q2[i] + 0.8*m_q2[i-1]; + + // 7. Homodyne Discriminator + double re = m_i2[i]*m_i2[i-1] + m_q2[i]*m_q2[i-1]; + double im = m_i2[i]*m_q2[i-1] - m_q2[i]*m_i2[i-1]; + + double period = 0; + if(im != 0 && re != 0) + period = 360.0 / (atan(im/re) * 180.0 / M_PI); + + // Fix wrap-around and limits + if(period > 1.5 * m_period[i-1]) + period = 1.5 * m_period[i-1]; + if(period < 0.67 * m_period[i-1]) + period = 0.67 * m_period[i-1]; + if(period < 6) + period = 6; + if(period > 50) + period = 50; + + m_period[i] = 0.2*period + 0.8*m_period[i-1]; + + // 8. Final Smooth (Median Filter equivalent) + m_smooth_period[i] = 0.33*m_period[i] + 0.67*m_smooth_period[i-1]; + + period_buffer[i] = m_smooth_period[i]; + } + } + +//+------------------------------------------------------------------+ +//| Prepare Price | +//+------------------------------------------------------------------+ +bool CCyclePeriodCalculator::PreparePriceSeries(int rates_total, int start_index, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]) + { + for(int i = start_index; i < rates_total; i++) + { + // Ehlers typically uses (High+Low)/2 + m_price[i] = (high[i] + low[i]) / 2.0; + } + return true; + } +//+------------------------------------------------------------------+