diff --git a/Include/MyIncludes/Cyber_Cycle_Calculator.mqh b/Include/MyIncludes/Cyber_Cycle_Calculator.mqh new file mode 100644 index 0000000..e17ed48 --- /dev/null +++ b/Include/MyIncludes/Cyber_Cycle_Calculator.mqh @@ -0,0 +1,125 @@ +//+------------------------------------------------------------------+ +//| Cyber_Cycle_Calculator.mqh| +//| Calculation engine for the John Ehlers' Cyber Cycle. | +//| Copyright 2025, xxxxxxxx | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2025, xxxxxxxx" + +#include + +//+==================================================================+ +//| | +//| CLASS 1: CCyberCycleCalculator (Base Class) | +//| | +//+==================================================================+ +class CCyberCycleCalculator + { +protected: + double m_alpha; + double m_price[]; + + virtual bool PreparePriceSeries(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[]); + +public: + CCyberCycleCalculator(void) {}; + virtual ~CCyberCycleCalculator(void) {}; + + bool Init(double alpha); + void Calculate(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], + double &cycle_buffer[], double &signal_buffer[]); + }; + +//+------------------------------------------------------------------+ +bool CCyberCycleCalculator::Init(double alpha) + { + m_alpha = alpha; + return true; + } + +//+------------------------------------------------------------------+ +void CCyberCycleCalculator::Calculate(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], + double &cycle_buffer[], double &signal_buffer[]) + { + if(rates_total < 7) + return; + if(!PreparePriceSeries(rates_total, open, high, low, close)) + return; + + double smooth_buffer[]; + ArrayResize(smooth_buffer, rates_total); + +// Step 1: Pre-smoothing with a 4-bar FIR filter + for(int i = 3; i < rates_total; i++) + { + smooth_buffer[i] = (m_price[i] + 2.0 * m_price[i-1] + 2.0 * m_price[i-2] + m_price[i-3]) / 6.0; + } + + double cycle_prev = 0, cycle_prev2 = 0; + +// Step 2 & 3: Calculate Cyber Cycle with initialization + for(int i = 0; i < rates_total; i++) + { + double cycle_val = 0; + if(i < 7) // Initialization period as per Ehlers' article + { + if(i > 1) + cycle_val = (m_price[i] - 2.0 * m_price[i-1] + m_price[i-2]) / 4.0; + } + else // Main recursive calculation + { + double term1 = (1.0 - 0.5 * m_alpha) * (1.0 - 0.5 * m_alpha) * (smooth_buffer[i] - 2.0 * smooth_buffer[i-1] + smooth_buffer[i-2]); + double term2 = 2.0 * (1.0 - m_alpha) * cycle_prev; + double term3 = (1.0 - m_alpha) * (1.0 - m_alpha) * cycle_prev2; + cycle_val = term1 + term2 - term3; + } + + cycle_buffer[i] = cycle_val; + + // Step 4: Create the signal line (2-bar delay) + if(i > 1) + signal_buffer[i] = cycle_buffer[i-2]; + else + signal_buffer[i] = 0; + + // Update previous values for next iteration + cycle_prev2 = cycle_prev; + cycle_prev = cycle_val; + } + } + +//+------------------------------------------------------------------+ +bool CCyberCycleCalculator::PreparePriceSeries(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[]) + { + ArrayResize(m_price, rates_total); +// Ehlers' original paper uses Median Price + for(int i=0; i