diff --git a/Include/MyIncludes/Cyber_Cycle_Calculator.mqh b/Include/MyIncludes/Cyber_Cycle_Calculator.mqh index b83a2d3..fb3ab17 100644 --- a/Include/MyIncludes/Cyber_Cycle_Calculator.mqh +++ b/Include/MyIncludes/Cyber_Cycle_Calculator.mqh @@ -1,7 +1,7 @@ //+------------------------------------------------------------------+ //| Cyber_Cycle_Calculator.mqh| //| Calculation engine for the John Ehlers' Cyber Cycle. | -//| VERSION 2.00: Optimized for incremental calculation. | +//| VERSION 2.10: Added CalculateOnArray support. | //| Copyright 2026, xxxxxxxx | //+------------------------------------------------------------------+ #property copyright "Copyright 2026, xxxxxxxx" @@ -30,9 +30,12 @@ public: bool Init(double alpha); - //--- Updated: Accepts prev_calculated + //--- Standard Calculation (OHLC) 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 &cycle_out[], double &signal_out[]); + + //--- Calculation on Custom Array + void CalculateOnArray(int rates_total, int prev_calculated, const double &src_buffer[], double &cycle_out[], double &signal_out[]); }; //+------------------------------------------------------------------+ @@ -45,7 +48,7 @@ bool CCyberCycleCalculator::Init(double alpha) } //+------------------------------------------------------------------+ -//| Main Calculation (Optimized) | +//| Main Calculation (Wrapper for OHLC) | //+------------------------------------------------------------------+ void CCyberCycleCalculator::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 &cycle_out[], double &signal_out[]) @@ -53,31 +56,44 @@ void CCyberCycleCalculator::Calculate(int rates_total, int prev_calculated, ENUM if(rates_total < 7) return; -//--- 1. Determine Start Index int start_index = (prev_calculated == 0) ? 0 : prev_calculated - 1; -//--- 2. Resize Buffers if(ArraySize(m_price) != rates_total) - { ArrayResize(m_price, rates_total); + + if(!PreparePriceSeries(rates_total, start_index, price_type, open, high, low, close)) + return; + +// Delegate to generic array calculation + CalculateOnArray(rates_total, prev_calculated, m_price, cycle_out, signal_out); + } + +//+------------------------------------------------------------------+ +//| Calculate On Array (Core Logic) | +//+------------------------------------------------------------------+ +void CCyberCycleCalculator::CalculateOnArray(int rates_total, int prev_calculated, const double &src_buffer[], double &cycle_out[], double &signal_out[]) + { + if(rates_total < 7) + return; + + int start_index = (prev_calculated == 0) ? 0 : prev_calculated - 1; + +// Resize internal buffers + if(ArraySize(m_smooth) != rates_total) + { ArrayResize(m_smooth, rates_total); ArrayResize(m_cycle, rates_total); } -//--- 3. Prepare Price - if(!PreparePriceSeries(rates_total, start_index, price_type, open, high, low, close)) - return; - -//--- 4. Main Loop -// Start at index 6 to ensure enough history for smoothing (i-3) and cycle (i-2) +// Main Loop int loop_start = MathMax(6, start_index); -// Initialization for the very first bars (if needed) +// Initialization if(loop_start == 6) { for(int k=0; k<6; k++) { - m_smooth[k] = m_price[k]; + m_smooth[k] = src_buffer[k]; m_cycle[k] = 0; cycle_out[k] = 0; signal_out[k] = 0; @@ -87,11 +103,9 @@ void CCyberCycleCalculator::Calculate(int rates_total, int prev_calculated, ENUM for(int i = loop_start; i < rates_total; i++) { // Step 1: Pre-smoothing (4-bar FIR filter) - m_smooth[i] = (m_price[i] + 2.0 * m_price[i-1] + 2.0 * m_price[i-2] + m_price[i-3]) / 6.0; + m_smooth[i] = (src_buffer[i] + 2.0 * src_buffer[i-1] + 2.0 * src_buffer[i-2] + src_buffer[i-3]) / 6.0; // Step 2: Calculate Cyber Cycle - // Formula: Cycle = (1 - 0.5*alpha)^2 * (Smooth[i] - 2*Smooth[i-1] + Smooth[i-2]) + 2*(1-alpha)*Cycle[i-1] - (1-alpha)^2*Cycle[i-2] - double term1 = (1.0 - 0.5 * m_alpha) * (1.0 - 0.5 * m_alpha) * (m_smooth[i] - 2.0 * m_smooth[i-1] + m_smooth[i-2]); double term2 = 2.0 * (1.0 - m_alpha) * m_cycle[i-1]; double term3 = (1.0 - m_alpha) * (1.0 - m_alpha) * m_cycle[i-2]; @@ -101,14 +115,8 @@ void CCyberCycleCalculator::Calculate(int rates_total, int prev_calculated, ENUM // Output cycle_out[i] = m_cycle[i]; - // Step 3: Signal Line (Cycle delayed by 1 bar, effectively Cycle[i-1]) - // Note: Original code used i-2, but standard Cyber Cycle signal is often i-1. - // Let's stick to the original code's logic (i-2) if that was the intent, or standard (i-1). - // Ehlers usually defines the trigger as Cycle[i-1]. - // The previous code had `signal_buffer[i] = cycle_buffer[i-2]`. Let's keep it for consistency, - // but note that i-1 is more common for a fast trigger. - - signal_out[i] = m_cycle[i-1]; // Changed to i-1 for standard Ehlers trigger behavior + // Step 3: Signal Line (1 bar delay) + signal_out[i] = m_cycle[i-1]; } } @@ -144,7 +152,7 @@ bool CCyberCycleCalculator::PreparePriceSeries(int rates_total, int start_index, break; default: m_price[i] = (high[i] + low[i]) / 2.0; - break; // Default to Median (Ehlers standard) + break; } } return true;