diff --git a/Include/MyIncludes/RSI_Engine.mqh b/Include/MyIncludes/RSI_Engine.mqh new file mode 100644 index 0000000..f55942f --- /dev/null +++ b/Include/MyIncludes/RSI_Engine.mqh @@ -0,0 +1,215 @@ +//+------------------------------------------------------------------+ +//| RSI_Engine.mqh | +//| Core engine for Wilder's RSI calculation. | +//| VERSION 1.00 | +//| Copyright 2025, xxxxxxxx | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2025, xxxxxxxx" + +#include + +//+==================================================================+ +//| CLASS 1: CRSIEngine (Base Class) | +//+==================================================================+ +class CRSIEngine + { +protected: + int m_period; + + //--- Persistent Buffers + double m_price[]; + double m_avg_gain[]; + double m_avg_loss[]; + + //--- Virtual Prepare (Standard vs HA) + virtual void PrepareData(int rates_total, int start_index, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]); + +public: + CRSIEngine(void) {}; + virtual ~CRSIEngine(void) {}; + + bool Init(int period); + int GetPeriod(void) const { return m_period; } + + //--- Main Calculation + 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 &rsi_buffer[]); + }; + +//+------------------------------------------------------------------+ +//| Init | +//+------------------------------------------------------------------+ +bool CRSIEngine::Init(int period) + { + m_period = (period < 1) ? 1 : period; + return true; + } + +//+------------------------------------------------------------------+ +//| Main Calculation | +//+------------------------------------------------------------------+ +void CRSIEngine::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 &rsi_buffer[]) + { + if(rates_total <= m_period) + return; + + int start_index = (prev_calculated > 0) ? prev_calculated - 1 : 0; + +// Resize Buffers + if(ArraySize(m_price) != rates_total) + { + ArrayResize(m_price, rates_total); + ArrayResize(m_avg_gain, rates_total); + ArrayResize(m_avg_loss, rates_total); + } + +// 1. Prepare Data + PrepareData(rates_total, start_index, price_type, open, high, low, close); + +// 2. Calculate RSI + int i = start_index; + if(i == 0) + { + m_avg_gain[0] = 0; + m_avg_loss[0] = 0; + rsi_buffer[0] = 0; + i = 1; + } + + for(; i < rates_total; i++) + { + double diff = m_price[i] - m_price[i-1]; + double pos = (diff > 0 ? diff : 0); + double neg = (diff < 0 ? -diff : 0); + + if(i <= m_period) + { + if(i < m_period) + { + m_avg_gain[i] = m_avg_gain[i-1] + pos; + m_avg_loss[i] = m_avg_loss[i-1] + neg; + rsi_buffer[i] = 0; + } + else // i == m_period (Initial SMA) + { + m_avg_gain[i] = (m_avg_gain[i-1] + pos) / m_period; + m_avg_loss[i] = (m_avg_loss[i-1] + neg) / m_period; + + if(m_avg_loss[i] > 0) + rsi_buffer[i] = 100.0 - (100.0 / (1.0 + (m_avg_gain[i] / m_avg_loss[i]))); + else + rsi_buffer[i] = 100.0; + } + } + else // Wilder's Smoothing (RMA) + { + m_avg_gain[i] = (m_avg_gain[i-1] * (m_period - 1) + pos) / m_period; + m_avg_loss[i] = (m_avg_loss[i-1] * (m_period - 1) + neg) / m_period; + + if(m_avg_loss[i] > 0) + rsi_buffer[i] = 100.0 - (100.0 / (1.0 + (m_avg_gain[i] / m_avg_loss[i]))); + else + rsi_buffer[i] = 100.0; + } + } + } + +//+------------------------------------------------------------------+ +//| Prepare Data (Standard) | +//+------------------------------------------------------------------+ +void CRSIEngine::PrepareData(int rates_total, int start_index, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]) + { + for(int i = start_index; i < rates_total; i++) + { + switch(price_type) + { + case PRICE_CLOSE: + m_price[i] = close[i]; + break; + 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])/2.0; + 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]+2*close[i])/4.0; + break; + default: + m_price[i] = close[i]; + break; + } + } + } + +//+==================================================================+ +//| CLASS 2: CRSIEngine_HA (Heikin Ashi) | +//+==================================================================+ +class CRSIEngine_HA : public CRSIEngine + { +private: + CHeikinAshi_Calculator m_ha_calculator; + double m_ha_open[], m_ha_high[], m_ha_low[], m_ha_close[]; + +protected: + virtual void PrepareData(int rates_total, int start_index, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]) override; + }; + +//+------------------------------------------------------------------+ +//| Prepare Data (Heikin Ashi) | +//+------------------------------------------------------------------+ +void CRSIEngine_HA::PrepareData(int rates_total, int start_index, ENUM_APPLIED_PRICE price_type, const double &open[], const double &high[], const double &low[], const double &close[]) + { + if(ArraySize(m_ha_open) != rates_total) + { + ArrayResize(m_ha_open, rates_total); + ArrayResize(m_ha_high, rates_total); + ArrayResize(m_ha_low, rates_total); + ArrayResize(m_ha_close, rates_total); + } + + m_ha_calculator.Calculate(rates_total, start_index, open, high, low, close, m_ha_open, m_ha_high, m_ha_low, m_ha_close); + + for(int i = start_index; i < rates_total; i++) + { + switch(price_type) + { + case PRICE_CLOSE: + m_price[i] = m_ha_close[i]; + break; + case PRICE_OPEN: + m_price[i] = m_ha_open[i]; + break; + case PRICE_HIGH: + m_price[i] = m_ha_high[i]; + break; + case PRICE_LOW: + m_price[i] = m_ha_low[i]; + break; + case PRICE_MEDIAN: + m_price[i] = (m_ha_high[i]+m_ha_low[i])/2.0; + break; + case PRICE_TYPICAL: + m_price[i] = (m_ha_high[i]+m_ha_low[i]+m_ha_close[i])/3.0; + break; + case PRICE_WEIGHTED: + m_price[i] = (m_ha_high[i]+m_ha_low[i]+2*m_ha_close[i])/4.0; + break; + default: + m_price[i] = m_ha_close[i]; + break; + } + } + } +//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+