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