From 22976a9bbea1d86d80da2220bea9a7f1b5d61212 Mon Sep 17 00:00:00 2001 From: Toh4iem9 Date: Sun, 19 Jul 2026 17:30:00 +0200 Subject: [PATCH] new files added --- .../Laguerre_Adaptive_RSI_Calculator.mqh | 433 ++++++++++++++++++ 1 file changed, 433 insertions(+) create mode 100644 Include/MyIncludes/Laguerre_Adaptive_RSI_Calculator.mqh diff --git a/Include/MyIncludes/Laguerre_Adaptive_RSI_Calculator.mqh b/Include/MyIncludes/Laguerre_Adaptive_RSI_Calculator.mqh new file mode 100644 index 0000000..d0a6e94 --- /dev/null +++ b/Include/MyIncludes/Laguerre_Adaptive_RSI_Calculator.mqh @@ -0,0 +1,433 @@ +//+------------------------------------------------------------------+ +//| Laguerre_Adaptive_RSI_Calculator.mqh | +//| Copyright 2026, xxxxxxxx| +//+------------------------------------------------------------------+ +#property copyright "Copyright 2026, xxxxxxxx" +#property version "1.00" // Adaptive Laguerre RSI engine with ER/ATR/StDev dynamic Gamma +#property description "Stateful calculator implementing John Ehlers' Laguerre RSI with adaptive Gamma scaling." + +#ifndef LAGUERRE_ADAPTIVE_RSI_CALCULATOR_MQH +#define LAGUERRE_ADAPTIVE_RSI_CALCULATOR_MQH + +#include +#include +#include +#include +#include // Share adaptive enums + +//+==================================================================+ +//| CLASS: CLaguerreAdaptiveRSICalculator | +//+==================================================================+ +class CLaguerreAdaptiveRSICalculator + { +protected: + ENUM_ADAPTIVE_METHOD m_method; + int m_adaptive_period; + double m_gamma_min; + double m_gamma_max; + bool m_is_ha; + + int m_signal_period; + ENUM_MA_TYPE m_signal_ma_type; + + CEfficiencyRatioCalculator *m_er_calc; + CATRCalculator *m_atr_calc; + CMovingAverageCalculator *m_ma_calc; + + //--- Persistent State Registers + double m_price[]; + double m_L0[], m_L1[], m_L2[], m_L3[]; + double m_adaptive_metric[]; + double m_temp_atr[]; + double m_temp_stdev[]; + + 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[]); + void NormalizeMetric(int rates_total, int prev_calculated, const double &src_array[]); + +public: + CLaguerreAdaptiveRSICalculator(void); + virtual ~CLaguerreAdaptiveRSICalculator(void); + + bool Init(ENUM_ADAPTIVE_METHOD method, int adaptive_period, double gamma_min, double gamma_max, int signal_p, ENUM_MA_TYPE signal_ma, bool is_ha); + + //--- Standard Calculate (Without volume data) + 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 &lrsi_buffer[], double &signal_buffer[]); + + //--- Overloaded Calculate (With Volume for VWMA support) + 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[], + const long &volume[], + double &lrsi_buffer[], double &signal_buffer[]); + }; + +//+------------------------------------------------------------------+ +//| Constructor | +//+------------------------------------------------------------------+ +CLaguerreAdaptiveRSICalculator::CLaguerreAdaptiveRSICalculator(void) + : m_er_calc(NULL), + m_atr_calc(NULL), + m_ma_calc(NULL), + m_is_ha(false) + { + m_ma_calc = new CMovingAverageCalculator(); + } + +//+------------------------------------------------------------------+ +//| Destructor | +//+------------------------------------------------------------------+ +CLaguerreAdaptiveRSICalculator::~CLaguerreAdaptiveRSICalculator(void) + { + if(CheckPointer(m_er_calc) != POINTER_INVALID) + delete m_er_calc; + if(CheckPointer(m_atr_calc) != POINTER_INVALID) + delete m_atr_calc; + if(CheckPointer(m_ma_calc) != POINTER_INVALID) + delete m_ma_calc; + } + +//+------------------------------------------------------------------+ +//| Init | +//+------------------------------------------------------------------+ +bool CLaguerreAdaptiveRSICalculator::Init(ENUM_ADAPTIVE_METHOD method, int adaptive_period, double gamma_min, double gamma_max, int signal_p, ENUM_MA_TYPE signal_ma, bool is_ha) + { + m_method = method; + m_adaptive_period = (adaptive_period < 2) ? 2 : adaptive_period; + m_gamma_min = fmax(0.0, fmin(1.0, gamma_min)); + m_gamma_max = fmax(0.0, fmin(1.0, gamma_max)); + m_is_ha = is_ha; + m_signal_period = (signal_p < 1) ? 1 : signal_p; + m_signal_ma_type = signal_ma; + + if(CheckPointer(m_er_calc) != POINTER_INVALID) + { + delete m_er_calc; + m_er_calc = NULL; + } + if(CheckPointer(m_atr_calc) != POINTER_INVALID) + { + delete m_atr_calc; + m_atr_calc = NULL; + } + + if(m_method == METHOD_EFFICIENCY_RATIO) + { + m_er_calc = new CEfficiencyRatioCalculator(); + if(CheckPointer(m_er_calc) == POINTER_INVALID || !m_er_calc.Init(m_adaptive_period)) + return false; + } + else + if(m_method == METHOD_ATR) + { + if(m_is_ha) + m_atr_calc = new CATRCalculator_HA(); + else + m_atr_calc = new CATRCalculator(); + + if(CheckPointer(m_atr_calc) == POINTER_INVALID || !m_atr_calc.Init(m_adaptive_period, ATR_POINTS)) + return false; + } + + if(!m_ma_calc.Init(m_signal_period, m_signal_ma_type)) + return false; + + return true; + } + +//+------------------------------------------------------------------+ +//| Calculate (Standard - No Volume) | +//+------------------------------------------------------------------+ +void CLaguerreAdaptiveRSICalculator::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 &lrsi_buffer[], double &signal_buffer[]) + { + int required_bars = m_adaptive_period * 2 + 5; + if(rates_total < required_bars) + return; + +//--- Resize state buffers & enforce chronological safety + if(ArraySize(m_price) != rates_total) + { + ArrayResize(m_price, rates_total); + ArrayResize(m_L0, rates_total); + ArrayResize(m_L1, rates_total); + ArrayResize(m_L2, rates_total); + ArrayResize(m_L3, rates_total); + ArrayResize(m_adaptive_metric, rates_total); + + ArraySetAsSeries(m_price, false); + ArraySetAsSeries(m_L0, false); + ArraySetAsSeries(m_L1, false); + ArraySetAsSeries(m_L2, false); + ArraySetAsSeries(m_L3, false); + ArraySetAsSeries(m_adaptive_metric, false); + } + +//--- Prepare prices and calculate metrics + int start_index = (prev_calculated > 0) ? prev_calculated - 1 : 0; + if(!PreparePriceSeries(rates_total, start_index, price_type, open, high, low, close)) + return; + + if(m_method == METHOD_EFFICIENCY_RATIO) + { + m_er_calc.Calculate(rates_total, prev_calculated, price_type, open, high, low, close, m_adaptive_metric); + } + else + if(m_method == METHOD_ATR) + { + if(ArraySize(m_temp_atr) != rates_total) + { + ArrayResize(m_temp_atr, rates_total); + ArraySetAsSeries(m_temp_atr, false); + } + m_atr_calc.Calculate(rates_total, prev_calculated, open, high, low, close, m_temp_atr); + NormalizeMetric(rates_total, prev_calculated, m_temp_atr); + } + else // METHOD_STAND_DEV + { + if(ArraySize(m_temp_stdev) != rates_total) + { + ArrayResize(m_temp_stdev, rates_total); + ArraySetAsSeries(m_temp_stdev, false); + } + + int start_sync = (prev_calculated > 0) ? prev_calculated - 1 : 0; + int loop_start = MathMax(m_adaptive_period - 1, start_sync); + + if(loop_start == m_adaptive_period - 1) + { + for(int i = 0; i < loop_start; i++) + m_temp_stdev[i] = 0.0; + } + + for(int i = loop_start; i < rates_total; i++) + { + double sum = 0.0; + for(int j = 0; j < m_adaptive_period; j++) + sum += m_price[i - j]; + double mean = sum / m_adaptive_period; + + double sum_sq = 0.0; + for(int j = 0; j < m_adaptive_period; j++) + sum_sq += pow(m_price[i - j] - mean, 2); + + m_temp_stdev[i] = sqrt(sum_sq / m_adaptive_period); + } + NormalizeMetric(rates_total, prev_calculated, m_temp_stdev); + } + +//--- Stateful Adaptive Laguerre States + if(start_index == 0) + { + m_L0[0] = m_price[0]; + m_L1[0] = m_price[0]; + m_L2[0] = m_price[0]; + m_L3[0] = m_price[0]; + lrsi_buffer[0] = 50.0; + start_index = 1; + } + + for(int i = start_index; i < rates_total; i++) + { + double metric = m_adaptive_metric[i]; + metric = fmax(0.0, fmin(1.0, metric)); + + double gamma = m_gamma_max - metric * (m_gamma_max - m_gamma_min); + gamma = fmax(0.0, fmin(1.0, gamma)); + + m_L0[i] = (1.0 - gamma) * m_price[i] + gamma * m_L0[i - 1]; + m_L1[i] = -gamma * m_L0[i] + m_L0[i - 1] + gamma * m_L1[i - 1]; + m_L2[i] = -gamma * m_L1[i] + m_L1[i - 1] + gamma * m_L2[i - 1]; + m_L3[i] = -gamma * m_L2[i] + m_L2[i - 1] + gamma * m_L3[i - 1]; + + // LRSI Difference components + double cu = 0.0, cd = 0.0; + if(m_L0[i] >= m_L1[i]) + cu = m_L0[i] - m_L1[i]; + else + cd = m_L1[i] - m_L0[i]; + if(m_L1[i] >= m_L2[i]) + cu += m_L1[i] - m_L2[i]; + else + cd += m_L2[i] - m_L1[i]; + if(m_L2[i] >= m_L3[i]) + cu += m_L2[i] - m_L3[i]; + else + cd += m_L3[i] - m_L2[i]; + + double lrsi_value; + if(cu + cd > 0.0) + lrsi_value = 100.0 * cu / (cu + cd); + else + lrsi_value = (i > 0) ? lrsi_buffer[i - 1] : 50.0; + + lrsi_buffer[i] = fmax(0.0, fmin(100.0, lrsi_value)); + } + +//--- Calculate Signal Line (No Volume) + m_ma_calc.CalculateOnArray(rates_total, prev_calculated, lrsi_buffer, signal_buffer, m_adaptive_period); + } + +//+------------------------------------------------------------------+ +//| Calculate (Overloaded - With Volume for VWMA) | +//+------------------------------------------------------------------+ +void CLaguerreAdaptiveRSICalculator::Calculate(int rates_total, int prev_calculated, ENUM_APPLIED_PRICE price_type, + const double &open[], const double &high[], const double &low[], const double &close[], + const long &volume[], + double &lrsi_buffer[], double &signal_buffer[]) + { + int required_bars = m_adaptive_period * 2 + 5; + if(rates_total < required_bars) + return; + +//--- Convert volume array locally for VWMA + double d_vol[]; + ArrayResize(d_vol, rates_total); + ArraySetAsSeries(d_vol, false); + int start_sync = (prev_calculated > 0) ? prev_calculated - 1 : 0; + for(int i = start_sync; i < rates_total; i++) + d_vol[i] = (double)volume[i]; + +//--- Run Standard calculation to obtain lrsi_buffer + Calculate(rates_total, prev_calculated, price_type, open, high, low, close, lrsi_buffer, signal_buffer); + +//--- Overwrite Signal Line calculation using Volume + m_ma_calc.CalculateOnArray(rates_total, prev_calculated, lrsi_buffer, d_vol, signal_buffer, m_adaptive_period); + } + +//+------------------------------------------------------------------+ +//| Sliding Min-Max Normalization (DRY Helper) | +//+------------------------------------------------------------------+ +void CLaguerreAdaptiveRSICalculator::NormalizeMetric(int rates_total, int prev_calculated, const double &src_array[]) + { + int start_sync = (prev_calculated > 0) ? prev_calculated - 1 : 0; + int min_lookback = m_adaptive_period; + int loop_start = MathMax(min_lookback * 2, start_sync); + + if(loop_start == min_lookback * 2) + { + for(int i = 0; i < loop_start; i++) + m_adaptive_metric[i] = 0.0; + } + + for(int i = loop_start; i < rates_total; i++) + { + double min_val = src_array[i]; + double max_val = src_array[i]; + for(int j = 1; j < m_adaptive_period; j++) + { + double val = src_array[i - j]; + if(val < min_val) + min_val = val; + if(val > max_val) + max_val = val; + } + double diff = max_val - min_val; + if(diff > 1.0e-9) + m_adaptive_metric[i] = (src_array[i] - min_val) / diff; + else + m_adaptive_metric[i] = 0.0; + } + } + +//+------------------------------------------------------------------+ +//| Prepare Price Series | +//+------------------------------------------------------------------+ +bool CLaguerreAdaptiveRSICalculator::PreparePriceSeries(int rates_total, int start_index, ENUM_APPLIED_PRICE price_type, + const double &open[], const double &high[], const double &low[], const double &close[]) + { + if(m_is_ha) + { + static CHeikinAshi_Calculator ha_calc; + static double ha_open[], ha_high[], ha_low[], ha_close[]; + if(ArraySize(ha_open) != rates_total) + { + ArrayResize(ha_open, rates_total); + ArrayResize(ha_high, rates_total); + ArrayResize(ha_low, rates_total); + ArrayResize(ha_close, rates_total); + ArraySetAsSeries(ha_open, false); + ArraySetAsSeries(ha_high, false); + ArraySetAsSeries(ha_low, false); + ArraySetAsSeries(ha_close, false); + } + + ha_calc.Calculate(rates_total, start_index, open, high, low, close, ha_open, ha_high, ha_low, ha_close); + + for(int i = start_index; i < rates_total; i++) + { + switch(price_type) + { + case PRICE_OPEN: + m_price[i] = ha_open[i]; + break; + case PRICE_HIGH: + m_price[i] = ha_high[i]; + break; + case PRICE_LOW: + m_price[i] = ha_low[i]; + break; + case PRICE_MEDIAN: + m_price[i] = (ha_high[i] + ha_low[i]) * 0.5; + break; + case PRICE_TYPICAL: + m_price[i] = (ha_high[i] + ha_low[i] + ha_close[i]) / 3.0; + break; + case PRICE_WEIGHTED: + m_price[i] = (ha_high[i] + ha_low[i] + ha_close[i] * 2.0) * 0.25; + break; + default: + m_price[i] = ha_close[i]; + break; + } + } + } + else + { + for(int i = start_index; i < rates_total; i++) + { + switch(price_type) + { + case PRICE_OPEN: + m_price[i] = open[i]; + break; + case PRICE_HIGH: + m_price[i] = high[i]; + break; + case PRICE_LOW: + m_price[i] = low[i]; + break; + case PRICE_MEDIAN: + m_price[i] = (high[i] + low[i]) * 0.5; + break; + case PRICE_TYPICAL: + m_price[i] = (high[i] + low[i] + close[i]) / 3.0; + break; + case PRICE_WEIGHTED: + m_price[i] = (high[i] + low[i] + close[i] * 2.0) * 0.25; + break; + default: + m_price[i] = close[i]; + break; + } + } + } + return true; + } + +//+==================================================================+ +//| CLASS 2: CLaguerreAdaptiveRSICalculator_HA | +//+==================================================================+ +class CLaguerreAdaptiveRSICalculator_HA : public CLaguerreAdaptiveRSICalculator + { +public: + CLaguerreAdaptiveRSICalculator_HA(void) + { + m_is_ha = true; + }; + }; + +#endif // LAGUERRE_ADAPTIVE_RSI_CALCULATOR_MQH +//+------------------------------------------------------------------+