diff --git a/Indicators/MyIndicators/ADX.mq5 b/Indicators/MyIndicators/ADX.mq5 new file mode 100644 index 0000000..16a1cf0 --- /dev/null +++ b/Indicators/MyIndicators/ADX.mq5 @@ -0,0 +1,179 @@ +//+------------------------------------------------------------------+ +//| ADX.mq5 | +//| Copyright 2025, xxxxxxxx (Based on MetaQuotes ADXW) | +//| | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2025, xxxxxxxx" +#property link "" +#property version "1.00" +#property description "ADX by Welles Wilder on standard price data." + +//--- Indicator Window and Level Properties --- +#property indicator_separate_window +#property indicator_buffers 7 // 3 for plotting, 4 for calculations +#property indicator_plots 3 + +//--- Plot 1: ADX line (Main trend strength) +#property indicator_label1 "ADX" +#property indicator_type1 DRAW_LINE +#property indicator_color1 clrLightSeaGreen +#property indicator_style1 STYLE_SOLID +#property indicator_width1 1 + +//--- Plot 2: +DI line (Positive Directional Indicator) +#property indicator_label2 "+DI" +#property indicator_type2 DRAW_LINE +#property indicator_color2 clrLimeGreen +#property indicator_style2 STYLE_DOT +#property indicator_width2 1 + +//--- Plot 3: -DI line (Negative Directional Indicator) +#property indicator_label3 "-DI" +#property indicator_type3 DRAW_LINE +#property indicator_color3 clrTomato +#property indicator_style3 STYLE_DOT +#property indicator_width3 1 + +//--- Input Parameters --- +input int InpPeriodADX = 14; // Period for ADX calculations + +//--- Indicator Buffers --- +double BufferADX[]; +double BufferPDI[]; +double BufferNDI[]; +double BufferSmoothed_PDM[]; +double BufferSmoothed_NDM[]; +double BufferSmoothed_TR[]; +double BufferDX[]; + +//--- Global Objects and Variables --- +int g_ExtADXPeriod; + +//+------------------------------------------------------------------+ +//| Custom indicator initialization function. | +//+------------------------------------------------------------------+ +int OnInit() + { + g_ExtADXPeriod = (InpPeriodADX < 1) ? 1 : InpPeriodADX; + + SetIndexBuffer(0, BufferADX, INDICATOR_DATA); + SetIndexBuffer(1, BufferPDI, INDICATOR_DATA); + SetIndexBuffer(2, BufferNDI, INDICATOR_DATA); + SetIndexBuffer(3, BufferSmoothed_PDM, INDICATOR_CALCULATIONS); + SetIndexBuffer(4, BufferSmoothed_NDM, INDICATOR_CALCULATIONS); + SetIndexBuffer(5, BufferSmoothed_TR, INDICATOR_CALCULATIONS); + SetIndexBuffer(6, BufferDX, INDICATOR_CALCULATIONS); + + ArraySetAsSeries(BufferADX, false); + ArraySetAsSeries(BufferPDI, false); + ArraySetAsSeries(BufferNDI, false); + ArraySetAsSeries(BufferSmoothed_PDM, false); + ArraySetAsSeries(BufferSmoothed_NDM, false); + ArraySetAsSeries(BufferSmoothed_TR, false); + ArraySetAsSeries(BufferDX, false); + + IndicatorSetInteger(INDICATOR_DIGITS, 2); + PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, g_ExtADXPeriod * 2 - 1); + PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, g_ExtADXPeriod); + PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, g_ExtADXPeriod); + IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("ADXW(%d)", g_ExtADXPeriod)); + + return(INIT_SUCCEEDED); + } + +//+------------------------------------------------------------------+ +//| Custom indicator calculation function. | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { + if(rates_total < g_ExtADXPeriod * 2) + return(0); + +//--- STEP 1: Calculate raw +DM, -DM, and TR from standard prices + double pDM[], nDM[], TR[]; + ArrayResize(pDM, rates_total); + ArrayResize(nDM, rates_total); + ArrayResize(TR, rates_total); + + for(int i = 1; i < rates_total; i++) + { + pDM[i] = high[i] - high[i-1]; + nDM[i] = low[i-1] - low[i]; + + if(pDM[i] < 0 || pDM[i] < nDM[i]) + pDM[i] = 0; + if(nDM[i] < 0 || nDM[i] < pDM[i]) + nDM[i] = 0; + + TR[i] = MathMax(high[i], close[i-1]) - MathMin(low[i], close[i-1]); + } + +//--- STEP 2: Calculate Smoothed PDM, NDM, and TR + for(int i = g_ExtADXPeriod; i < rates_total; i++) + { + if(i == g_ExtADXPeriod) // First calculation is a simple sum + { + double sum_pdm=0, sum_ndm=0, sum_tr=0; + for(int j=1; j<=g_ExtADXPeriod; j++) + { + sum_pdm += pDM[j]; + sum_ndm += nDM[j]; + sum_tr += TR[j]; + } + BufferSmoothed_PDM[i] = sum_pdm; + BufferSmoothed_NDM[i] = sum_ndm; + BufferSmoothed_TR[i] = sum_tr; + } + else // Subsequent calculations use Wilder's smoothing + { + BufferSmoothed_PDM[i] = BufferSmoothed_PDM[i-1] - (BufferSmoothed_PDM[i-1] / g_ExtADXPeriod) + pDM[i]; + BufferSmoothed_NDM[i] = BufferSmoothed_NDM[i-1] - (BufferSmoothed_NDM[i-1] / g_ExtADXPeriod) + nDM[i]; + BufferSmoothed_TR[i] = BufferSmoothed_TR[i-1] - (BufferSmoothed_TR[i-1] / g_ExtADXPeriod) + TR[i]; + } + } + +//--- STEP 3: Calculate +DI, -DI, and DX + for(int i = g_ExtADXPeriod; i < rates_total; i++) + { + if(BufferSmoothed_TR[i] != 0.0) + { + BufferPDI[i] = (BufferSmoothed_PDM[i] / BufferSmoothed_TR[i]) * 100.0; + BufferNDI[i] = (BufferSmoothed_NDM[i] / BufferSmoothed_TR[i]) * 100.0; + } + + double di_sum = BufferPDI[i] + BufferNDI[i]; + if(di_sum != 0.0) + BufferDX[i] = MathAbs(BufferPDI[i] - BufferNDI[i]) / di_sum * 100.0; + else + BufferDX[i] = 0.0; + } + +//--- STEP 4: Smooth DX to get the final ADX value + for(int i = g_ExtADXPeriod * 2 - 1; i < rates_total; i++) + { + if(i == g_ExtADXPeriod * 2 - 1) // First ADX value is a simple average + { + double sum_dx = 0; + for(int j=i-g_ExtADXPeriod+1; j<=i; j++) + sum_dx += BufferDX[j]; + BufferADX[i] = sum_dx / g_ExtADXPeriod; + } + else // Subsequent ADX values are smoothed + { + BufferADX[i] = (BufferADX[i-1] * (g_ExtADXPeriod - 1) + BufferDX[i]) / g_ExtADXPeriod; + } + } + + return(rates_total); + } +//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/ADXW_HeikenAshi.mq5 b/Indicators/MyIndicators/ADXW_HeikenAshi.mq5 new file mode 100644 index 0000000..84c7282 Binary files /dev/null and b/Indicators/MyIndicators/ADXW_HeikenAshi.mq5 differ diff --git a/Indicators/MyIndicators/ALMA_HeikenAshi.mq5 b/Indicators/MyIndicators/ALMA_HeikenAshi.mq5 new file mode 100644 index 0000000..88a1a27 Binary files /dev/null and b/Indicators/MyIndicators/ALMA_HeikenAshi.mq5 differ diff --git a/Indicators/MyIndicators/Chart_HeikenAshi.mq5 b/Indicators/MyIndicators/Chart_HeikenAshi.mq5 new file mode 100644 index 0000000..d0e93f8 --- /dev/null +++ b/Indicators/MyIndicators/Chart_HeikenAshi.mq5 @@ -0,0 +1,103 @@ +//+------------------------------------------------------------------+ +//| Chart_HeikenAshi.mq5 | +//| Copyright 2025, xxxxxxxx | +//| | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2025, xxxxxxxx" +#property link "" +#property version "2.00" // Refactored to use HA_Tools.mqh +#property description "Draws Heiken Ashi candles on the main chart." + +//--- Custom Toolkit Include --- +#include + +//--- Indicator Window and Plot Properties --- +#property indicator_chart_window // Draw on the main chart window +#property indicator_buffers 5 // 4 for OHLC, 1 for color +#property indicator_plots 1 + +//--- Plot 1: Heiken Ashi Candles +#property indicator_type1 DRAW_COLOR_CANDLES +#property indicator_color1 clrDodgerBlue, clrMaroon // Up and Down colors +#property indicator_label1 "HA Open;HA High;HA Low;HA Close" // Labels for Data Window + +//--- Indicator Buffers --- +double BufferHA_Open[]; +double BufferHA_High[]; +double BufferHA_Low[]; +double BufferHA_Close[]; +double BufferColor[]; // Buffer for candle colors + +//--- Global Objects --- +CHA_Calculator g_ha_calculator; // Global instance of our Heiken Ashi calculator + +//+------------------------------------------------------------------+ +//| Custom indicator initialization function. | +//| Called once when the indicator is first loaded. | +//+------------------------------------------------------------------+ +void OnInit() + { +//--- Map the buffers to the indicator's internal memory + SetIndexBuffer(0, BufferHA_Open, INDICATOR_DATA); + SetIndexBuffer(1, BufferHA_High, INDICATOR_DATA); + SetIndexBuffer(2, BufferHA_Low, INDICATOR_DATA); + SetIndexBuffer(3, BufferHA_Close, INDICATOR_DATA); + SetIndexBuffer(4, BufferColor, INDICATOR_COLOR_INDEX); + +//--- Set indicator properties + IndicatorSetInteger(INDICATOR_DIGITS, _Digits); // Use the same precision as the symbol + IndicatorSetString(INDICATOR_SHORTNAME, "Heiken Ashi"); + PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, 0.0); // Define the empty value for the plot + } + +//+------------------------------------------------------------------+ +//| Heiken Ashi calculation function. | +//| Called on every new tick or new bar. | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { +//--- Check if there is enough historical data + if(rates_total < 2) + return(0); + +//--- STEP 1: Calculate Heiken Ashi bars using our toolkit +// We use a full recalculation (prev_calculated=0) for maximum stability + if(!g_ha_calculator.Calculate(rates_total, 0, open, high, low, close)) + { + Print("Heiken Ashi calculation failed in OnCalculate."); + return(0); + } + +//--- STEP 2: Copy data from the calculator and set colors +// The main loop iterates through all bars to ensure data consistency + for(int i = 0; i < rates_total; i++) + { + // Copy the calculated HA values from our toolkit to the indicator's buffers + BufferHA_Open[i] = g_ha_calculator.ha_open[i]; + BufferHA_High[i] = g_ha_calculator.ha_high[i]; + BufferHA_Low[i] = g_ha_calculator.ha_low[i]; + BufferHA_Close[i] = g_ha_calculator.ha_close[i]; + + //--- Set the color for the current candle + // Color index 0 (clrDodgerBlue) for bullish candles + // Color index 1 (clrMaroon) for bearish candles + if(BufferHA_Open[i] < BufferHA_Close[i]) + BufferColor[i] = 0.0; // Bullish + else + BufferColor[i] = 1.0; // Bearish + } + +//--- Return value of prev_calculated for the next call + return(rates_total); + } +//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/CutlerRSI_MA_HeikenAshi.mq5 b/Indicators/MyIndicators/CutlerRSI_MA_HeikenAshi.mq5 new file mode 100644 index 0000000..756ce2d --- /dev/null +++ b/Indicators/MyIndicators/CutlerRSI_MA_HeikenAshi.mq5 @@ -0,0 +1,177 @@ +//+------------------------------------------------------------------+ +//| CutlerRSI_MA_HeikenAshi.mq5 | +//| Copyright 2025, xxxxxxxx | +//| | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2025, xxxxxxxx" +#property link "" +#property version "1.00" +#property description "Cutler's RSI (SMA-based) on Heiken Ashi data, with a signal line." + +#include +#include + +//--- Indicator Window and Level Properties --- +#property indicator_separate_window +#property indicator_minimum 0 +#property indicator_maximum 100 +#property indicator_level1 30.0 +#property indicator_level2 50.0 +#property indicator_level3 70.0 + +//--- Buffers and Plots --- +#property indicator_buffers 4 // CutlerRSI_MA, CutlerRSI, Pos, Neg +#property indicator_plots 2 + +//--- Plot 1: MA line (smoothed) +#property indicator_label1 "MA" +#property indicator_type1 DRAW_LINE +#property indicator_color1 clrRed +#property indicator_style1 STYLE_DOT +#property indicator_width1 1 + +//--- Plot 2: Cutler's RSI line (raw) +#property indicator_label2 "HA_CutlerRSI" +#property indicator_type2 DRAW_LINE +#property indicator_color2 clrDodgerBlue +#property indicator_style2 STYLE_SOLID +#property indicator_width2 1 + +//--- Input Parameters --- +input int InpPeriodRSI = 14; // RSI Period +input group "Signal Line Settings" +input int InpPeriodMA = 14; // MA Period +input ENUM_MA_METHOD InpMethodMA = MODE_SMA; // MA Method + +//--- Indicator Buffers --- +double BufferCutlerRSI_MA[]; +double BufferCutlerRSI[]; +double BufferAvgPos[]; +double BufferAvgNeg[]; + +//--- Global Objects and Variables --- +int ExtPeriodRSI; +int ExtPeriodMA; +CHA_Calculator g_ha_calculator; + +//+------------------------------------------------------------------+ +//| Custom indicator initialization function. | +//+------------------------------------------------------------------+ +void OnInit() + { + ExtPeriodRSI = (InpPeriodRSI < 1) ? 1 : InpPeriodRSI; + ExtPeriodMA = (InpPeriodMA < 1) ? 1 : InpPeriodMA; + + SetIndexBuffer(0, BufferCutlerRSI_MA, INDICATOR_DATA); + SetIndexBuffer(1, BufferCutlerRSI, INDICATOR_DATA); + SetIndexBuffer(2, BufferAvgPos, INDICATOR_CALCULATIONS); + SetIndexBuffer(3, BufferAvgNeg, INDICATOR_CALCULATIONS); + + ArraySetAsSeries(BufferCutlerRSI_MA, false); + ArraySetAsSeries(BufferCutlerRSI, false); + ArraySetAsSeries(BufferAvgPos, false); + ArraySetAsSeries(BufferAvgNeg, false); + + IndicatorSetInteger(INDICATOR_DIGITS, 2); + PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, ExtPeriodRSI + ExtPeriodMA - 2); + PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, ExtPeriodRSI); + IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA_CutlerRSI(%d,%d)", ExtPeriodRSI, ExtPeriodMA)); + } + +//+------------------------------------------------------------------+ +//| Cutler's RSI on Heiken Ashi calculation function. | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { + if(rates_total < ExtPeriodRSI) + return(0); + +//--- STEP 1: Calculate Heiken Ashi bars + if(!g_ha_calculator.Calculate(rates_total, 0, open, high, low, close)) + return(0); + +//--- Create temporary buffers for raw changes + double pos_changes[], neg_changes[]; + ArrayResize(pos_changes, rates_total); + ArrayResize(neg_changes, rates_total); + +//--- STEP 2: Calculate and separate price changes based on HA Close + for(int i = 1; i < rates_total; i++) + { + double diff = g_ha_calculator.ha_close[i] - g_ha_calculator.ha_close[i-1]; + pos_changes[i] = (diff > 0) ? diff : 0; + neg_changes[i] = (diff < 0) ? -diff : 0; + } + +//--- STEP 3: Smooth changes with SMA + for(int i = ExtPeriodRSI; i < rates_total; i++) + { + BufferAvgPos[i] = SimpleMA(i, ExtPeriodRSI, pos_changes); + BufferAvgNeg[i] = SimpleMA(i, ExtPeriodRSI, neg_changes); + } + +//--- STEP 4: Calculate final Cutler's RSI value + for(int i = ExtPeriodRSI; i < rates_total; i++) + { + if(BufferAvgNeg[i] > 0) + { + double rs = BufferAvgPos[i] / BufferAvgNeg[i]; + BufferCutlerRSI[i] = 100.0 - (100.0 / (1.0 + rs)); + } + else + { + BufferCutlerRSI[i] = 100.0; + } + } + +//--- STEP 5: Calculate the signal line (MA of Cutler's RSI) + if(rates_total < ExtPeriodRSI + ExtPeriodMA) + return(rates_total); + + for(int i = 1; i < rates_total; i++) + { + if(i < ExtPeriodRSI + ExtPeriodMA - 2) + { + BufferCutlerRSI_MA[i] = EMPTY_VALUE; + continue; + } + + switch(InpMethodMA) + { + case MODE_EMA: + if(i == ExtPeriodRSI + ExtPeriodMA - 2) + BufferCutlerRSI_MA[i] = SimpleMA(i, ExtPeriodMA, BufferCutlerRSI); + else + { + double pr = 2.0 / (ExtPeriodMA + 1.0); + BufferCutlerRSI_MA[i] = BufferCutlerRSI[i] * pr + BufferCutlerRSI_MA[i-1] * (1.0 - pr); + } + break; + case MODE_SMMA: + if(i == ExtPeriodRSI + ExtPeriodMA - 2) + BufferCutlerRSI_MA[i] = SimpleMA(i, ExtPeriodMA, BufferCutlerRSI); + else + BufferCutlerRSI_MA[i] = (BufferCutlerRSI_MA[i-1] * (ExtPeriodMA - 1) + BufferCutlerRSI[i]) / ExtPeriodMA; + break; + case MODE_LWMA: + BufferCutlerRSI_MA[i] = LinearWeightedMA(i, ExtPeriodMA, BufferCutlerRSI); + break; + default: // MODE_SMA + BufferCutlerRSI_MA[i] = SimpleMA(i, ExtPeriodMA, BufferCutlerRSI); + break; + } + } + + return(rates_total); + } +//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/FisherTransform_HeikenAshi.mq5 b/Indicators/MyIndicators/FisherTransform_HeikenAshi.mq5 new file mode 100644 index 0000000..8d536d7 --- /dev/null +++ b/Indicators/MyIndicators/FisherTransform_HeikenAshi.mq5 @@ -0,0 +1,187 @@ +//+------------------------------------------------------------------+ +//| FisherTransform_HeikenAshi.mq5 | +//| Copyright 2025, xxxxxxxx | +//| | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2025, xxxxxxxx" +#property link "" +#property version "1.00" +#property description "Fisher Transform Oscillator on Heiken Ashi data" + +//--- Custom Toolkit Include --- +#include + +//--- Indicator Window and Level Properties --- +#property indicator_separate_window +#property indicator_level1 1.5 +#property indicator_level2 0.75 +#property indicator_level3 0.0 +#property indicator_level4 -0.75 +#property indicator_level5 -1.5 +#property indicator_levelstyle STYLE_DOT + +//--- Buffers and Plots --- +#property indicator_buffers 3 // Fisher, Trigger, and 1 calculation buffer +#property indicator_plots 2 + +//--- Plot 1: Fisher line +#property indicator_label1 "HA_Fisher" +#property indicator_type1 DRAW_LINE +#property indicator_color1 clrBlue +#property indicator_style1 STYLE_SOLID +#property indicator_width1 1 + +//--- Plot 2: Trigger line +#property indicator_label2 "HA_Trigger" +#property indicator_type2 DRAW_LINE +#property indicator_color2 clrOrange +#property indicator_style2 STYLE_SOLID +#property indicator_width2 1 + +//--- Input Parameters --- +input int InpLength = 9; // Length + +//--- Indicator Buffers --- +double BufferHA_Fisher[]; +double BufferHA_Trigger[]; +double BufferValue[]; // Calculation buffer for the intermediate 'value' + +//--- Global Objects and Variables --- +int ExtLength; +CHA_Calculator g_ha_calculator; + +//--- Forward declarations for helper functions --- +double Highest(const double &array[], int period, int current_pos); +double Lowest(const double &array[], int period, int current_pos); + +//+------------------------------------------------------------------+ +//| Custom indicator initialization function. | +//+------------------------------------------------------------------+ +void OnInit() + { +//--- Validate and store input + ExtLength = (InpLength < 1) ? 1 : InpLength; + +//--- Map the buffers + SetIndexBuffer(0, BufferHA_Fisher, INDICATOR_DATA); + SetIndexBuffer(1, BufferHA_Trigger, INDICATOR_DATA); + SetIndexBuffer(2, BufferValue, INDICATOR_CALCULATIONS); + +//--- Set all buffers to non-timeseries for stable calculation + ArraySetAsSeries(BufferHA_Fisher, false); + ArraySetAsSeries(BufferHA_Trigger, false); + ArraySetAsSeries(BufferValue, false); + +//--- Set indicator properties + IndicatorSetInteger(INDICATOR_DIGITS, 4); + PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, ExtLength); + PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, ExtLength + 1); + IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA_Fisher(%d)", ExtLength)); + } + +//+------------------------------------------------------------------+ +//| Fisher Transform on Heiken Ashi calculation function. | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { +//--- Check for enough data + if(rates_total < ExtLength) + return(0); + +//--- STEP 1: Calculate Heiken Ashi bars using our toolkit + if(!g_ha_calculator.Calculate(rates_total, 0, open, high, low, close)) + return(0); + +//--- STEP 2: Create a buffer for Heiken Ashi HL2 price + double ha_hl2[]; + ArrayResize(ha_hl2, rates_total); + for(int i=0; i 0) + price_pos = (ha_hl2[i] - low_) / range - 0.5; + + BufferValue[i] = 0.33 * 2 * price_pos + 0.67 * BufferValue[i-1]; + + if(BufferValue[i] > 0.999) + BufferValue[i] = 0.999; + if(BufferValue[i] < -0.999) + BufferValue[i] = -0.999; + + // Calculate the Fisher Transform value + double log_val = 0.5 * MathLog((1 + BufferValue[i]) / (1 - BufferValue[i])); + BufferHA_Fisher[i] = log_val + 0.5 * BufferHA_Fisher[i-1]; + + // The trigger is the previous Fisher value + BufferHA_Trigger[i] = BufferHA_Fisher[i-1]; + } + + return(rates_total); + } + +//+------------------------------------------------------------------+ +//| Finds the highest value in a given period of an array. | +//+------------------------------------------------------------------+ +double Highest(const double &array[], int period, int current_pos) + { + double res = array[current_pos]; + for(int i = 1; i < period; i++) + { + int index = current_pos - i; + if(index < 0) + break; + if(res < array[index]) + res = array[index]; + } + return(res); + } + +//+------------------------------------------------------------------+ +//| Finds the lowest value in a given period of an array. | +//+------------------------------------------------------------------+ +double Lowest(const double &array[], int period, int current_pos) + { + double res = array[current_pos]; + for(int i = 1; i < period; i++) + { + int index = current_pos - i; + if(index < 0) + break; + if(res > array[index]) + res = array[index]; + } + return(res); + } +//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/Gann_HiLo_HeikenAshi.mq5 b/Indicators/MyIndicators/Gann_HiLo_HeikenAshi.mq5 new file mode 100644 index 0000000..6607d8a --- /dev/null +++ b/Indicators/MyIndicators/Gann_HiLo_HeikenAshi.mq5 @@ -0,0 +1,160 @@ +//+------------------------------------------------------------------+ +//| Gann_HiLo_HeikenAshi.mq5 | +//| Copyright 2025, xxxxxxxx | +//| | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2025, xxxxxxxx" +#property link "" +#property version "1.00" +#property description "Gann HiLo Activator on Heiken Ashi data with selectable MA" + +#include +#include + +//--- Indicator Window and Plot Properties --- +#property indicator_chart_window +#property indicator_buffers 5 +#property indicator_plots 1 + +//--- Plot 1: Gann HiLo line +#property indicator_label1 "HA_Gann_HiLo" +#property indicator_type1 DRAW_COLOR_LINE +#property indicator_color1 clrDodgerBlue, clrTomato +#property indicator_style1 STYLE_SOLID +#property indicator_width1 2 + +//--- Input Parameters --- +input int InpPeriod = 10; // Period for High/Low averages +input ENUM_MA_METHOD InpMAMethod = MODE_SMA; // Method for High/Low averages + +//--- Indicator Buffers --- +double BufferHA_GannHiLo[]; +double BufferColor[]; +double BufferHiAvg[]; +double BufferLoAvg[]; +double BufferTrend[]; + +//--- Global Objects and Variables --- +int ExtPeriod; +CHA_Calculator g_ha_calculator; + +//+------------------------------------------------------------------+ +//| Custom indicator initialization function. | +//+------------------------------------------------------------------+ +void OnInit() + { + ExtPeriod = (InpPeriod < 1) ? 1 : InpPeriod; + + SetIndexBuffer(0, BufferHA_GannHiLo, INDICATOR_DATA); + SetIndexBuffer(1, BufferColor, INDICATOR_COLOR_INDEX); + SetIndexBuffer(2, BufferHiAvg, INDICATOR_CALCULATIONS); + SetIndexBuffer(3, BufferLoAvg, INDICATOR_CALCULATIONS); + SetIndexBuffer(4, BufferTrend, INDICATOR_CALCULATIONS); + + ArraySetAsSeries(BufferHA_GannHiLo, false); + ArraySetAsSeries(BufferColor, false); + ArraySetAsSeries(BufferHiAvg, false); + ArraySetAsSeries(BufferLoAvg, false); + ArraySetAsSeries(BufferTrend, false); + + IndicatorSetInteger(INDICATOR_DIGITS, _Digits); + PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, ExtPeriod - 1); + IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA_Gann_HiLo(%d)", ExtPeriod)); + } + +//+------------------------------------------------------------------+ +//| Gann HiLo on Heiken Ashi calculation function. | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { + if(rates_total < ExtPeriod) + return(0); + +//--- STEP 1: Calculate Heiken Ashi bars using our toolkit + if(!g_ha_calculator.Calculate(rates_total, 0, open, high, low, close)) + return(0); + +//--- STEP 2: Calculate the two moving averages on HA High and HA Low + for(int i = 1; i < rates_total; i++) + { + if(i < ExtPeriod - 1) + continue; + + switch(InpMAMethod) + { + case MODE_EMA: + if(i == ExtPeriod - 1) + { + BufferHiAvg[i] = SimpleMA(i, ExtPeriod, g_ha_calculator.ha_high); + BufferLoAvg[i] = SimpleMA(i, ExtPeriod, g_ha_calculator.ha_low); + } + else + { + double pr = 2.0 / (ExtPeriod + 1.0); + BufferHiAvg[i] = g_ha_calculator.ha_high[i] * pr + BufferHiAvg[i-1] * (1.0 - pr); + BufferLoAvg[i] = g_ha_calculator.ha_low[i] * pr + BufferLoAvg[i-1] * (1.0 - pr); + } + break; + case MODE_SMMA: + if(i == ExtPeriod - 1) + { + BufferHiAvg[i] = SimpleMA(i, ExtPeriod, g_ha_calculator.ha_high); + BufferLoAvg[i] = SimpleMA(i, ExtPeriod, g_ha_calculator.ha_low); + } + else + { + BufferHiAvg[i] = (BufferHiAvg[i-1] * (ExtPeriod - 1) + g_ha_calculator.ha_high[i]) / ExtPeriod; + BufferLoAvg[i] = (BufferLoAvg[i-1] * (ExtPeriod - 1) + g_ha_calculator.ha_low[i]) / ExtPeriod; + } + break; + case MODE_LWMA: + BufferHiAvg[i] = LinearWeightedMA(i, ExtPeriod, g_ha_calculator.ha_high); + BufferLoAvg[i] = LinearWeightedMA(i, ExtPeriod, g_ha_calculator.ha_low); + break; + default: // MODE_SMA + BufferHiAvg[i] = SimpleMA(i, ExtPeriod, g_ha_calculator.ha_high); + BufferLoAvg[i] = SimpleMA(i, ExtPeriod, g_ha_calculator.ha_low); + break; + } + } + +//--- STEP 3 & 4: Determine trend and set the final Gann HiLo value + for(int i = 1; i < rates_total; i++) + { + if(i < ExtPeriod -1) + continue; + + // Use HA Close to determine the trend + if(g_ha_calculator.ha_close[i] > BufferHiAvg[i]) + BufferTrend[i] = 1; // Up trend + else + if(g_ha_calculator.ha_close[i] < BufferLoAvg[i]) + BufferTrend[i] = -1; // Down trend + else + BufferTrend[i] = BufferTrend[i-1]; + + if(BufferTrend[i] == 1) + { + BufferHA_GannHiLo[i] = BufferLoAvg[i]; + BufferColor[i] = 0; + } + else + { + BufferHA_GannHiLo[i] = BufferHiAvg[i]; + BufferColor[i] = 1; + } + } + + return(rates_total); + } +//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/McGinleyDynamic_HeikenAshi.mq5 b/Indicators/MyIndicators/McGinleyDynamic_HeikenAshi.mq5 new file mode 100644 index 0000000..7c5dd7e --- /dev/null +++ b/Indicators/MyIndicators/McGinleyDynamic_HeikenAshi.mq5 @@ -0,0 +1,158 @@ +//+------------------------------------------------------------------+ +//| McGinleyDynamic_HeikenAshi.mq5 | +//| Copyright 2025, xxxxxxxx | +//| | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2025, xxxxxxxx" +#property link "" +#property version "1.01" // Corrected array handling +#property description "McGinley Dynamic Indicator on Heiken Ashi data" + +#include +#include + +//--- Indicator Window and Plot Properties --- +#property indicator_chart_window +#property indicator_buffers 1 +#property indicator_plots 1 + +//--- Plot 1: McGinley Dynamic line +#property indicator_label1 "HA_McGinley" +#property indicator_type1 DRAW_LINE +#property indicator_color1 clrCrimson +#property indicator_style1 STYLE_SOLID +#property indicator_width1 2 + +//--- Enum for selecting Heiken Ashi price source --- +enum ENUM_HA_APPLIED_PRICE + { + HA_PRICE_CLOSE, // Heiken Ashi Close + HA_PRICE_OPEN, // Heiken Ashi Open + HA_PRICE_HIGH, // Heiken Ashi High + HA_PRICE_LOW, // Heiken Ashi Low + }; + +//--- Input Parameters --- +input int InpLength = 14; +input ENUM_HA_APPLIED_PRICE InpAppliedPrice = HA_PRICE_CLOSE; + +//--- Indicator Buffers --- +double BufferHA_McGinley[]; + +//--- Global Objects and Variables --- +int ExtLength; +CHA_Calculator g_ha_calculator; + +//+------------------------------------------------------------------+ +//| Custom indicator initialization function. | +//+------------------------------------------------------------------+ +void OnInit() + { + ExtLength = (InpLength < 1) ? 1 : InpLength; + + SetIndexBuffer(0, BufferHA_McGinley, INDICATOR_DATA); + ArraySetAsSeries(BufferHA_McGinley, false); + + IndicatorSetInteger(INDICATOR_DIGITS, _Digits); + PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, ExtLength); + IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA_McGinley(%d)", ExtLength)); + } + +//+------------------------------------------------------------------+ +//| McGinley Dynamic on Heiken Ashi calculation function. | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { + if(rates_total < ExtLength) + return(0); + +//--- STEP 1: Calculate Heiken Ashi bars using our toolkit + if(!g_ha_calculator.Calculate(rates_total, 0, open, high, low, close)) + return(0); + +//--- STEP 2: Main calculation loop + for(int i = 1; i < rates_total; i++) + { + if(i < ExtLength) + { + BufferHA_McGinley[i] = EMPTY_VALUE; + continue; + } + + // Select the source price for the current bar 'i' + double source_price = 0; + switch(InpAppliedPrice) + { + case HA_PRICE_OPEN: + source_price = g_ha_calculator.ha_open[i]; + break; + case HA_PRICE_HIGH: + source_price = g_ha_calculator.ha_high[i]; + break; + case HA_PRICE_LOW: + source_price = g_ha_calculator.ha_low[i]; + break; + default: + source_price = g_ha_calculator.ha_close[i]; + break; + } + + // --- Initialization Step --- + if(i == ExtLength) + { + // The first McGinley value is an SMA of the source HA price + // We need to create a temporary array for the SMA function + double temp_price_array[]; + switch(InpAppliedPrice) + { + case HA_PRICE_OPEN: + ArrayCopy(temp_price_array, g_ha_calculator.ha_open); + break; + case HA_PRICE_HIGH: + ArrayCopy(temp_price_array, g_ha_calculator.ha_high); + break; + case HA_PRICE_LOW: + ArrayCopy(temp_price_array, g_ha_calculator.ha_low); + break; + default: + ArrayCopy(temp_price_array, g_ha_calculator.ha_close); + break; + } + BufferHA_McGinley[i] = SimpleMA(i, ExtLength, temp_price_array); + continue; + } + + // --- Recursive Calculation Step --- + double prev_mg = BufferHA_McGinley[i-1]; + + if(prev_mg == 0) + { + BufferHA_McGinley[i] = source_price; + continue; + } + + double ratio = source_price / prev_mg; + double denominator = ExtLength * MathPow(ratio, 4); + + if(denominator == 0) + { + BufferHA_McGinley[i] = prev_mg; + continue; + } + + BufferHA_McGinley[i] = prev_mg + (source_price - prev_mg) / denominator; + } + + return(rates_total); + } +//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/RSI_HeikenAshi.mq5 b/Indicators/MyIndicators/RSI_HeikenAshi.mq5 new file mode 100644 index 0000000..cc25d99 Binary files /dev/null and b/Indicators/MyIndicators/RSI_HeikenAshi.mq5 differ diff --git a/Indicators/MyIndicators/SMI_HeikenAshi.mq5 b/Indicators/MyIndicators/SMI_HeikenAshi.mq5 new file mode 100644 index 0000000..90c4ffd --- /dev/null +++ b/Indicators/MyIndicators/SMI_HeikenAshi.mq5 @@ -0,0 +1,241 @@ +//+------------------------------------------------------------------+ +//| SMI_HeikenAshi.mq5 | +//| Copyright 2025, xxxxxxxx | +//| | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2025, xxxxxxxx" +#property link "" +#property version "1.00" +#property description "Stochastic Momentum Index (SMI) on Heiken Ashi data" + +// --- Custom Toolkit Include --- +#include + +//--- Indicator Window and Level Properties --- +#property indicator_separate_window +#property indicator_level1 40.0 +#property indicator_level2 0.0 +#property indicator_level3 -40.0 +#property indicator_levelstyle STYLE_DOT + +//--- Buffers and Plots --- +#property indicator_buffers 8 // SMI, Signal, and 6 calculation buffers +#property indicator_plots 2 + +//--- Plot 1: SMI line +#property indicator_label1 "HA_SMI" +#property indicator_type1 DRAW_LINE +#property indicator_color1 clrBlue +#property indicator_style1 STYLE_SOLID +#property indicator_width1 1 + +//--- Plot 2: Signal line (EMA of SMI) +#property indicator_label2 "HA_Signal" +#property indicator_type2 DRAW_LINE +#property indicator_color2 clrOrange +#property indicator_style2 STYLE_DOT +#property indicator_width2 1 + +//--- Input Parameters --- +input int InpLengthK = 10; // %K Length +input int InpLengthD = 3; // %D Length (for double smoothing) +input int InpLengthEMA = 3; // EMA Length (for signal line) + +//--- Indicator Buffers --- +double BufferSMI[]; +double BufferSignal[]; +double BufferHighestHigh[]; +double BufferLowestLow[]; +double BufferHighestLowestRange[]; +double BufferRelativeRange[]; +double BufferEmaEma_Relative[]; +double BufferEmaEma_Range[]; + +//--- Global Objects and Variables --- +int ExtLengthK, ExtLengthD, ExtLengthEMA; +CHA_Calculator g_ha_calculator; + +//--- Forward declarations for helper functions --- +double Highest(const double &array[], int period, int current_pos); +double Lowest(const double &array[], int period, int current_pos); + +//+------------------------------------------------------------------+ +//| Custom indicator initialization function. | +//+------------------------------------------------------------------+ +void OnInit() + { +//--- Validate and store inputs + ExtLengthK = (InpLengthK < 1) ? 1 : InpLengthK; + ExtLengthD = (InpLengthD < 1) ? 1 : InpLengthD; + ExtLengthEMA = (InpLengthEMA < 1) ? 1 : InpLengthEMA; + +//--- Map the buffers + SetIndexBuffer(0, BufferSMI, INDICATOR_DATA); + SetIndexBuffer(1, BufferSignal, INDICATOR_DATA); + SetIndexBuffer(2, BufferHighestHigh, INDICATOR_CALCULATIONS); + SetIndexBuffer(3, BufferLowestLow, INDICATOR_CALCULATIONS); + SetIndexBuffer(4, BufferHighestLowestRange, INDICATOR_CALCULATIONS); + SetIndexBuffer(5, BufferRelativeRange, INDICATOR_CALCULATIONS); + SetIndexBuffer(6, BufferEmaEma_Relative, INDICATOR_CALCULATIONS); + SetIndexBuffer(7, BufferEmaEma_Range, INDICATOR_CALCULATIONS); + +//--- Set all buffers to non-timeseries manually --- + ArraySetAsSeries(BufferSMI, false); + ArraySetAsSeries(BufferSignal, false); + ArraySetAsSeries(BufferHighestHigh, false); + ArraySetAsSeries(BufferLowestLow, false); + ArraySetAsSeries(BufferHighestLowestRange, false); + ArraySetAsSeries(BufferRelativeRange, false); + ArraySetAsSeries(BufferEmaEma_Relative, false); + ArraySetAsSeries(BufferEmaEma_Range, false); + +//--- Set indicator properties + IndicatorSetInteger(INDICATOR_DIGITS, 2); + PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, ExtLengthK + ExtLengthD - 2); + PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, ExtLengthK + ExtLengthD + ExtLengthEMA - 3); + IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA_SMI(%d,%d,%d)", ExtLengthK, ExtLengthD, ExtLengthEMA)); + } + +//+------------------------------------------------------------------+ +//| Stochastic Momentum Index calculation function. | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { +//--- Check for enough data + if(rates_total < ExtLengthK + ExtLengthD) + return(0); + +//--- STEP 1: Calculate Heiken Ashi bars using our toolkit + if(!g_ha_calculator.Calculate(rates_total, 0, open, high, low, close)) + return(0); + +//--- STEP 2-4: Calculate Highest, Lowest, and Ranges using HA data + for(int i = ExtLengthK - 1; i < rates_total; i++) + { + // Use HA High and HA Low from our calculator + BufferHighestHigh[i] = Highest(g_ha_calculator.ha_high, ExtLengthK, i); + BufferLowestLow[i] = Lowest(g_ha_calculator.ha_low, ExtLengthK, i); + BufferHighestLowestRange[i] = BufferHighestHigh[i] - BufferLowestLow[i]; + // Use HA Close from our calculator + BufferRelativeRange[i] = g_ha_calculator.ha_close[i] - (BufferHighestHigh[i] + BufferLowestLow[i]) / 2.0; + } + +//--- STEP 5: Double EMA Smoothing (Robust Manual Calculation) + double temp_ema_relative[], temp_ema_range[]; + ArrayResize(temp_ema_relative, rates_total); + ArrayResize(temp_ema_range, rates_total); + double pr = 2.0 / (ExtLengthD + 1.0); + + for(int i = 1; i < rates_total; i++) + { + if(i < ExtLengthK - 1) + continue; + if(i == ExtLengthK - 1) + { + temp_ema_relative[i] = BufferRelativeRange[i]; + temp_ema_range[i] = BufferHighestLowestRange[i]; + } + else + { + temp_ema_relative[i] = BufferRelativeRange[i] * pr + temp_ema_relative[i-1] * (1.0 - pr); + temp_ema_range[i] = BufferHighestLowestRange[i] * pr + temp_ema_range[i-1] * (1.0 - pr); + } + } + + for(int i = 1; i < rates_total; i++) + { + if(i < ExtLengthK + ExtLengthD - 2) + continue; + if(i == ExtLengthK + ExtLengthD - 2) + { + double sum_rel=0, sum_ran=0; + for(int j=i-ExtLengthD+1; j<=i; j++) + { + sum_rel += temp_ema_relative[j]; + sum_ran += temp_ema_range[j]; + } + BufferEmaEma_Relative[i] = sum_rel / ExtLengthD; + BufferEmaEma_Range[i] = sum_ran / ExtLengthD; + } + else + { + BufferEmaEma_Relative[i] = temp_ema_relative[i] * pr + BufferEmaEma_Relative[i-1] * (1.0 - pr); + BufferEmaEma_Range[i] = temp_ema_range[i] * pr + BufferEmaEma_Range[i-1] * (1.0 - pr); + } + } + +//--- STEP 6: Calculate final SMI value + for(int i = ExtLengthK + ExtLengthD - 2; i < rates_total; i++) + { + if(BufferEmaEma_Range[i] != 0) + BufferSMI[i] = 200 * (BufferEmaEma_Relative[i] / BufferEmaEma_Range[i]); + else + BufferSMI[i] = 0; + } + +//--- STEP 7: Calculate the signal line (EMA of SMI) + double pr_signal = 2.0 / (ExtLengthEMA + 1.0); + for(int i = 1; i < rates_total; i++) + { + if(i < ExtLengthK + ExtLengthD + ExtLengthEMA - 3) + continue; + if(i == ExtLengthK + ExtLengthD + ExtLengthEMA - 3) + { + double sum_smi=0; + for(int j=i-ExtLengthEMA+1; j<=i; j++) + sum_smi += BufferSMI[j]; + BufferSignal[i] = sum_smi / ExtLengthEMA; + } + else + { + BufferSignal[i] = BufferSMI[i] * pr_signal + BufferSignal[i-1] * (1.0 - pr_signal); + } + } + + return(rates_total); + } + +//+------------------------------------------------------------------+ +//| Finds the highest value in a given period of an array. | +//+------------------------------------------------------------------+ +double Highest(const double &array[], int period, int current_pos) + { + double res = array[current_pos]; + for(int i = 1; i < period; i++) + { + int index = current_pos - i; + if(index < 0) + break; + if(res < array[index]) + res = array[index]; + } + return(res); + } + +//+------------------------------------------------------------------+ +//| Finds the lowest value in a given period of an array. | +//+------------------------------------------------------------------+ +double Lowest(const double &array[], int period, int current_pos) + { + double res = array[current_pos]; + for(int i = 1; i < period; i++) + { + int index = current_pos - i; + if(index < 0) + break; + if(res > array[index]) + res = array[index]; + } + return(res); + } +//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/StochRSI_Fast_HeikenAshi.mq5 b/Indicators/MyIndicators/StochRSI_Fast_HeikenAshi.mq5 new file mode 100644 index 0000000..f185ff8 --- /dev/null +++ b/Indicators/MyIndicators/StochRSI_Fast_HeikenAshi.mq5 @@ -0,0 +1,183 @@ +//+------------------------------------------------------------------+ +//| StochRSI_Fast_HeikenAshi.mq5 | +//| Copyright 2025, xxxxxxxx | +//| | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2025, xxxxxxxx" +#property link "" +#property version "1.00" +#property description "Fast Stochastic on a Heiken Ashi based RSI" + +//--- Indicator Window and Level Properties --- +#property indicator_separate_window +#property indicator_buffers 2 // %K and %D +#property indicator_plots 2 +#property indicator_level1 20.0 +#property indicator_level2 80.0 +#property indicator_minimum -10.0 // Allow for overshoots +#property indicator_maximum 110.0 // Allow for overshoots + +//--- Plot 1: %K line +#property indicator_label1 "HA_%K" +#property indicator_type1 DRAW_LINE +#property indicator_color1 clrBlue +#property indicator_style1 STYLE_SOLID +#property indicator_width1 1 + +//--- Plot 2: %D line +#property indicator_label2 "HA_%D" +#property indicator_type2 DRAW_LINE +#property indicator_color2 clrOrange +#property indicator_style2 STYLE_SOLID +#property indicator_width2 1 + +//--- Input Parameters --- +input int InpLengthRSI = 14; // RSI Length +input int InpLengthStoch = 14; // Stochastic Length (%K Period) +input int InpSmoothD = 3; // %D Smoothing (Signal Line) + +//--- Indicator Buffers --- +double BufferK[]; +double BufferD[]; +double BufferHA_RSI[]; // Buffer to store the Heiken Ashi RSI values + +//--- Global Variables --- +int ExtLengthRSI, ExtLengthStoch, ExtSmoothD; +int handle_ha_rsi; // Handle for our custom RSI_HeikenAshi indicator + +//--- Forward declarations for helper functions --- +double Highest(const double &array[], int period, int current_pos); +double Lowest(const double &array[], int period, int current_pos); + +//+------------------------------------------------------------------+ +//| Custom indicator initialization function. | +//+------------------------------------------------------------------+ +void OnInit() + { + ExtLengthRSI = (InpLengthRSI < 1) ? 1 : InpLengthRSI; + ExtLengthStoch = (InpLengthStoch < 1) ? 1 : InpLengthStoch; + ExtSmoothD = (InpSmoothD < 1) ? 1 : InpSmoothD; + + SetIndexBuffer(0, BufferK, INDICATOR_DATA); + SetIndexBuffer(1, BufferD, INDICATOR_DATA); + SetIndexBuffer(2, BufferHA_RSI, INDICATOR_CALCULATIONS); + + ArraySetAsSeries(BufferK, false); + ArraySetAsSeries(BufferD, false); + ArraySetAsSeries(BufferHA_RSI, false); + +//--- Create a handle to our custom RSI_HeikenAshi indicator --- +// The path must be relative to the MQL5/Indicators/ folder +// We assume it's in the MyIndicators subfolder + string indicator_path = "MyIndicators\\RSI_HeikenAshi"; + handle_ha_rsi = iCustom(_Symbol, _Period, indicator_path, + InpLengthRSI, // Pass RSI Period + 14, // Pass default MA Period (not used by the RSI line itself) + MODE_SMA // Pass default MA Method (not used) + ); + if(handle_ha_rsi == INVALID_HANDLE) + Print("Error creating iCustom handle for RSI_HeikenAshi."); + + IndicatorSetInteger(INDICATOR_DIGITS, 2); + PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, ExtLengthRSI + ExtLengthStoch - 2); + PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, ExtLengthRSI + ExtLengthStoch + ExtSmoothD - 3); + IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA_StochRSI_Fast(%d,%d,%d)", ExtLengthRSI, ExtLengthStoch, ExtSmoothD)); + } + +//+------------------------------------------------------------------+ +//| Fast StochRSI on Heiken Ashi calculation function. | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { + if(rates_total < ExtLengthRSI + ExtLengthStoch) + return(0); + +//--- STEP 1: Get Heiken Ashi RSI values from our custom indicator + if(BarsCalculated(handle_ha_rsi) < rates_total) + return(0); +// We need the raw HA_RSI line, which is in buffer #1 of the RSI_HeikenAshi indicator + if(CopyBuffer(handle_ha_rsi, 1, 0, rates_total, BufferHA_RSI) <= 0) + return(0); + +//--- Main calculation loop + for(int i = 0; i < rates_total; i++) + { + //--- STEP 2: Calculate Fast %K on the HA_RSI buffer --- + if(i >= ExtLengthRSI + ExtLengthStoch - 2) + { + double highest_ha_rsi = Highest(BufferHA_RSI, ExtLengthStoch, i); + double lowest_ha_rsi = Lowest(BufferHA_RSI, ExtLengthStoch, i); + + double range = highest_ha_rsi - lowest_ha_rsi; + if(range > 0.00001) + BufferK[i] = (BufferHA_RSI[i] - lowest_ha_rsi) / range * 100.0; + else + BufferK[i] = (i > 0) ? BufferK[i-1] : 50.0; + } + else + { + BufferK[i] = 0; + } + + //--- STEP 3: Calculate %D (Signal Line) as an SMA of %K --- + if(i >= ExtLengthRSI + ExtLengthStoch + ExtSmoothD - 3) + { + double sum = 0; + for(int j = 0; j < ExtSmoothD; j++) + { + sum += BufferK[i-j]; + } + BufferD[i] = sum / ExtSmoothD; + } + else + { + BufferD[i] = 0; + } + } + return(rates_total); + } + +//+------------------------------------------------------------------+ +//| Finds the highest value in a given period of an array. | +//+------------------------------------------------------------------+ +double Highest(const double &array[], int period, int current_pos) + { + double res = array[current_pos]; + for(int i = 1; i < period; i++) + { + int index = current_pos - i; + if(index < 0) + break; + if(res < array[index]) + res = array[index]; + } + return(res); + } + +//+------------------------------------------------------------------+ +//| Finds the lowest value in a given period of an array. | +//+------------------------------------------------------------------+ +double Lowest(const double &array[], int period, int current_pos) + { + double res = array[current_pos]; + for(int i = 1; i < period; i++) + { + int index = current_pos - i; + if(index < 0) + break; + if(res > array[index]) + res = array[index]; + } + return(res); + } +//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/StochRSI_Slow_HeikenAshi.mq5 b/Indicators/MyIndicators/StochRSI_Slow_HeikenAshi.mq5 new file mode 100644 index 0000000..4542b13 --- /dev/null +++ b/Indicators/MyIndicators/StochRSI_Slow_HeikenAshi.mq5 @@ -0,0 +1,201 @@ +//+------------------------------------------------------------------+ +//| StochRSI_Slow_HeikenAshi.mq5 | +//| Copyright 2025, xxxxxxxx | +//| | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2025, xxxxxxxx" +#property link "" +#property version "1.00" +#property description "Slow Stochastic on a Heiken Ashi based RSI" + +//--- Indicator Window and Level Properties --- +#property indicator_separate_window +#property indicator_buffers 4 // %K, %D, RawK, and HA_RSI buffer +#property indicator_plots 2 +#property indicator_level1 20.0 +#property indicator_level2 80.0 +#property indicator_minimum -10.0 +#property indicator_maximum 110.0 + +//--- Plot 1: %K line (Slow) +#property indicator_label1 "HA_%K" +#property indicator_type1 DRAW_LINE +#property indicator_color1 clrLightSeaGreen +#property indicator_style1 STYLE_SOLID +#property indicator_width1 1 + +//--- Plot 2: %D line (Signal) +#property indicator_label2 "HA_%D" +#property indicator_type2 DRAW_LINE +#property indicator_color2 clrRed +#property indicator_style2 STYLE_DOT +#property indicator_width2 1 + +//--- Input Parameters --- +input int InpLengthRSI = 14; // RSI Length +input int InpLengthStoch = 14; // Stochastic %K Period +input int InpSlowing = 3; // Slowing Period +input int InpSmoothD = 3; // %D Smoothing Period + +//--- Indicator Buffers --- +double BufferK[]; +double BufferD[]; +double BufferHA_RSI[]; +double BufferRawStochK[]; + +//--- Global Variables --- +int ExtLengthRSI, ExtLengthStoch, ExtSlowing, ExtSmoothD; +int handle_ha_rsi; // Handle for our custom RSI_HeikenAshi indicator + +//--- Forward declarations for helper functions --- +double Highest(const double &array[], int period, int current_pos); +double Lowest(const double &array[], int period, int current_pos); + +//+------------------------------------------------------------------+ +//| Custom indicator initialization function. | +//+------------------------------------------------------------------+ +void OnInit() + { + ExtLengthRSI = (InpLengthRSI < 1) ? 1 : InpLengthRSI; + ExtLengthStoch = (InpLengthStoch < 1) ? 1 : InpLengthStoch; + ExtSlowing = (InpSlowing < 1) ? 1 : InpSlowing; + ExtSmoothD = (InpSmoothD < 1) ? 1 : InpSmoothD; + + SetIndexBuffer(0, BufferK, INDICATOR_DATA); + SetIndexBuffer(1, BufferD, INDICATOR_DATA); + SetIndexBuffer(2, BufferHA_RSI, INDICATOR_CALCULATIONS); + SetIndexBuffer(3, BufferRawStochK, INDICATOR_CALCULATIONS); + + ArraySetAsSeries(BufferK, false); + ArraySetAsSeries(BufferD, false); + ArraySetAsSeries(BufferHA_RSI, false); + ArraySetAsSeries(BufferRawStochK, false); + +//--- Create a handle to our custom RSI_HeikenAshi indicator + string indicator_path = "MyIndicators\\RSI_HeikenAshi"; + handle_ha_rsi = iCustom(_Symbol, _Period, indicator_path, + ExtLengthRSI, // Pass RSI Period + 14, // Pass default MA Period + MODE_SMA // Pass default MA Method + ); + if(handle_ha_rsi == INVALID_HANDLE) + Print("Error creating iCustom handle for RSI_HeikenAshi."); + + IndicatorSetInteger(INDICATOR_DIGITS, 2); + PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, ExtLengthRSI + ExtLengthStoch + ExtSlowing - 3); + PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, ExtLengthRSI + ExtLengthStoch + ExtSlowing + ExtSmoothD - 4); + IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA_StochRSI_Slow(%d,%d,%d,%d)", ExtLengthRSI, ExtLengthStoch, ExtSlowing, ExtSmoothD)); + } + +//+------------------------------------------------------------------+ +//| Slow StochRSI on Heiken Ashi calculation function. | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { + if(rates_total < ExtLengthRSI + ExtLengthStoch) + return(0); + +//--- STEP 1: Get Heiken Ashi RSI values from our custom indicator + if(BarsCalculated(handle_ha_rsi) < rates_total) + return(0); +// We need the raw HA_RSI line, which is in buffer #1 of the RSI_HeikenAshi indicator + if(CopyBuffer(handle_ha_rsi, 1, 0, rates_total, BufferHA_RSI) <= 0) + return(0); + +//--- Main calculation loop + for(int i = 0; i < rates_total; i++) + { + //--- STEP 2: Calculate Raw Stochastic %K on the HA_RSI buffer --- + if(i >= ExtLengthRSI + ExtLengthStoch - 2) + { + double highest_ha_rsi = Highest(BufferHA_RSI, ExtLengthStoch, i); + double lowest_ha_rsi = Lowest(BufferHA_RSI, ExtLengthStoch, i); + + double range = highest_ha_rsi - lowest_ha_rsi; + if(range > 0.00001) + BufferRawStochK[i] = (BufferHA_RSI[i] - lowest_ha_rsi) / range * 100.0; + else + BufferRawStochK[i] = (i > 0) ? BufferRawStochK[i-1] : 50.0; + } + else + { + BufferRawStochK[i] = 0; + } + + //--- STEP 3: Calculate Slow %K (Main Line) by smoothing Raw %K --- + if(i >= ExtLengthRSI + ExtLengthStoch + ExtSlowing - 3) + { + double sum = 0; + for(int j = 0; j < ExtSlowing; j++) + { + sum += BufferRawStochK[i-j]; + } + BufferK[i] = sum / ExtSlowing; + } + else + { + BufferK[i] = 0; + } + + //--- STEP 4: Calculate %D (Signal Line) by smoothing Slow %K --- + if(i >= ExtLengthRSI + ExtLengthStoch + ExtSlowing + ExtSmoothD - 4) + { + double sum = 0; + for(int j = 0; j < ExtSmoothD; j++) + { + sum += BufferK[i-j]; + } + BufferD[i] = sum / ExtSmoothD; + } + else + { + BufferD[i] = 0; + } + } + return(rates_total); + } + +//+------------------------------------------------------------------+ +//| Finds the highest value in a given period of an array. | +//+------------------------------------------------------------------+ +double Highest(const double &array[], int period, int current_pos) + { + double res = array[current_pos]; + for(int i = 1; i < period; i++) + { + int index = current_pos - i; + if(index < 0) + break; + if(res < array[index]) + res = array[index]; + } + return(res); + } + +//+------------------------------------------------------------------+ +//| Finds the lowest value in a given period of an array. | +//+------------------------------------------------------------------+ +double Lowest(const double &array[], int period, int current_pos) + { + double res = array[current_pos]; + for(int i = 1; i < period; i++) + { + int index = current_pos - i; + if(index < 0) + break; + if(res > array[index]) + res = array[index]; + } + return(res); + } +//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/StochasticFast_HeikenAshi.mq5 b/Indicators/MyIndicators/StochasticFast_HeikenAshi.mq5 new file mode 100644 index 0000000..903ece7 --- /dev/null +++ b/Indicators/MyIndicators/StochasticFast_HeikenAshi.mq5 @@ -0,0 +1,172 @@ +//+------------------------------------------------------------------+ +//| StochasticFast_HeikenAshi.mq5 | +//| Copyright 2025, xxxxxxxx | +//| | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2025, xxxxxxxx" +#property link "" +#property version "1.00" +#property description "Fast Stochastic Oscillator on Heiken Ashi data" + +//--- Custom Toolkit Include --- +#include + +//--- Indicator Window and Level Properties --- +#property indicator_separate_window +#property indicator_buffers 2 // %K (Main) and %D (Signal) +#property indicator_plots 2 +#property indicator_level1 20.0 +#property indicator_level2 80.0 +#property indicator_minimum 0.0 +#property indicator_maximum 100.0 + +//--- Plot 1: %K line (Fast) +#property indicator_label1 "HA_%K" +#property indicator_type1 DRAW_LINE +#property indicator_color1 clrLightSeaGreen +#property indicator_style1 STYLE_SOLID +#property indicator_width1 1 + +//--- Plot 2: %D line (Signal) +#property indicator_label2 "HA_%D" +#property indicator_type2 DRAW_LINE +#property indicator_color2 clrRed +#property indicator_style2 STYLE_DOT +#property indicator_width2 1 + +//--- Input Parameters --- +input int InpKPeriod = 14; // %K Period (Stochastic period) +input int InpDPeriod = 3; // %D Period (signal line smoothing) + +//--- Indicator Buffers --- +double BufferHA_K[]; // Plotted buffer for the main %K line +double BufferHA_D[]; // Plotted buffer for the signal %D line + +//--- Global Objects and Variables --- +int ExtKPeriod, ExtDPeriod; +CHA_Calculator g_ha_calculator; + +//--- Forward declarations for helper functions --- +double Highest(const double &array[], int period, int current_pos); +double Lowest(const double &array[], int period, int current_pos); + +//+------------------------------------------------------------------+ +//| Custom indicator initialization function. | +//+------------------------------------------------------------------+ +void OnInit() + { +//--- Validate and store input periods + ExtKPeriod = (InpKPeriod < 1) ? 1 : InpKPeriod; + ExtDPeriod = (InpDPeriod < 1) ? 1 : InpDPeriod; + +//--- Map the buffers and set as non-timeseries + SetIndexBuffer(0, BufferHA_K, INDICATOR_DATA); + SetIndexBuffer(1, BufferHA_D, INDICATOR_DATA); + ArraySetAsSeries(BufferHA_K, false); + ArraySetAsSeries(BufferHA_D, false); + +//--- Set indicator display properties + IndicatorSetInteger(INDICATOR_DIGITS, 2); + PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, ExtKPeriod - 1); + PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, ExtKPeriod + ExtDPeriod - 2); + IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA_Fast_Stoch(%d,%d)", ExtKPeriod, ExtDPeriod)); + } + +//+------------------------------------------------------------------+ +//| Fast Stochastic on Heiken Ashi calculation function. | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { +//--- Check if there is enough historical data + if(rates_total < ExtKPeriod + ExtDPeriod) + return(0); + +//--- STEP 1: Calculate Heiken Ashi bars using our toolkit + if(!g_ha_calculator.Calculate(rates_total, 0, open, high, low, close)) + return(0); + +//--- Main calculation loop, iterating from past to present + for(int i = 0; i < rates_total; i++) + { + //--- STEP 2: Calculate Raw %K using Heiken Ashi data --- + if(i >= ExtKPeriod - 1) + { + // Use HA High and HA Low from our calculator + double highest_ha_high = Highest(g_ha_calculator.ha_high, ExtKPeriod, i); + double lowest_ha_low = Lowest(g_ha_calculator.ha_low, ExtKPeriod, i); + + double range = highest_ha_high - lowest_ha_low; + if(range > 0) + // Use HA Close from our calculator + BufferHA_K[i] = (g_ha_calculator.ha_close[i] - lowest_ha_low) / range * 100.0; + else + BufferHA_K[i] = (i > 0) ? BufferHA_K[i-1] : 50.0; + } + else + { + BufferHA_K[i] = 0; // Not enough data yet + } + + //--- STEP 3: Calculate %D (Signal Line) as an SMA of %K --- + if(i >= ExtKPeriod + ExtDPeriod - 2) + { + double sum = 0; + for(int j = 0; j < ExtDPeriod; j++) + { + sum += BufferHA_K[i-j]; + } + BufferHA_D[i] = sum / ExtDPeriod; + } + else + { + BufferHA_D[i] = 0; // Not enough data yet + } + } +//--- Return value of prev_calculated for next call + return(rates_total); + } + +//+------------------------------------------------------------------+ +//| Finds the highest value in a given period of an array. | +//+------------------------------------------------------------------+ +double Highest(const double &array[], int period, int current_pos) + { + double res = array[current_pos]; + for(int i = 1; i < period; i++) + { + int index = current_pos - i; + if(index < 0) + break; + if(res < array[index]) + res = array[index]; + } + return(res); + } + +//+------------------------------------------------------------------+ +//| Finds the lowest value in a given period of an array. | +//+------------------------------------------------------------------+ +double Lowest(const double &array[], int period, int current_pos) + { + double res = array[current_pos]; + for(int i = 1; i < period; i++) + { + int index = current_pos - i; + if(index < 0) + break; + if(res > array[index]) + res = array[index]; + } + return(res); + } +//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/StochasticSlow_HeikenAshi.mq5 b/Indicators/MyIndicators/StochasticSlow_HeikenAshi.mq5 new file mode 100644 index 0000000..ac6a005 --- /dev/null +++ b/Indicators/MyIndicators/StochasticSlow_HeikenAshi.mq5 @@ -0,0 +1,190 @@ +//+------------------------------------------------------------------+ +//| StochasticSlow_HeikenAshi.mq5| +//| Copyright 2025, xxxxxxxx | +//| | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2025, xxxxxxxx" +#property link "" +#property version "1.00" +#property description "Slow Stochastic Oscillator on Heiken Ashi data" + +#include + +//--- Indicator Window and Level Properties --- +#property indicator_separate_window +#property indicator_buffers 3 // %K, %D, and Raw %K for calculation +#property indicator_plots 2 +#property indicator_level1 20.0 +#property indicator_level2 80.0 +#property indicator_minimum 0.0 +#property indicator_maximum 100.0 + +//--- Plot 1: %K line (Slow) +#property indicator_label1 "HA_%K" +#property indicator_type1 DRAW_LINE +#property indicator_color1 clrLightSeaGreen +#property indicator_style1 STYLE_SOLID +#property indicator_width1 1 + +//--- Plot 2: %D line (Signal) +#property indicator_label2 "HA_%D" +#property indicator_type2 DRAW_LINE +#property indicator_color2 clrRed +#property indicator_style2 STYLE_DOT +#property indicator_width2 1 + +//--- Input Parameters --- +input int InpKPeriod = 5; // %K Period +input int InpDPeriod = 3; // %D Period (signal line smoothing) +input int InpSlowing = 3; // Slowing (initial %K smoothing) + +//--- Indicator Buffers --- +double BufferHA_K[]; // Plotted buffer for the main (Slow) %K line +double BufferHA_D[]; // Plotted buffer for the signal %D line +double BufferRawK[]; // Calculation buffer for raw %K before slowing + +//--- Global Objects and Variables --- +int ExtKPeriod, ExtDPeriod, ExtSlowing; +CHA_Calculator g_ha_calculator; + +//--- Forward declarations for helper functions --- +double Highest(const double &array[], int period, int current_pos); +double Lowest(const double &array[], int period, int current_pos); + +//+------------------------------------------------------------------+ +//| Custom indicator initialization function. | +//+------------------------------------------------------------------+ +void OnInit() + { +//--- Validate and store input periods + ExtKPeriod = (InpKPeriod < 1) ? 1 : InpKPeriod; + ExtDPeriod = (InpDPeriod < 1) ? 1 : InpDPeriod; + ExtSlowing = (InpSlowing < 1) ? 1 : InpSlowing; + +//--- Map the buffers and set as non-timeseries + SetIndexBuffer(0, BufferHA_K, INDICATOR_DATA); + SetIndexBuffer(1, BufferHA_D, INDICATOR_DATA); + SetIndexBuffer(2, BufferRawK, INDICATOR_CALCULATIONS); + + ArraySetAsSeries(BufferHA_K, false); + ArraySetAsSeries(BufferHA_D, false); + ArraySetAsSeries(BufferRawK, false); + +//--- Set indicator display properties + IndicatorSetInteger(INDICATOR_DIGITS, 2); + PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, ExtKPeriod + ExtSlowing - 2); + PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, ExtKPeriod + ExtSlowing + ExtDPeriod - 3); + IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA_Slow_Stoch(%d,%d,%d)", ExtKPeriod, ExtDPeriod, ExtSlowing)); + } + +//+------------------------------------------------------------------+ +//| Slow Stochastic on Heiken Ashi calculation function. | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { +//--- Check if there is enough historical data + if(rates_total < ExtKPeriod + ExtSlowing + ExtDPeriod) + return(0); + +//--- STEP 1: Calculate Heiken Ashi bars + if(!g_ha_calculator.Calculate(rates_total, 0, open, high, low, close)) + return(0); + +//--- Main calculation loop, iterating from past to present + for(int i = 0; i < rates_total; i++) + { + //--- STEP 2: Calculate Raw %K using Heiken Ashi data --- + if(i >= ExtKPeriod - 1) + { + double highest_ha_high = Highest(g_ha_calculator.ha_high, ExtKPeriod, i); + double lowest_ha_low = Lowest(g_ha_calculator.ha_low, ExtKPeriod, i); + + double range = highest_ha_high - lowest_ha_low; + if(range > 0) + BufferRawK[i] = (g_ha_calculator.ha_close[i] - lowest_ha_low) / range * 100.0; + else + BufferRawK[i] = (i > 0) ? BufferRawK[i-1] : 50.0; + } + else + { + BufferRawK[i] = 0; + } + + //--- STEP 3: Calculate Slow %K (Main Line) by smoothing Raw %K --- + if(i >= ExtKPeriod + ExtSlowing - 2) + { + double sum = 0; + for(int j = 0; j < ExtSlowing; j++) + { + sum += BufferRawK[i-j]; + } + BufferHA_K[i] = sum / ExtSlowing; + } + else + { + BufferHA_K[i] = 0; + } + + //--- STEP 4: Calculate %D (Signal Line) by smoothing Slow %K --- + if(i >= ExtKPeriod + ExtSlowing + ExtDPeriod - 3) + { + double sum = 0; + for(int j = 0; j < ExtDPeriod; j++) + { + sum += BufferHA_K[i-j]; + } + BufferHA_D[i] = sum / ExtDPeriod; + } + else + { + BufferHA_D[i] = 0; + } + } +//--- Return value of prev_calculated for next call + return(rates_total); + } + +//+------------------------------------------------------------------+ +//| Finds the highest value in a given period of an array. | +//+------------------------------------------------------------------+ +double Highest(const double &array[], int period, int current_pos) + { + double res = array[current_pos]; + for(int i = 1; i < period; i++) + { + int index = current_pos - i; + if(index < 0) + break; + if(res < array[index]) + res = array[index]; + } + return(res); + } + +//+------------------------------------------------------------------+ +//| Finds the lowest value in a given period of an array. | +//+------------------------------------------------------------------+ +double Lowest(const double &array[], int period, int current_pos) + { + double res = array[current_pos]; + for(int i = 1; i < period; i++) + { + int index = current_pos - i; + if(index < 0) + break; + if(res > array[index]) + res = array[index]; + } + return(res); + } +//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/Stochastic_HeikenAshi.mq5 b/Indicators/MyIndicators/Stochastic_HeikenAshi.mq5 new file mode 100644 index 0000000..072c1cf --- /dev/null +++ b/Indicators/MyIndicators/Stochastic_HeikenAshi.mq5 @@ -0,0 +1,235 @@ +//+------------------------------------------------------------------+ +//| Stochastic_HeikenAshi.mq5 | +//| Copyright 2025, xxxxxxxx | +//| | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2025, xxxxxxxx" +#property link "" +#property version "1.10" // Added selectable MA for Signal Line +#property description "Stochastic Oscillator on Heiken Ashi data with selectable MA for %D line." + +// --- Standard and Custom Includes --- +#include +#include + +//--- Indicator Window and Level Properties --- +#property indicator_separate_window +#property indicator_buffers 5 // %K, %D, and 3 calculation buffers +#property indicator_plots 2 +#property indicator_level1 20.0 +#property indicator_level2 80.0 +#property indicator_minimum 0.0 +#property indicator_maximum 100.0 + +//--- Plot 1: %K line (Main) +#property indicator_label1 "HA_%K" +#property indicator_type1 DRAW_LINE +#property indicator_color1 clrLightSeaGreen +#property indicator_style1 STYLE_SOLID +#property indicator_width1 1 + +//--- Plot 2: %D line (Signal) +#property indicator_label2 "HA_%D" +#property indicator_type2 DRAW_LINE +#property indicator_color2 clrRed +#property indicator_style2 STYLE_DOT +#property indicator_width2 1 + +//--- Input Parameters --- +input int InpKPeriod = 5; // %K Period +input int InpSlowing = 3; // Slowing (initial %K smoothing) +input group "Signal Line Settings" +input int InpDPeriod = 3; // %D Period (signal line smoothing) +input ENUM_MA_METHOD InpMAMethod = MODE_SMA; // MA Method for %D line + +//--- Indicator Buffers --- +double BufferHA_K[]; // Plotted buffer for the main %K line +double BufferHA_D[]; // Plotted buffer for the signal %D line +double BufferRawK[]; // Calculation buffer for raw %K before slowing +double BufferHighest[]; // Calculation buffer for Highest HA_High in period +double BufferLowest[]; // Calculation buffer for Lowest HA_Low in period + +//--- Global Objects and Variables --- +int ExtKPeriod, ExtDPeriod, ExtSlowing; +CHA_Calculator g_ha_calculator; // Global instance of our Heiken Ashi calculator + +//--- Forward declarations for helper functions --- +double Highest(const double &array[], int period, int current_pos); +double Lowest(const double &array[], int period, int current_pos); + +//+------------------------------------------------------------------+ +//| Custom indicator initialization function. | +//| Called once when the indicator is first loaded. | +//+------------------------------------------------------------------+ +void OnInit() + { +//--- Validate and store input periods + ExtKPeriod = (InpKPeriod < 1) ? 1 : InpKPeriod; + ExtDPeriod = (InpDPeriod < 1) ? 1 : InpDPeriod; + ExtSlowing = (InpSlowing < 1) ? 1 : InpSlowing; + +//--- Map the buffers to the indicator's internal memory + SetIndexBuffer(0, BufferHA_K, INDICATOR_DATA); + SetIndexBuffer(1, BufferHA_D, INDICATOR_DATA); + SetIndexBuffer(2, BufferRawK, INDICATOR_CALCULATIONS); + SetIndexBuffer(3, BufferHighest, INDICATOR_CALCULATIONS); + SetIndexBuffer(4, BufferLowest, INDICATOR_CALCULATIONS); + +//--- Set all buffers to work as regular arrays (non-timeseries) + ArraySetAsSeries(BufferHA_K, false); + ArraySetAsSeries(BufferHA_D, false); + ArraySetAsSeries(BufferRawK, false); + ArraySetAsSeries(BufferHighest, false); + ArraySetAsSeries(BufferLowest, false); + +//--- Set indicator display properties + IndicatorSetInteger(INDICATOR_DIGITS, 2); + PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, ExtKPeriod + ExtSlowing - 2); + PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, ExtKPeriod + ExtSlowing + ExtDPeriod - 3); + IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA_Stoch(%d,%d,%d)", ExtKPeriod, ExtDPeriod, ExtSlowing)); + } + +//+------------------------------------------------------------------+ +//| Stochastic Oscillator on Heiken Ashi calculation function. | +//| Performs a full recalculation on every call for stability. | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { +//--- Check if there is enough historical data for all calculations + if(rates_total < ExtKPeriod + ExtSlowing + ExtDPeriod) + return(0); + +//--- STEP 1: Calculate Heiken Ashi bars using our toolkit + if(!g_ha_calculator.Calculate(rates_total, 0, open, high, low, close)) + return(0); + +//--- Main calculation loop, iterating from past to present + for(int i = 0; i < rates_total; i++) + { + //--- STEP 2 & 3: Calculate Highest, Lowest, and Raw %K --- + if(i >= ExtKPeriod - 1) + { + BufferHighest[i] = Highest(g_ha_calculator.ha_high, ExtKPeriod, i); + BufferLowest[i] = Lowest(g_ha_calculator.ha_low, ExtKPeriod, i); + + double range = BufferHighest[i] - BufferLowest[i]; + if(range > 0) + BufferRawK[i] = (g_ha_calculator.ha_close[i] - BufferLowest[i]) / range * 100.0; + else + BufferRawK[i] = (i > 0) ? BufferRawK[i-1] : 50.0; // Avoid division by zero + } + else + { + // Initialize early bars to 0 + BufferHighest[i] = 0; + BufferLowest[i] = 0; + BufferRawK[i] = 0; + } + + //--- STEP 4: Calculate Slow %K (Main Line) by smoothing Raw %K with SMA + if(i >= ExtKPeriod + ExtSlowing - 2) + { + double sum = 0; + for(int j = 0; j < ExtSlowing; j++) + sum += BufferRawK[i-j]; + BufferHA_K[i] = sum / ExtSlowing; + } + else + { + BufferHA_K[i] = 0; + } + + //--- STEP 5: Calculate %D (Signal Line) with user-selectable MA + if(i >= ExtKPeriod + ExtSlowing + ExtDPeriod - 3) + { + switch(InpMAMethod) + { + case MODE_EMA: + if(i == ExtKPeriod + ExtSlowing + ExtDPeriod - 3) // First EMA is an SMA + BufferHA_D[i] = SimpleMA(i, ExtDPeriod, BufferHA_K); + else + { + double pr = 2.0 / (ExtDPeriod + 1.0); + BufferHA_D[i] = BufferHA_K[i] * pr + BufferHA_D[i-1] * (1.0 - pr); + } + break; + case MODE_SMMA: + if(i == ExtKPeriod + ExtSlowing + ExtDPeriod - 3) // First SMMA is an SMA + BufferHA_D[i] = SimpleMA(i, ExtDPeriod, BufferHA_K); + else + BufferHA_D[i] = (BufferHA_D[i-1] * (ExtDPeriod - 1) + BufferHA_K[i]) / ExtDPeriod; + break; + case MODE_LWMA: + BufferHA_D[i] = LinearWeightedMA(i, ExtDPeriod, BufferHA_K); + break; + default: // MODE_SMA + { + double sum = 0; + for(int j = 0; j < ExtDPeriod; j++) + sum += BufferHA_K[i-j]; + BufferHA_D[i] = sum / ExtDPeriod; + } + break; + } + } + else + { + BufferHA_D[i] = 0; + } + } +//--- Return value of prev_calculated for next call + return(rates_total); + } + +//+------------------------------------------------------------------+ +//| Finds the highest value in a given period of an array. | +//| INPUT: array[] - The data array to search in. | +//| period - The number of elements to look back. | +//| current_pos - The starting position (index) to search from.| +//| RETURN: The highest value found in the specified range. | +//+------------------------------------------------------------------+ +double Highest(const double &array[], int period, int current_pos) + { + double res = array[current_pos]; + for(int i = 1; i < period; i++) + { + int index = current_pos - i; + if(index < 0) + break; + if(res < array[index]) + res = array[index]; + } + return(res); + } + +//+------------------------------------------------------------------+ +//| Finds the lowest value in a given period of an array. | +//| INPUT: array[] - The data array to search in. | +//| period - The number of elements to look back. | +//| current_pos - The starting position (index) to search from.| +//| RETURN: The lowest value found in the specified range. | +//+------------------------------------------------------------------+ +double Lowest(const double &array[], int period, int current_pos) + { + double res = array[current_pos]; + for(int i = 1; i < period; i++) + { + int index = current_pos - i; + if(index < 0) + break; + if(res > array[index]) + res = array[index]; + } + return(res); + } +//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/Supertrend_HeikenAshi.mq5 b/Indicators/MyIndicators/Supertrend_HeikenAshi.mq5 new file mode 100644 index 0000000..da939d3 --- /dev/null +++ b/Indicators/MyIndicators/Supertrend_HeikenAshi.mq5 @@ -0,0 +1,140 @@ +//+------------------------------------------------------------------+ +//| Supertrend_HeikenAshi.mq5 | +//| Copyright 2025, xxxxxxxx | +//| | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2025, xxxxxxxx" +#property link "" +#property version "1.00" +#property description "Supertrend Indicator on Heiken Ashi data" + +#include + +//--- Indicator Window and Plot Properties --- +#property indicator_chart_window +#property indicator_buffers 5 // Supertrend, Color, ATR, UpperBand, LowerBand +#property indicator_plots 1 + +//--- Plot 1: Supertrend line +#property indicator_label1 "HA_Supertrend" +#property indicator_type1 DRAW_COLOR_LINE +#property indicator_color1 clrLimeGreen, clrTomato +#property indicator_style1 STYLE_SOLID +#property indicator_width1 2 + +//--- Input Parameters --- +input int InpAtrPeriod = 10; +input double InpFactor = 3.0; + +//--- Indicator Buffers --- +double BufferSupertrend[]; +double BufferColor[]; +double BufferATR[]; +double BufferUpperBand[]; +double BufferLowerBand[]; + +//--- Global Objects and Variables --- +int ExtAtrPeriod; +double ExtFactor; +int handle_atr; +CHA_Calculator g_ha_calculator; + +//+------------------------------------------------------------------+ +//| Custom indicator initialization function. | +//+------------------------------------------------------------------+ +void OnInit() + { + ExtAtrPeriod = (InpAtrPeriod < 1) ? 1 : InpAtrPeriod; + ExtFactor = (InpFactor <= 0) ? 3.0 : InpFactor; + + SetIndexBuffer(0, BufferSupertrend, INDICATOR_DATA); + SetIndexBuffer(1, BufferColor, INDICATOR_COLOR_INDEX); + SetIndexBuffer(2, BufferATR, INDICATOR_CALCULATIONS); + SetIndexBuffer(3, BufferUpperBand, INDICATOR_CALCULATIONS); + SetIndexBuffer(4, BufferLowerBand, INDICATOR_CALCULATIONS); + + ArraySetAsSeries(BufferSupertrend, false); + ArraySetAsSeries(BufferColor, false); + ArraySetAsSeries(BufferATR, false); + ArraySetAsSeries(BufferUpperBand, false); + ArraySetAsSeries(BufferLowerBand, false); + +// ATR is calculated on standard candles, as it measures true volatility + handle_atr = iATR(_Symbol, _Period, ExtAtrPeriod); + if(handle_atr == INVALID_HANDLE) + Print("Error creating iATR handle."); + + IndicatorSetInteger(INDICATOR_DIGITS, _Digits); + PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, ExtAtrPeriod); + IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA_Supertrend(%d, %.1f)", ExtAtrPeriod, ExtFactor)); + } + +//+------------------------------------------------------------------+ +//| Supertrend on Heiken Ashi calculation function. | +//+------------------------------------------------------------------+ +int OnCalculate(const int rates_total, + const int prev_calculated, + const datetime &time[], + const double &open[], + const double &high[], + const double &low[], + const double &close[], + const long &tick_volume[], + const long &volume[], + const int &spread[]) + { + if(rates_total < ExtAtrPeriod) + return(0); + +//--- STEP 1: Calculate Heiken Ashi bars + if(!g_ha_calculator.Calculate(rates_total, 0, open, high, low, close)) + return(0); + +//--- STEP 2: Get ATR values + if(BarsCalculated(handle_atr) < rates_total) + return(0); + if(CopyBuffer(handle_atr, 0, 0, rates_total, BufferATR) <= 0) + return(0); + +//--- STEP 3: Main calculation loop + for(int i = 1; i < rates_total; i++) + { + double ha_hl2 = (g_ha_calculator.ha_high[i] + g_ha_calculator.ha_low[i]) / 2.0; + + double upper_basic = ha_hl2 + (ExtFactor * BufferATR[i]); + double lower_basic = ha_hl2 - (ExtFactor * BufferATR[i]); + + // Stair-step logic + if(upper_basic < BufferUpperBand[i-1] || g_ha_calculator.ha_close[i-1] > BufferUpperBand[i-1]) + BufferUpperBand[i] = upper_basic; + else + BufferUpperBand[i] = BufferUpperBand[i-1]; + + if(lower_basic > BufferLowerBand[i-1] || g_ha_calculator.ha_close[i-1] < BufferLowerBand[i-1]) + BufferLowerBand[i] = lower_basic; + else + BufferLowerBand[i] = BufferLowerBand[i-1]; + + // Trend direction + int trend = 0; + if(BufferSupertrend[i-1] == BufferUpperBand[i-1]) + trend = (g_ha_calculator.ha_close[i] > BufferUpperBand[i]) ? 1 : -1; + else + trend = (g_ha_calculator.ha_close[i] < BufferLowerBand[i]) ? -1 : 1; + + if(trend == 1) // Uptrend + { + BufferSupertrend[i] = BufferLowerBand[i]; + BufferColor[i] = 0; // Green + } + else // Downtrend + { + BufferSupertrend[i] = BufferUpperBand[i]; + BufferColor[i] = 1; // Red + } + } + + return(rates_total); + } +//+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/WPRMA_HeikenAshi.mq5 b/Indicators/MyIndicators/WPRMA_HeikenAshi.mq5 new file mode 100644 index 0000000..bcc3a36 Binary files /dev/null and b/Indicators/MyIndicators/WPRMA_HeikenAshi.mq5 differ diff --git a/Indicators/MyIndicators/WPR_HeikenAshi.mq5 b/Indicators/MyIndicators/WPR_HeikenAshi.mq5 new file mode 100644 index 0000000..56b46ac Binary files /dev/null and b/Indicators/MyIndicators/WPR_HeikenAshi.mq5 differ