diff --git a/Indicators/MyIndicators/RSI_HeikenAshi.mq5 b/Indicators/MyIndicators/RSI_HeikenAshi.mq5 index 857dbca..c1ccd16 100644 --- a/Indicators/MyIndicators/RSI_HeikenAshi.mq5 +++ b/Indicators/MyIndicators/RSI_HeikenAshi.mq5 @@ -1,14 +1,19 @@ //+------------------------------------------------------------------+ //| RSI_HeikenAshi.mq5 | -//| Copyright 2024, Your Name (Based on MetaQuotes RSI) | +//| Copyright 2025, xxxxxxxx (Based on MetaQuotes RSI) | //| | //+------------------------------------------------------------------+ -#property copyright "Copyright 2024, Your Name" +#property copyright "Copyright 2025, xxxxxxxx" #property link "" -#property version "1.00" -#property description "RSI calculated on Heiken Ashi Close prices, with a Moving Average." +#property version "2.00" // Refactored to use HA_Tools.mqh +#property description "RSI on Heiken Ashi prices, with a Moving Average." -//--- Indicator settings +// --- Standard Includes --- +#include +// --- Custom Toolkit Includes --- +#include + +//--- Indicator Window and Level Properties --- #property indicator_separate_window #property indicator_minimum 0 #property indicator_maximum 100 @@ -16,9 +21,9 @@ #property indicator_level2 50.0 #property indicator_level3 70.0 -//--- Buffers and Plots -#property indicator_buffers 5 // HA_RSI_MA, HA_RSI, Pos, Neg, HA_Close (all calculations) -#property indicator_plots 2 // We only plot HA_RSI_MA and HA_RSI +//--- Buffers and Plots --- +#property indicator_buffers 4 // HA_RSI_MA, HA_RSI, Pos, Neg +#property indicator_plots 2 //--- Plot 1: RSI MA line (smoothed) #property indicator_label1 "HA_RSIMA" @@ -34,62 +39,54 @@ #property indicator_style2 STYLE_SOLID #property indicator_width2 1 -//--- Input parameters +//--- Input Parameters --- input int InpPeriodRSI = 14; // RSI Period input int InpPeriodMA = 14; // MA Period input ENUM_MA_METHOD InpMethodMA = MODE_SMA; // MA Method -//--- Indicator Buffers +//--- Indicator Buffers --- // Plotted buffers double BufferHARSI_MA[]; // Smoothed Heiken Ashi RSI double BufferHARSI[]; // Raw Heiken Ashi RSI // Calculation buffers double BufferPos[]; // For RSI calculation (average gain) double BufferNeg[]; // For RSI calculation (average loss) -double BufferHAClose[]; // To store Heiken Ashi Close prices -//--- Global variables -int ExtPeriodRSI; -int ExtPeriodMA; - -//--- Include for MA calculations -#include +//--- Global Objects and Variables --- +int ExtPeriodRSI; +int ExtPeriodMA; +CHA_Calculator g_ha_calculator; // Global instance of our Heiken Ashi calculator //+------------------------------------------------------------------+ -//| Custom indicator initialization function | +//| Custom indicator initialization function. | +//| Called once when the indicator is first loaded. | //+------------------------------------------------------------------+ int OnInit() { -//--- Validate inputs +//--- Validate and store input periods ExtPeriodRSI = (InpPeriodRSI < 1) ? 1 : InpPeriodRSI; ExtPeriodMA = (InpPeriodMA < 1) ? 1 : InpPeriodMA; -//--- Indicator buffers mapping +//--- Map the buffers to the indicator's internal memory SetIndexBuffer(0, BufferHARSI_MA, INDICATOR_DATA); SetIndexBuffer(1, BufferHARSI, INDICATOR_DATA); SetIndexBuffer(2, BufferPos, INDICATOR_CALCULATIONS); SetIndexBuffer(3, BufferNeg, INDICATOR_CALCULATIONS); - SetIndexBuffer(4, BufferHAClose, INDICATOR_CALCULATIONS); -//--- Set accuracy +//--- Set indicator properties IndicatorSetInteger(INDICATOR_DIGITS, 2); - -//--- Set drawing start positions - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, ExtPeriodRSI + ExtPeriodMA); + PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, ExtPeriodRSI + ExtPeriodMA - 1); PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, ExtPeriodRSI); - -//--- Set labels for DataWindow PlotIndexSetString(0, PLOT_LABEL, "HA_RSIMA"); PlotIndexSetString(1, PLOT_LABEL, "HA_RSI"); - -//--- Set indicator short name IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA_RSI(%d, %d)", ExtPeriodRSI, ExtPeriodMA)); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ -//| Custom indicator calculation function | +//| Custom indicator calculation function. | +//| Called on every new tick or new bar. | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, @@ -102,48 +99,28 @@ int OnCalculate(const int rates_total, const long &volume[], const int &spread[]) { -//--- Check if there is enough data +//--- Check if there is enough historical data if(rates_total < ExtPeriodRSI) return(0); -//====== STEP 1: CALCULATE HEIKEN ASHI BARS ====== - double ha_open, ha_close; - -// Calculate the very first HA bar - ha_open = (open[0] + close[0]) / 2.0; - ha_close = (open[0] + high[0] + low[0] + close[0]) / 4.0; - BufferHAClose[0] = ha_close; - -// Loop to calculate all HA bars - for(int i = 1; i < rates_total; i++) +//--- STEP 1: Calculate Heiken Ashi bars using our toolkit + if(!g_ha_calculator.Calculate(rates_total, prev_calculated, open, high, low, close)) { - // Previous HA values are needed - double prev_ha_open = ha_open; - double prev_ha_close = ha_close; - - // Calculate current HA values - ha_close = (open[i] + high[i] + low[i] + close[i]) / 4.0; - ha_open = (prev_ha_open + prev_ha_close) / 2.0; - - // We only need the HA Close for RSI, so we store it in our buffer - BufferHAClose[i] = ha_close; + Print("Heiken Ashi calculation failed."); + return(0); } -//====== STEP 2: CALCULATE RSI BASED ON HEIKEN ASHI CLOSE PRICES ====== -// This part is adapted from the standard RSI indicator code - +//--- STEP 2: Calculate RSI based on the Heiken Ashi Close prices int start_pos; if(prev_calculated > 0) start_pos = prev_calculated - 1; else start_pos = 0; -// --- First-time calculation setup --- +//--- First-time calculation setup if(start_pos == 0) { - double sum_pos = 0.0; - double sum_neg = 0.0; - + double sum_pos = 0.0, sum_neg = 0.0; // Initialize first period values to zero for(int i = 0; i < ExtPeriodRSI; i++) { @@ -151,32 +128,30 @@ int OnCalculate(const int rates_total, BufferPos[i] = 0.0; BufferNeg[i] = 0.0; } - // Calculate initial sums for the first visible RSI value for(int i = 1; i <= ExtPeriodRSI; i++) { - double diff = BufferHAClose[i] - BufferHAClose[i-1]; + // Use the HA Close from our calculator object + double diff = g_ha_calculator.ha_close[i] - g_ha_calculator.ha_close[i-1]; sum_pos += (diff > 0 ? diff : 0); sum_neg += (diff < 0 ? -diff : 0); } - // Calculate first visible value BufferPos[ExtPeriodRSI] = sum_pos / ExtPeriodRSI; BufferNeg[ExtPeriodRSI] = sum_neg / ExtPeriodRSI; - if(BufferNeg[ExtPeriodRSI] != 0.0) BufferHARSI[ExtPeriodRSI] = 100.0 - (100.0 / (1.0 + BufferPos[ExtPeriodRSI] / BufferNeg[ExtPeriodRSI])); else BufferHARSI[ExtPeriodRSI] = (BufferPos[ExtPeriodRSI] != 0.0) ? 100.0 : 50.0; - // Set the starting position for the main loop start_pos = ExtPeriodRSI + 1; } -// --- Main RSI calculation loop --- +//--- Main RSI calculation loop for(int i = start_pos; i < rates_total; i++) { - double diff = BufferHAClose[i] - BufferHAClose[i-1]; + // Use the HA Close from our calculator object + double diff = g_ha_calculator.ha_close[i] - g_ha_calculator.ha_close[i-1]; BufferPos[i] = (BufferPos[i-1] * (ExtPeriodRSI - 1) + (diff > 0.0 ? diff : 0.0)) / ExtPeriodRSI; BufferNeg[i] = (BufferNeg[i-1] * (ExtPeriodRSI - 1) + (diff < 0.0 ? -diff : 0.0)) / ExtPeriodRSI; @@ -186,11 +161,9 @@ int OnCalculate(const int rates_total, BufferHARSI[i] = (BufferPos[i] != 0.0) ? 100.0 : 50.0; } -//====== STEP 3: CALCULATE MOVING AVERAGE ON THE HEIKEN ASHI RSI BUFFER ====== -// We use the robust manual loop from our final RSIMA indicator - +//--- STEP 3: Calculate Moving Average on the Heiken Ashi RSI buffer if(rates_total < ExtPeriodRSI + ExtPeriodMA) - return(rates_total); // Not enough data for MA yet + return(rates_total); // Determine starting bar for MA calculation if(prev_calculated > 0) @@ -198,6 +171,9 @@ int OnCalculate(const int rates_total, else start_pos = ExtPeriodRSI + ExtPeriodMA - 2; +// The MA functions need non-timeseries arrays + ArraySetAsSeries(BufferHARSI, false); + // Loop through bars that need MA calculation for(int i = start_pos; i < rates_total; i++) { @@ -206,7 +182,6 @@ int OnCalculate(const int rates_total, BufferHARSI_MA[i] = EMPTY_VALUE; continue; } - switch(InpMethodMA) { case MODE_EMA: @@ -223,6 +198,8 @@ int OnCalculate(const int rates_total, break; } } +// Restore timeseries property for the next call + ArraySetAsSeries(BufferHARSI, true); return(rates_total); }