From e6231832cba445ca28d415ff92e8320665766270 Mon Sep 17 00:00:00 2001 From: Toh4iem9 Date: Sun, 18 Jan 2026 19:22:13 +0100 Subject: [PATCH] refactor(indicators): Optimized for incremental calculation --- Include/MyIncludes/RSIH_Calculator.mqh | 279 ++++++++++++++++--------- 1 file changed, 179 insertions(+), 100 deletions(-) diff --git a/Include/MyIncludes/RSIH_Calculator.mqh b/Include/MyIncludes/RSIH_Calculator.mqh index d9af203..88ef9c2 100644 --- a/Include/MyIncludes/RSIH_Calculator.mqh +++ b/Include/MyIncludes/RSIH_Calculator.mqh @@ -2,79 +2,149 @@ //| RSIH_Calculator.mqh | //| Calculation engine for Ehlers' RSI with Hann Windowing (RSIH) | //| and Noise Elimination Technology (NET). | -//| Copyright 2025, xxxxxxxx | +//| VERSION 2.00: Optimized for incremental calculation. | +//| Copyright 2026, xxxxxxxx | //+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" +#property copyright "Copyright 2026, xxxxxxxx" -#include +#include //+==================================================================+ -//| | //| CLASS 1: CRSIHCalculator (Base Class) | -//| | //+==================================================================+ class CRSIHCalculator { protected: int m_period_rsi; int m_period_net; - double m_price[]; - virtual bool PreparePriceSeries(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]); + //--- Composition: Windowed MA Engines for CU and CD + CWindowedMACalculator *m_cu_engine; + CWindowedMACalculator *m_cd_engine; + + //--- Persistent Buffers + double m_price[]; + double m_cu_raw[]; // Raw Closes Up + double m_cd_raw[]; // Raw Closes Down + double m_cu_smooth[]; // Smoothed CU + double m_cd_smooth[]; // Smoothed CD + + 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[]); + virtual void CreateEngines(void); public: - CRSIHCalculator(void) {}; - virtual ~CRSIHCalculator(void) {}; + CRSIHCalculator(void); + virtual ~CRSIHCalculator(void); bool Init(int rsi_period, int net_period); - void Calculate(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[], + 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 &rsih_buffer[], double &net_buffer[]); }; +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CRSIHCalculator::CRSIHCalculator(void) + { + m_cu_engine = NULL; + m_cd_engine = NULL; + } + +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CRSIHCalculator::~CRSIHCalculator(void) + { + if(CheckPointer(m_cu_engine) != POINTER_INVALID) + delete m_cu_engine; + if(CheckPointer(m_cd_engine) != POINTER_INVALID) + delete m_cd_engine; + } + +//+------------------------------------------------------------------+ +//| Factory Method | +//+------------------------------------------------------------------+ +void CRSIHCalculator::CreateEngines(void) + { + m_cu_engine = new CWindowedMACalculator(); + m_cd_engine = new CWindowedMACalculator(); + } + +//+------------------------------------------------------------------+ +//| Init | //+------------------------------------------------------------------+ bool CRSIHCalculator::Init(int rsi_period, int net_period) { m_period_rsi = (rsi_period < 2) ? 2 : rsi_period; m_period_net = (net_period < 2) ? 2 : net_period; + + CreateEngines(); + +// Initialize engines with SOURCE_PRICE (we pass raw CU/CD arrays) + if(CheckPointer(m_cu_engine) == POINTER_INVALID || !m_cu_engine.Init(m_period_rsi, SOURCE_PRICE)) + return false; + if(CheckPointer(m_cd_engine) == POINTER_INVALID || !m_cd_engine.Init(m_period_rsi, SOURCE_PRICE)) + return false; + return true; } //+------------------------------------------------------------------+ -void CRSIHCalculator::Calculate(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[], +//| Main Calculation (Optimized) | +//+------------------------------------------------------------------+ +void CRSIHCalculator::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 &rsih_buffer[], double &net_buffer[]) { if(rates_total < m_period_rsi + 1) return; - if(!PreparePriceSeries(rates_total, price_type, open, high, low, close)) + + int start_index = (prev_calculated == 0) ? 0 : prev_calculated - 1; + +// Resize buffers + if(ArraySize(m_price) != rates_total) + { + ArrayResize(m_price, rates_total); + ArrayResize(m_cu_raw, rates_total); + ArrayResize(m_cd_raw, rates_total); + ArrayResize(m_cu_smooth, rates_total); + ArrayResize(m_cd_smooth, rates_total); + } + +// 1. Prepare Price + if(!PreparePriceSeries(rates_total, start_index, price_type, open, high, low, close)) return; -// --- Step 1: Calculate the base RSIH indicator --- - for(int i = m_period_rsi; i < rates_total; i++) +// 2. Calculate Raw CU and CD + int loop_start = MathMax(1, start_index); + for(int i = loop_start; i < rates_total; i++) { - double cu = 0.0, cd = 0.0; - for(int j = 1; j <= m_period_rsi; j++) - { - double diff = m_price[i - j + 1] - m_price[i - j]; - double weight = 1.0 - cos(2 * M_PI * j / (m_period_rsi + 1.0)); - if(diff > 0) - cu += diff * weight; - else - cd += -diff * weight; - } - if(cu + cd > 0) - rsih_buffer[i] = (cu - cd) / (cu + cd); + double diff = m_price[i] - m_price[i-1]; + m_cu_raw[i] = (diff > 0) ? diff : 0; + m_cd_raw[i] = (diff < 0) ? -diff : 0; + } + +// 3. Smooth CU and CD using Windowed MA Engine + m_cu_engine.CalculateOnArray(rates_total, prev_calculated, m_cu_raw, m_cu_smooth); + m_cd_engine.CalculateOnArray(rates_total, prev_calculated, m_cd_raw, m_cd_smooth); + +// 4. Calculate RSIH + int rsih_start = MathMax(m_period_rsi, start_index); + for(int i = rsih_start; i < rates_total; i++) + { + double sum = m_cu_smooth[i] + m_cd_smooth[i]; + if(sum > 0) + rsih_buffer[i] = (m_cu_smooth[i] - m_cd_smooth[i]) / sum; else rsih_buffer[i] = (i > 0) ? rsih_buffer[i-1] : 0.0; } -// --- Step 2: Apply Noise Elimination Technology (NET) --- +// 5. Calculate NET (Noise Elimination Technology) if(m_period_net > 0) { double denominator = 0.5 * m_period_net * (m_period_net - 1); - if(denominator <= 0) - return; + int net_start = MathMax(m_period_rsi + m_period_net, start_index); - for(int i = m_period_rsi + m_period_net; i < rates_total; i++) + for(int i = net_start; i < rates_total; i++) { double numerator = 0; // Double loop for Kendall correlation @@ -82,11 +152,8 @@ void CRSIHCalculator::Calculate(int rates_total, ENUM_APPLIED_PRICE price_type, { for(int k = 0; k < j; k++) { - // Ehlers' simplified formula is Num = Num - Sign(X[count] - X[K]) - // This implies adding the sign of (X[fresher] - X[older]) - // In our arrays, i-k is fresher than i-j + // Sign(X[fresher] - X[older]) double diff = rsih_buffer[i-k] - rsih_buffer[i-j]; - // CORRECTED: Use addition instead of subtraction to match Ehlers' logic numerator += (diff > 0 ? 1 : (diff < 0 ? -1 : 0)); } } @@ -96,90 +163,102 @@ void CRSIHCalculator::Calculate(int rates_total, ENUM_APPLIED_PRICE price_type, } //+------------------------------------------------------------------+ -bool CRSIHCalculator::PreparePriceSeries(int rates_total, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]) +//| Prepare Price (Standard) | +//+------------------------------------------------------------------+ +bool CRSIHCalculator::PreparePriceSeries(int rates_total, int start_index, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]) { - ArrayResize(m_price, rates_total); - switch(price_type) + for(int i = start_index; i < rates_total; i++) { - case PRICE_CLOSE: - ArrayCopy(m_price, close, 0, 0, rates_total); - break; - case PRICE_OPEN: - ArrayCopy(m_price, open, 0, 0, rates_total); - break; - case PRICE_HIGH: - ArrayCopy(m_price, high, 0, 0, rates_total); - break; - case PRICE_LOW: - ArrayCopy(m_price, low, 0, 0, rates_total); - break; - case PRICE_MEDIAN: - for(int i=0; i