diff --git a/Include/MyIncludes/CutlerRSI_Calculator.mqh b/Include/MyIncludes/CutlerRSI_Calculator.mqh new file mode 100644 index 0000000..c84521b --- /dev/null +++ b/Include/MyIncludes/CutlerRSI_Calculator.mqh @@ -0,0 +1,223 @@ +//+------------------------------------------------------------------+ +//| CutlerRSI_Calculator.mqh| +//| Calculation engine for Standard and Heikin Ashi Cutler's RSI. | +//| Copyright 2025, xxxxxxxx | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2025, xxxxxxxx" + +#include + +//+==================================================================+ +//| | +//| CLASS 1: CCutlerRSICalculator (Base Class) | +//| | +//+==================================================================+ +class CCutlerRSICalculator + { +protected: + int m_rsi_period; + int m_ma_period; + ENUM_MA_METHOD m_ma_method; + + //--- Internal buffer for the selected source price + double m_price[]; + + //--- Virtual method for preparing the price series. + virtual bool PreparePriceSeries(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], ENUM_APPLIED_PRICE price_type); + +public: + CCutlerRSICalculator(void) {}; + virtual ~CCutlerRSICalculator(void) {}; + + //--- Public methods + bool Init(int rsi_p, int ma_p, ENUM_MA_METHOD ma_m); + void Calculate(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], ENUM_APPLIED_PRICE price_type, double &rsi_buffer[], double &signal_buffer[]); + }; + +//+------------------------------------------------------------------+ +//| CCutlerRSICalculator: Initialization | +//+------------------------------------------------------------------+ +bool CCutlerRSICalculator::Init(int rsi_p, int ma_p, ENUM_MA_METHOD ma_m) + { + m_rsi_period = (rsi_p < 1) ? 1 : rsi_p; + m_ma_period = (ma_p < 1) ? 1 : ma_p; + m_ma_method = ma_m; + return true; + } + +//+------------------------------------------------------------------+ +//| CCutlerRSICalculator: Main Calculation Method (Shared Logic) | +//+------------------------------------------------------------------+ +void CCutlerRSICalculator::Calculate(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], ENUM_APPLIED_PRICE price_type, double &rsi_buffer[], double &signal_buffer[]) + { + if(rates_total <= m_rsi_period) + return; + +//--- STEP 1: Prepare the source price array (delegated to virtual method) + if(!PreparePriceSeries(rates_total, open, high, low, close, price_type)) + return; + +//--- STEP 2: Calculate Cutler's RSI (SMA-based) using a sliding window sum + double sum_pos = 0, sum_neg = 0; + for(int i = 1; i < rates_total; i++) + { + double diff = m_price[i] - m_price[i-1]; + double pos_change = (diff > 0) ? diff : 0; + double neg_change = (diff < 0) ? -diff : 0; + + sum_pos += pos_change; + sum_neg += neg_change; + + if(i > m_rsi_period) + { + double old_diff = m_price[i - m_rsi_period] - m_price[i - m_rsi_period - 1]; + sum_pos -= (old_diff > 0) ? old_diff : 0; + sum_neg -= (old_diff < 0) ? -old_diff : 0; + } + + if(i >= m_rsi_period) + { + if(sum_pos + sum_neg > 0) + { + // The division by period cancels out, so we can use sums directly + double rs = sum_pos / sum_neg; + rsi_buffer[i] = 100.0 - (100.0 / (1.0 + rs)); + } + else + { + rsi_buffer[i] = 100.0; + } + } + } + +//--- STEP 3: Calculate the Signal Line (MA of Cutler's RSI) + int ma_start_pos = m_rsi_period + m_ma_period - 1; + for(int i = ma_start_pos; i < rates_total; i++) + { + switch(m_ma_method) + { + case MODE_EMA: + case MODE_SMMA: + if(i == ma_start_pos) + { + double sum=0; + for(int j=0; j0) signal_buffer[i]=lwma_sum/weight_sum;} + break; + default: + {double sum=0; for(int j=0; j