From 752f1f436298506a04f7a23968b485e71a0a4af6 Mon Sep 17 00:00:00 2001 From: Toh4iem9 Date: Thu, 2 Oct 2025 00:28:57 +0200 Subject: [PATCH] chore: remove old indicators --- Indicators/MyIndicators/AD.md | 58 ---- Indicators/MyIndicators/AD.mq5 | 79 ----- Indicators/MyIndicators/ADX.md | 91 ----- Indicators/MyIndicators/ADX.mq5 | 179 ---------- Indicators/MyIndicators/ADX_HeikinAshi.mq5 | 232 ------------- Indicators/MyIndicators/AD_HeikinAshi.mq5 | 113 ------ Indicators/MyIndicators/ALMA.md | 67 ---- Indicators/MyIndicators/ALMA.mq5 | 134 ------- Indicators/MyIndicators/ALMA_HeikinAshi.mq5 | 172 --------- Indicators/MyIndicators/AMA.md | 64 ---- Indicators/MyIndicators/AMA.mq5 | 139 -------- Indicators/MyIndicators/AMA_HeikinAshi.mq5 | 166 --------- Indicators/MyIndicators/AMA_TrendActivity.md | 66 ---- Indicators/MyIndicators/AMA_TrendActivity.mq5 | 190 ---------- .../AMA_TrendActivity_HeikinAshi.mq5 | 224 ------------ Indicators/MyIndicators/ATR.md | 64 ---- Indicators/MyIndicators/ATR.mq5 | 99 ------ Indicators/MyIndicators/ATR_HeikinAshi.mq5 | 131 ------- Indicators/MyIndicators/CCI.md | 77 ----- Indicators/MyIndicators/CCI.mq5 | 210 ----------- Indicators/MyIndicators/CCI_HeikinAshi.mq5 | 256 -------------- Indicators/MyIndicators/CCI_Oscillator.mq5 | 192 ---------- .../CCI_Oscillator_HeikinAshi.mq5 | 237 ------------- Indicators/MyIndicators/CCI_Precise.mq5 | 200 ----------- .../MyIndicators/CCI_Precise_HeikinAshi.mq5 | 229 ------------ .../MyIndicators/CCI_Precise_Oscillator.mq5 | 172 --------- .../CCI_Precise_Oscillator_HeikinAshi.mq5 | 216 ------------ Indicators/MyIndicators/CHO.md | 65 ---- Indicators/MyIndicators/CHO.mq5 | 210 ----------- Indicators/MyIndicators/CHO_HeikinAshi.mq5 | 241 ------------- Indicators/MyIndicators/CutlerRSI_MA.md | 74 ---- Indicators/MyIndicators/CutlerRSI_MA.mq5 | 220 ------------ .../MyIndicators/CutlerRSI_MA_HeikinAshi.mq5 | 213 ------------ .../MyIndicators/CutlerRSI_Oscillator.mq5 | 185 ---------- .../CutlerRSI_Oscillator_HeikinAshi.mq5 | 191 ---------- Indicators/MyIndicators/Fibonacci_WMA.md | 65 ---- Indicators/MyIndicators/Fibonacci_WMA.mq5 | 76 ---- .../MyIndicators/Fibonacci_WMA_HeikinAshi.mq5 | 76 ---- Indicators/MyIndicators/FisherTransform.md | 66 ---- Indicators/MyIndicators/FisherTransform.mq5 | 181 ---------- .../FisherTransform_HeikinAshi.mq5 | 226 ------------ Indicators/MyIndicators/Gann_HiLo.md | 66 ---- Indicators/MyIndicators/Gann_HiLo.mq5 | 189 ---------- .../MyIndicators/Gann_HiLo_HeikinAshi.mq5 | 190 ---------- Indicators/MyIndicators/HMA.md | 60 ---- Indicators/MyIndicators/HMA.mq5 | 163 --------- Indicators/MyIndicators/HMA_HeikinAshi.mq5 | 169 --------- Indicators/MyIndicators/Holt_Channel.mq5 | 125 ------- .../MyIndicators/Holt_Channel_HeikinAshi.mq5 | 107 ------ Indicators/MyIndicators/Holt_MA.mq5 | 85 ----- .../MyIndicators/Holt_MA_HeikinAshi.mq5 | 75 ---- Indicators/MyIndicators/Holt_Oscillator.mq5 | 89 ----- .../Holt_Oscillator_HeikinAshi.mq5 | 79 ----- Indicators/MyIndicators/KeltnerChannel.md | 72 ---- Indicators/MyIndicators/KeltnerChannel.mq5 | 158 --------- .../KeltnerChannel_HeikinAshi.mq5 | 255 -------------- .../KeltnerChannel_HeikinAshi_Pure.mq5 | 230 ------------ .../MyIndicators/LinearRegressionChannel.md | 47 --- .../MyIndicators/LinearRegressionChannel.mq5 | 124 ------- .../LinearRegression_Pro_HeikinAshi.mq5 | 246 ------------- .../LinearRegression_Pro_Sample.mq5 | 215 ------------ Indicators/MyIndicators/MACD.md | 82 ----- Indicators/MyIndicators/MACD.mq5 | 197 ----------- Indicators/MyIndicators/MACD_HeikinAshi.mq5 | 229 ------------ .../MyIndicators/MACD_Pro_HeikinAshi.mq5 | 327 ------------------ Indicators/MyIndicators/MAMA_FAMA.md | 69 ---- Indicators/MyIndicators/MAMA_FAMA.mq5 | 96 ----- .../MyIndicators/MAMA_FAMA_HeikinAshi.mq5 | 95 ----- Indicators/MyIndicators/MFI.md | 71 ---- Indicators/MyIndicators/MFI.mq5 | 198 ----------- Indicators/MyIndicators/MFI_HeikinAshi.mq5 | 230 ------------ Indicators/MyIndicators/McGinleyDynamic.md | 62 ---- Indicators/MyIndicators/McGinleyDynamic.mq5 | 142 -------- .../McGinleyDynamic_HeikinAshi.mq5 | 170 --------- Indicators/MyIndicators/Pascal_WMA.md | 62 ---- Indicators/MyIndicators/Pascal_WMA.mq5 | 199 ----------- Indicators/MyIndicators/RSIMa.md | 63 ---- Indicators/MyIndicators/RSIMa.mq5 | 177 ---------- Indicators/MyIndicators/RSI_HeikinAshi.mq5 | 171 --------- .../RSI_Oscillator_HeikinAshi.mq5 | 162 --------- Indicators/MyIndicators/SMI.md | 71 ---- Indicators/MyIndicators/SMI.mq5 | 226 ------------ Indicators/MyIndicators/SMI_HeikinAshi.mq5 | 268 -------------- Indicators/MyIndicators/Sine_WMA.md | 65 ---- Indicators/MyIndicators/Sine_WMA.mq5 | 185 ---------- .../MyIndicators/Sine_WMA_HeikinAshi.mq5 | 75 ---- 86 files changed, 12582 deletions(-) delete mode 100644 Indicators/MyIndicators/AD.md delete mode 100644 Indicators/MyIndicators/AD.mq5 delete mode 100644 Indicators/MyIndicators/ADX.md delete mode 100644 Indicators/MyIndicators/ADX.mq5 delete mode 100644 Indicators/MyIndicators/ADX_HeikinAshi.mq5 delete mode 100644 Indicators/MyIndicators/AD_HeikinAshi.mq5 delete mode 100644 Indicators/MyIndicators/ALMA.md delete mode 100644 Indicators/MyIndicators/ALMA.mq5 delete mode 100644 Indicators/MyIndicators/ALMA_HeikinAshi.mq5 delete mode 100644 Indicators/MyIndicators/AMA.md delete mode 100644 Indicators/MyIndicators/AMA.mq5 delete mode 100644 Indicators/MyIndicators/AMA_HeikinAshi.mq5 delete mode 100644 Indicators/MyIndicators/AMA_TrendActivity.md delete mode 100644 Indicators/MyIndicators/AMA_TrendActivity.mq5 delete mode 100644 Indicators/MyIndicators/AMA_TrendActivity_HeikinAshi.mq5 delete mode 100644 Indicators/MyIndicators/ATR.md delete mode 100644 Indicators/MyIndicators/ATR.mq5 delete mode 100644 Indicators/MyIndicators/ATR_HeikinAshi.mq5 delete mode 100644 Indicators/MyIndicators/CCI.md delete mode 100644 Indicators/MyIndicators/CCI.mq5 delete mode 100644 Indicators/MyIndicators/CCI_HeikinAshi.mq5 delete mode 100644 Indicators/MyIndicators/CCI_Oscillator.mq5 delete mode 100644 Indicators/MyIndicators/CCI_Oscillator_HeikinAshi.mq5 delete mode 100644 Indicators/MyIndicators/CCI_Precise.mq5 delete mode 100644 Indicators/MyIndicators/CCI_Precise_HeikinAshi.mq5 delete mode 100644 Indicators/MyIndicators/CCI_Precise_Oscillator.mq5 delete mode 100644 Indicators/MyIndicators/CCI_Precise_Oscillator_HeikinAshi.mq5 delete mode 100644 Indicators/MyIndicators/CHO.md delete mode 100644 Indicators/MyIndicators/CHO.mq5 delete mode 100644 Indicators/MyIndicators/CHO_HeikinAshi.mq5 delete mode 100644 Indicators/MyIndicators/CutlerRSI_MA.md delete mode 100644 Indicators/MyIndicators/CutlerRSI_MA.mq5 delete mode 100644 Indicators/MyIndicators/CutlerRSI_MA_HeikinAshi.mq5 delete mode 100644 Indicators/MyIndicators/CutlerRSI_Oscillator.mq5 delete mode 100644 Indicators/MyIndicators/CutlerRSI_Oscillator_HeikinAshi.mq5 delete mode 100644 Indicators/MyIndicators/Fibonacci_WMA.md delete mode 100644 Indicators/MyIndicators/Fibonacci_WMA.mq5 delete mode 100644 Indicators/MyIndicators/Fibonacci_WMA_HeikinAshi.mq5 delete mode 100644 Indicators/MyIndicators/FisherTransform.md delete mode 100644 Indicators/MyIndicators/FisherTransform.mq5 delete mode 100644 Indicators/MyIndicators/FisherTransform_HeikinAshi.mq5 delete mode 100644 Indicators/MyIndicators/Gann_HiLo.md delete mode 100644 Indicators/MyIndicators/Gann_HiLo.mq5 delete mode 100644 Indicators/MyIndicators/Gann_HiLo_HeikinAshi.mq5 delete mode 100644 Indicators/MyIndicators/HMA.md delete mode 100644 Indicators/MyIndicators/HMA.mq5 delete mode 100644 Indicators/MyIndicators/HMA_HeikinAshi.mq5 delete mode 100644 Indicators/MyIndicators/Holt_Channel.mq5 delete mode 100644 Indicators/MyIndicators/Holt_Channel_HeikinAshi.mq5 delete mode 100644 Indicators/MyIndicators/Holt_MA.mq5 delete mode 100644 Indicators/MyIndicators/Holt_MA_HeikinAshi.mq5 delete mode 100644 Indicators/MyIndicators/Holt_Oscillator.mq5 delete mode 100644 Indicators/MyIndicators/Holt_Oscillator_HeikinAshi.mq5 delete mode 100644 Indicators/MyIndicators/KeltnerChannel.md delete mode 100644 Indicators/MyIndicators/KeltnerChannel.mq5 delete mode 100644 Indicators/MyIndicators/KeltnerChannel_HeikinAshi.mq5 delete mode 100644 Indicators/MyIndicators/KeltnerChannel_HeikinAshi_Pure.mq5 delete mode 100644 Indicators/MyIndicators/LinearRegressionChannel.md delete mode 100644 Indicators/MyIndicators/LinearRegressionChannel.mq5 delete mode 100644 Indicators/MyIndicators/LinearRegression_Pro_HeikinAshi.mq5 delete mode 100644 Indicators/MyIndicators/LinearRegression_Pro_Sample.mq5 delete mode 100644 Indicators/MyIndicators/MACD.md delete mode 100644 Indicators/MyIndicators/MACD.mq5 delete mode 100644 Indicators/MyIndicators/MACD_HeikinAshi.mq5 delete mode 100644 Indicators/MyIndicators/MACD_Pro_HeikinAshi.mq5 delete mode 100644 Indicators/MyIndicators/MAMA_FAMA.md delete mode 100644 Indicators/MyIndicators/MAMA_FAMA.mq5 delete mode 100644 Indicators/MyIndicators/MAMA_FAMA_HeikinAshi.mq5 delete mode 100644 Indicators/MyIndicators/MFI.md delete mode 100644 Indicators/MyIndicators/MFI.mq5 delete mode 100644 Indicators/MyIndicators/MFI_HeikinAshi.mq5 delete mode 100644 Indicators/MyIndicators/McGinleyDynamic.md delete mode 100644 Indicators/MyIndicators/McGinleyDynamic.mq5 delete mode 100644 Indicators/MyIndicators/McGinleyDynamic_HeikinAshi.mq5 delete mode 100644 Indicators/MyIndicators/Pascal_WMA.md delete mode 100644 Indicators/MyIndicators/Pascal_WMA.mq5 delete mode 100644 Indicators/MyIndicators/RSIMa.md delete mode 100644 Indicators/MyIndicators/RSIMa.mq5 delete mode 100644 Indicators/MyIndicators/RSI_HeikinAshi.mq5 delete mode 100644 Indicators/MyIndicators/RSI_Oscillator_HeikinAshi.mq5 delete mode 100644 Indicators/MyIndicators/SMI.md delete mode 100644 Indicators/MyIndicators/SMI.mq5 delete mode 100644 Indicators/MyIndicators/SMI_HeikinAshi.mq5 delete mode 100644 Indicators/MyIndicators/Sine_WMA.md delete mode 100644 Indicators/MyIndicators/Sine_WMA.mq5 delete mode 100644 Indicators/MyIndicators/Sine_WMA_HeikinAshi.mq5 diff --git a/Indicators/MyIndicators/AD.md b/Indicators/MyIndicators/AD.md deleted file mode 100644 index b9e7e8d..0000000 --- a/Indicators/MyIndicators/AD.md +++ /dev/null @@ -1,58 +0,0 @@ -# Accumulation/Distribution Line (ADL) - -## 1. Summary (Introduction) - -The Accumulation/Distribution Line (A/D Line or ADL) is a volume-based indicator developed by Marc Chaikin. It was designed to measure the cumulative flow of money into and out of a security. The ADL attempts to identify whether traders are primarily "accumulating" (buying) or "distributing" (selling) an asset by analyzing the relationship between the closing price and its trading range, weighted by volume. - -It is a cumulative, running total. A rising ADL suggests that buying pressure is dominant, while a falling ADL suggests that selling pressure is dominant. It is primarily used to confirm the strength of a trend or to spot divergences that may signal a potential reversal. - -## 2. Mathematical Foundations and Calculation Logic - -The ADL is calculated by first determining the "Money Flow Multiplier" for each period and then using it to weight the volume. - -### Required Components - -- **Price Data:** The `High`, `Low`, and `Close` of each bar. -- **Volume Data:** The volume for each bar. - -### Calculation Steps (Algorithm) - -1. **Calculate the Money Flow Multiplier (MFM):** This value determines the proportion of the volume that was bullish or bearish. It ranges from +1 (if Close = High) to -1 (if Close = Low). - $\text{MFM} = \frac{(\text{Close} - \text{Low}) - (\text{High} - \text{Close})}{\text{High} - \text{Low}}$ - _(Note: If High equals Low, the MFM is 0)._ - -2. **Calculate the Money Flow Volume (MFV):** Multiply the MFM by the volume for the period. - $\text{MFV}_i = \text{MFM}_i \times \text{Volume}_i$ - -3. **Calculate the Accumulation/Distribution Line (ADL):** The ADL is the cumulative sum of the Money Flow Volume. - $\text{ADL}_i = \text{ADL}_{i-1} + \text{MFV}_i$ - -## 3. MQL5 Implementation Details - -Our MQL5 implementation is a self-contained, robust, and accurate representation of the classic A/D Line. - -- **Stability via Full Recalculation:** We employ a "brute-force" full recalculation within the `OnCalculate` function. For a cumulative, recursive indicator like the ADL, this is the most reliable method to ensure stability and prevent calculation errors. - -- **Self-Contained Logic:** The indicator is completely self-contained. It does not use any external indicator handles. All calculations are performed manually within a single, efficient `for` loop in the `OnCalculate` function. - -- **Correct Algorithm:** The implementation strictly follows the correct, textbook definition of the ADL, ensuring its results are consistent with other professional charting platforms. The logic correctly handles the selection of Tick or Real volume based on user input. - -- **Heikin Ashi Variant (`AD_HeikinAshi.mq5`):** - - Our toolkit also includes a "pure" Heikin Ashi version of this indicator. The calculation logic is identical, but it uses the smoothed Heikin Ashi `ha_high`, `ha_low`, and `ha_close` values to calculate the Money Flow Multiplier. The volume component remains the standard volume from the underlying chart. - - This results in a smoother ADL that reflects the buying and selling pressure of the underlying Heikin Ashi trend, effectively filtering out some of the noise from standard price action. - -## 4. Parameters - -- **Volume Type (`InpVolumeType`):** Allows the user to select between Tick Volume (`VOLUME_TICK`) and Real Volume (`VOLUME_REAL`) for the calculation. - -## 5. Usage and Interpretation - -The absolute value of the ADL is not important; its **slope and direction** are what matter. - -- **Trend Confirmation:** - - If both the price and the ADL are making higher highs and higher lows, the uptrend is considered strong and likely to continue. - - If both the price and the ADL are making lower highs and lower lows, the downtrend is considered strong. -- **Divergence:** This is the most powerful signal from the ADL. - - **Bullish Divergence:** The price continues to fall and makes a new low, but the ADL fails to make a new low and starts to rise. This suggests that accumulation (buying) is taking place despite the lower prices, which can foreshadow a bullish reversal. - - **Bearish Divergence:** The price continues to rise and makes a new high, but the ADL fails to make a new high and starts to fall. This suggests that distribution (selling) is occurring on the rally, which can be an early warning of a bearish reversal. -- **Caution:** The ADL does not account for price gaps between periods. A significant gap down will not be reflected in the ADL's calculation, which can sometimes lead to a discrepancy between price and the indicator. It is best used for confirmation alongside other price-based indicators. diff --git a/Indicators/MyIndicators/AD.mq5 b/Indicators/MyIndicators/AD.mq5 deleted file mode 100644 index 06cd9e8..0000000 --- a/Indicators/MyIndicators/AD.mq5 +++ /dev/null @@ -1,79 +0,0 @@ -//+------------------------------------------------------------------+ -//| AD.mq5 | -//| Copyright 2025, xxxxxxxx | -//| | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property link "" -#property version "1.01" // Corrected volume source handling -#property description "Accumulation/Distribution Line" - -//--- Indicator Window and Plot Properties --- -#property indicator_separate_window -#property indicator_buffers 1 -#property indicator_plots 1 -#property indicator_type1 DRAW_LINE -#property indicator_color1 clrLightSeaGreen -#property indicator_label1 "A/D" - -//--- Input Parameters --- -input ENUM_APPLIED_VOLUME InpVolumeType = VOLUME_TICK; // Volume type - -//--- Indicator Buffers --- -double BufferAD[]; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -void OnInit() - { - SetIndexBuffer(0, BufferAD, INDICATOR_DATA); - ArraySetAsSeries(BufferAD, false); - - IndicatorSetInteger(INDICATOR_DIGITS, 0); - IndicatorSetString(INDICATOR_SHORTNAME, "A/D"); - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, 1); - } - -//+------------------------------------------------------------------+ -//| Accumulation/Distribution 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 < 2) - return(0); - -//--- Main calculation loop - for(int i = 0; i < rates_total; i++) - { - double mfm = 0; // Money Flow Multiplier - double range = high[i] - low[i]; - - if(range > 0) - { - mfm = ((close[i] - low[i]) - (high[i] - close[i])) / range; - } - - // --- FIX: Use ternary operator to select volume source --- - long current_volume = (InpVolumeType == VOLUME_TICK) ? tick_volume[i] : volume[i]; - double mfv = mfm * current_volume; // Money Flow Volume - - if(i > 0) - BufferAD[i] = BufferAD[i-1] + mfv; - else - BufferAD[i] = mfv; // First value - } - - return(rates_total); - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/ADX.md b/Indicators/MyIndicators/ADX.md deleted file mode 100644 index cdcbb4f..0000000 --- a/Indicators/MyIndicators/ADX.md +++ /dev/null @@ -1,91 +0,0 @@ -# Average Directional Index (ADX) - -## 1. Summary (Introduction) - -The Average Directional Index (ADX), developed by J. Welles Wilder, is a widely used technical indicator designed to measure the **strength of a trend**, regardless of its direction. It does not indicate whether the trend is bullish or bearish, but only quantifies its momentum. - -The ADX system consists of three lines: - -- **ADX Line:** The main line that indicates trend strength. -- **+DI (Positive Directional Indicator):** A line that measures the strength of the upward price movement. -- **-DI (Negative Directional Indicator):** A line that measures the strength of the downward price movement. - -It is a powerful tool for traders to distinguish between trending and non-trending (ranging) market conditions. - -## 2. Mathematical Foundations and Calculation Logic - -The ADX calculation is a complex, multi-stage process that relies heavily on Wilder's smoothing technique (a specific type of Smoothed or Running Moving Average - SMMA/RMA). - -### Required Components - -- **ADX Period (N):** The lookback period for all calculations (e.g., 14). -- **Directional Movement (+DM, -DM):** Measures the portion of the current bar's range that is outside the previous bar's range. -- **True Range (TR):** The standard measure of a single bar's volatility. - -### Calculation Steps (Algorithm) - -1. **Calculate Directional Movement and True Range:** For each period, calculate: - - - $\text{Up Move} = \text{High}_i - \text{High}_{i-1}$ - - $\text{Down Move} = \text{Low}_{i-1} - \text{Low}_i$ - - If $\text{Up Move} > \text{Down Move}$ and $\text{Up Move} > 0$, then $\text{+DM} = \text{Up Move}$, else $\text{+DM} = 0$. - - If $\text{Down Move} > \text{Up Move}$ and $\text{Down Move} > 0$, then $\text{-DM} = \text{Down Move}$, else $\text{-DM} = 0$. - - $\text{True Range (TR)} = \text{Max}[(\text{High}_i - \text{Low}_i), \text{Abs}(\text{High}_i - \text{Close}_{i-1}), \text{Abs}(\text{Low}_i - \text{Close}_{i-1})]$ - -2. **Smooth +DM, -DM, and TR:** Apply Wilder's smoothing method over the period `N`. - - - **Initialization:** The first value is the sum of the first `N` periods. - $\text{Smoothed +DM}_{N} = \sum_{i=1}^{N} \text{+DM}_i$ - - **Recursive Calculation:** - $\text{Smoothed +DM}_i = \text{Smoothed +DM}_{i-1} - \frac{\text{Smoothed +DM}_{i-1}}{N} + \text{+DM}_i$ - - _(The same logic applies to -DM and TR)_ - -3. **Calculate Directional Indicators (+DI, -DI):** - $\text{+DI}_i = 100 \times \frac{\text{Smoothed +DM}_i}{\text{Smoothed TR}_i}$ - $\text{-DI}_i = 100 \times \frac{\text{Smoothed -DM}_i}{\text{Smoothed TR}_i}$ - -4. **Calculate the Directional Index (DX):** - $\text{DX}_i = 100 \times \frac{\text{Abs}(\text{+DI}_i - \text{-DI}_i)}{\text{+DI}_i + \text{-DI}_i}$ - -5. **Calculate the Final ADX:** The ADX is a Wilder-smoothed moving average of the DX. - - **Initialization:** The first ADX value is a simple average of the first `N` DX values. - - **Recursive Calculation:** - $\text{ADX}_i = \frac{(\text{ADX}_{i-1} \times (N-1)) + \text{DX}_i}{N}$ - -## 3. MQL5 Implementation Details - -Our MQL5 implementation was refactored to be highly robust, clear, and consistent with our established "Wilder Algorithm". - -- **Stability via Full Recalculation:** We employ a "brute-force" full recalculation within the `OnCalculate` function. For a complex, multi-stage indicator like the ADX, this is the most reliable method to prevent calculation errors. - -- **Consensus Wilder Algorithm:** The implementation strictly follows our established two-step algorithm for Wilder's smoothing: - - 1. **Robust Initialization:** The first smoothed value is calculated non-recursively (as a simple sum for `+DM`, `-DM`, `TR`, and as a simple average for `ADX`). - 2. **Efficient Recursive Calculation:** All subsequent values are calculated using the efficient formula: `Previous Value - (Previous Value / N) + Current Value`. - -- **Clear, Staged Calculation:** The `OnCalculate` function is structured into clear, sequential steps, each handled by a dedicated `for` loop. This improves code readability and makes the complex logic easy to follow: - - 1. **Step 1:** Raw `+DM`, `-DM`, and `TR` values are calculated and stored in temporary arrays. - 2. **Step 2:** The raw values are smoothed using our Wilder algorithm. - 3. **Step 3:** The `+DI`, `-DI`, and `DX` values are calculated from the smoothed data. - 4. **Step 4:** The final `ADX` line is calculated by applying the Wilder algorithm to the `DX` values. - -- **Heikin Ashi Variant (`ADX_HeikinAshi.mq5`):** - - Our toolkit also includes a Heikin Ashi version of this indicator. The calculation logic is identical, but it uses the smoothed Heikin Ashi `ha_high`, `ha_low`, and `ha_close` values as its input. - - This results in a smoother ADX system that reflects the momentum of the underlying Heikin Ashi trend, effectively filtering out some of the market noise that can cause the +DI and -DI lines to cross frequently. - -## 4. Parameters - -- **ADX Period (`InpPeriodADX`):** The lookback period used for all internal calculations (+DM, -DM, TR, and the final ADX smoothing). Wilder's original recommendation and the most common value is `14`. - -## 5. Usage and Interpretation - -- **Trend Strength:** The primary signal is the ADX line itself. - - **ADX < 25:** Weak or non-existent trend (ranging market). Trend-following strategies should be avoided. - - **ADX > 25:** Strong trend. The higher the ADX, the stronger the trend. - - **Rising ADX:** The trend is gaining strength. - - **Falling ADX:** The trend is losing strength. -- **Trend Direction (+DI and -DI Crossover):** - - When the **+DI line (green) crosses above the -DI line (red)**, it suggests the start of a bullish trend. - - When the **-DI line (red) crosses above the +DI line (green)**, it suggests the start of a bearish trend. -- **Trade Confirmation:** A common strategy is to wait for a +DI/-DI crossover and then confirm that the ADX line is above 25 (or rising) before entering a trade. This helps to filter out signals that occur in weak or non-trending markets. diff --git a/Indicators/MyIndicators/ADX.mq5 b/Indicators/MyIndicators/ADX.mq5 deleted file mode 100644 index 7615ec3..0000000 --- a/Indicators/MyIndicators/ADX.mq5 +++ /dev/null @@ -1,179 +0,0 @@ -//+------------------------------------------------------------------+ -//| 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/ADX_HeikinAshi.mq5 b/Indicators/MyIndicators/ADX_HeikinAshi.mq5 deleted file mode 100644 index 9adfaa0..0000000 --- a/Indicators/MyIndicators/ADX_HeikinAshi.mq5 +++ /dev/null @@ -1,232 +0,0 @@ -//+------------------------------------------------------------------+ -//| ADX_HeikinAshi.mq5 | -//| Copyright 2025, xxxxxxxx (Based on MetaQuotes ADXW) | -//| | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property link "" -#property version "4.00" // Refactored for full recalculation and stability -#property description "ADX by Welles Wilder on Heikin Ashi data." - -// --- Standard and Custom Includes --- -#include - -//--- 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 "HA_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 "HA_+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 "HA_-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 BufferHA_ADX[]; -double BufferHA_PDI[]; -double BufferHA_NDI[]; -double BufferSmoothed_PDM[]; -double BufferSmoothed_NDM[]; -double BufferSmoothed_TR[]; -double BufferDX[]; - -//--- Intermediate Heikin Ashi Buffers --- -double ExtHaOpenBuffer[]; -double ExtHaHighBuffer[]; -double ExtHaLowBuffer[]; -double ExtHaCloseBuffer[]; - -//--- Global Objects and Variables --- -int g_ExtADXPeriod; -CHeikinAshi_Calculator *g_ha_calculator; // Pointer to our Heikin Ashi calculator - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { -//--- Validate and store the ADX period - g_ExtADXPeriod = (InpPeriodADX < 1) ? 1 : InpPeriodADX; - -//--- Map the buffers - SetIndexBuffer(0, BufferHA_ADX, INDICATOR_DATA); - SetIndexBuffer(1, BufferHA_PDI, INDICATOR_DATA); - SetIndexBuffer(2, BufferHA_NDI, 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); - -//--- Set all buffers as non-timeseries for stable calculation - ArraySetAsSeries(BufferHA_ADX, false); - ArraySetAsSeries(BufferHA_PDI, false); - ArraySetAsSeries(BufferHA_NDI, false); - ArraySetAsSeries(BufferSmoothed_PDM, false); - ArraySetAsSeries(BufferSmoothed_NDM, false); - ArraySetAsSeries(BufferSmoothed_TR, false); - ArraySetAsSeries(BufferDX, false); - -//--- Set indicator properties - 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("HA_ADXW(%d)", g_ExtADXPeriod)); - -//--- Create the calculator instance - g_ha_calculator = new CHeikinAshi_Calculator(); - if(CheckPointer(g_ha_calculator) == POINTER_INVALID) - { - Print("Error creating CHeikinAshi_Calculator object"); - return(INIT_FAILED); - } - - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { -//--- Free the calculator object to prevent memory leaks - if(CheckPointer(g_ha_calculator) != POINTER_INVALID) - { - delete g_ha_calculator; - g_ha_calculator = NULL; - } - } - -//+------------------------------------------------------------------+ -//| 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[]) - { -//--- Check if there is enough historical data for the calculation - if(rates_total < g_ExtADXPeriod + 1) - return(0); - -//--- Resize intermediate buffers to match the available bars - ArrayResize(ExtHaOpenBuffer, rates_total); - ArrayResize(ExtHaHighBuffer, rates_total); - ArrayResize(ExtHaLowBuffer, rates_total); - ArrayResize(ExtHaCloseBuffer, rates_total); - -//--- STEP 1: Calculate Heikin Ashi bars using our toolkit - g_ha_calculator.Calculate(rates_total, open, high, low, close, - ExtHaOpenBuffer, ExtHaHighBuffer, ExtHaLowBuffer, ExtHaCloseBuffer); - -//--- STEP 2: Calculate raw +DM, -DM, and TR - double pDM[], nDM[], TR[]; - ArrayResize(pDM, rates_total); - ArrayResize(nDM, rates_total); - ArrayResize(TR, rates_total); - - for(int i = 1; i < rates_total; i++) - { - double ha_high = ExtHaHighBuffer[i]; - double prev_ha_high = ExtHaHighBuffer[i-1]; - double ha_low = ExtHaLowBuffer[i]; - double prev_ha_low = ExtHaLowBuffer[i-1]; - double prev_ha_close = ExtHaCloseBuffer[i-1]; - - pDM[i] = ha_high - prev_ha_high; - nDM[i] = prev_ha_low - ha_low; - - 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(ha_high, prev_ha_close) - MathMin(ha_low, prev_ha_close); - } - -//--- STEP 3: 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 4: Calculate +DI, -DI, and DX - for(int i = g_ExtADXPeriod; i < rates_total; i++) - { - if(BufferSmoothed_TR[i] != 0.0) - { - BufferHA_PDI[i] = (BufferSmoothed_PDM[i] / BufferSmoothed_TR[i]) * 100.0; - BufferHA_NDI[i] = (BufferSmoothed_NDM[i] / BufferSmoothed_TR[i]) * 100.0; - } - - double di_sum = BufferHA_PDI[i] + BufferHA_NDI[i]; - if(di_sum != 0.0) - BufferDX[i] = MathAbs(BufferHA_PDI[i] - BufferHA_NDI[i]) / di_sum * 100.0; - else - BufferDX[i] = 0.0; - } - -//--- STEP 5: 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]; - BufferHA_ADX[i] = sum_dx / g_ExtADXPeriod; - } - else // Subsequent ADX values are smoothed - { - BufferHA_ADX[i] = (BufferHA_ADX[i-1] * (g_ExtADXPeriod - 1) + BufferDX[i]) / g_ExtADXPeriod; - } - } - -//--- Return value of rates_total to signal a full recalculation - return(rates_total); - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/AD_HeikinAshi.mq5 b/Indicators/MyIndicators/AD_HeikinAshi.mq5 deleted file mode 100644 index 4d7e243..0000000 --- a/Indicators/MyIndicators/AD_HeikinAshi.mq5 +++ /dev/null @@ -1,113 +0,0 @@ -//+------------------------------------------------------------------+ -//| AD_HeikinAshi.mq5 | -//| Copyright 2025, xxxxxxxx | -//| | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property link "" -#property version "1.00" -#property description "Accumulation/Distribution Line on Heikin Ashi data" - -#include - -//--- Indicator Window and Plot Properties --- -#property indicator_separate_window -#property indicator_buffers 1 -#property indicator_plots 1 -#property indicator_type1 DRAW_LINE -#property indicator_color1 clrLightSeaGreen -#property indicator_label1 "HA_A/D" - -//--- Input Parameters --- -input ENUM_APPLIED_VOLUME InpVolumeType = VOLUME_TICK; // Volume type - -//--- Indicator Buffers --- -double BufferAD[]; - -//--- Global Objects and Variables --- -CHeikinAshi_Calculator *g_ha_calculator; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - SetIndexBuffer(0, BufferAD, INDICATOR_DATA); - ArraySetAsSeries(BufferAD, false); - - IndicatorSetInteger(INDICATOR_DIGITS, 0); - IndicatorSetString(INDICATOR_SHORTNAME, "HA_A/D"); - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, 1); - - g_ha_calculator = new CHeikinAshi_Calculator(); - if(CheckPointer(g_ha_calculator) == POINTER_INVALID) - { - Print("Error creating CHeikinAshi_Calculator object"); - return(INIT_FAILED); - } - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { - if(CheckPointer(g_ha_calculator) != POINTER_INVALID) - { - delete g_ha_calculator; - g_ha_calculator = NULL; - } - } - -//+------------------------------------------------------------------+ -//| A/D on Heikin 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 < 2) - return(0); - -//--- Intermediate Heikin Ashi Buffers - double ha_open[], ha_high[], ha_low[], ha_close[]; - ArrayResize(ha_open, rates_total); - ArrayResize(ha_high, rates_total); - ArrayResize(ha_low, rates_total); - ArrayResize(ha_close, rates_total); - -//--- STEP 1: Calculate Heikin Ashi bars - g_ha_calculator.Calculate(rates_total, open, high, low, close, ha_open, ha_high, ha_low, ha_close); - -//--- STEP 2: Main calculation loop on HA data - for(int i = 0; i < rates_total; i++) - { - double mfm = 0; // Money Flow Multiplier - double range = ha_high[i] - ha_low[i]; - - if(range > 0) - { - mfm = ((ha_close[i] - ha_low[i]) - (ha_high[i] - ha_close[i])) / range; - } - - long current_volume = (InpVolumeType == VOLUME_TICK) ? tick_volume[i] : volume[i]; - double mfv = mfm * current_volume; // Money Flow Volume - - if(i > 0) - BufferAD[i] = BufferAD[i-1] + mfv; - else - BufferAD[i] = mfv; // First value - } - - return(rates_total); - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/ALMA.md b/Indicators/MyIndicators/ALMA.md deleted file mode 100644 index 0a882e0..0000000 --- a/Indicators/MyIndicators/ALMA.md +++ /dev/null @@ -1,67 +0,0 @@ -# Arnaud Legoux Moving Average (ALMA) - -## 1. Summary (Introduction) - -The Arnaud Legoux Moving Average (ALMA) was developed by Arnaud Legoux and Dimitrios Kouzis-Loukas. It was designed to address two common problems with traditional moving averages: lag and smoothness. The ALMA attempts to strike a better balance between responsiveness and smoothness, providing a high-fidelity trend line that reduces lag significantly while still filtering out minor price noise. - -It achieves this by applying a Gaussian filter to the moving average calculation, which is shifted according to a user-defined "offset" parameter. This allows the filter to be more weighted towards recent bars, thus reducing lag. - -## 2. Mathematical Foundations and Calculation Logic - -The ALMA is a sophisticated weighted moving average that uses a Gaussian distribution for its weights. Unlike a simple or exponential moving average, the weights are not linear or exponentially decaying but follow a bell curve. - -### Required Components - -- **Window Size (N):** The lookback period for the moving average. -- **Offset (O):** A parameter between 0 and 1 that shifts the focus of the bell curve. An offset of 0.85 (the default) means the most weight is applied to bars that are 85% of the way through the lookback window, emphasizing more recent data. -- **Sigma (S):** A parameter that controls the "flatness" or "sharpness" of the bell curve. A larger sigma creates a flatter curve (more like an SMA), while a smaller sigma creates a sharper curve (more focused weights). -- **Source Price (P):** The price series used for the calculation (e.g., Close). - -### Calculation Steps (Algorithm) - -For each bar `i`, the ALMA is calculated by taking a weighted sum of the prices in the lookback window from `i - (N - 1)` to `i`. - -1. **Calculate Gaussian Weight:** For each point `j` within the lookback window (where `j` goes from `0` to `N-1`), a weight is calculated based on a Gaussian function. - - - First, calculate the `m` and `s` parameters from the user inputs: - $m = O \times (N - 1)$ - $s = \frac{N}{S}$ - - Then, calculate the weight for each point `j`: - $\text{Weight}_j = e^{-\frac{(j - m)^2}{2s^2}}$ - Where `e` is Euler's number. - -2. **Calculate the Weighted Sum:** Multiply each price in the window by its corresponding weight and sum the results. - $\text{Weighted Sum}_i = \sum_{j=0}^{N-1} P_{i - (N - 1) + j} \times \text{Weight}_j$ - -3. **Normalize and Calculate Final ALMA:** Divide the weighted sum by the sum of all weights to get the final ALMA value. - $\text{ALMA}_i = \frac{\text{Weighted Sum}_i}{\sum_{j=0}^{N-1} \text{Weight}_j}$ - -## 3. MQL5 Implementation Details - -Our MQL5 implementation was refocused to be a completely self-contained, robust, and accurate indicator. - -- **Stability via Full Recalculation:** We employ a "brute-force" full recalculation within the `OnCalculate` function. As ALMA is not a recursive indicator, this is a straightforward and highly stable approach. - -- **Self-Contained Price Handling:** The indicator does not use external handles like `iMA`. It directly processes the price arrays (`open`, `high`, `low`, `close`) provided by `OnCalculate`. A `for` loop and `switch` block prepare a single `price_source[]` array based on the user's `InpAppliedPrice` selection, including all standard and calculated price types (e.g., `PRICE_TYPICAL`). - -- **Accurate Indexing:** The implementation uses the correct indexing logic (`price_index = i - (g_ExtAlmaPeriod - 1) + j`) within the calculation loop. This ensures that the weights are applied to the correct prices within the sliding window, perfectly matching the standard definition of the indicator. - -- **Integrated Calculation Loop:** The `OnCalculate` function uses a single, efficient main `for` loop to calculate the ALMA for each bar. The complex weighting and summation logic is handled within this loop, making the code clear and easy to follow. - -- **Heikin Ashi Variant (`ALMA_HeikinAshi.mq5`):** - - Our toolkit also includes a Heikin Ashi version of this indicator. The calculation logic is identical, but it uses the smoothed Heikin Ashi price data (e.g., `ha_close`) as its input. - - This combines the advanced smoothing of the ALMA formula with the noise-filtering properties of Heikin Ashi candles, resulting in an exceptionally smooth and responsive trend line. - -## 4. Parameters - -- **Window Size / Period (`InpAlmaPeriod`):** The lookback period for the moving average. Default is `9`. -- **Applied Price (`InpAppliedPrice`):** The source price used for the calculation. Default is `PRICE_CLOSE`. -- **Offset (`InpAlmaOffset`):** Controls the focus of the moving average. A value closer to `1` makes the ALMA more responsive (less lag), while a value closer to `0` makes it smoother (more lag). Default is `0.85`. -- **Sigma (`InpAlmaSigma`):** Controls the smoothness of the moving average. A larger value makes the line smoother, while a smaller value makes it follow the price more closely. Default is `6.0`. - -## 5. Usage and Interpretation - -- **Trend Identification:** The ALMA is primarily used as a high-fidelity trend line. When the price is above the ALMA and the ALMA is rising, the trend is considered bullish. When the price is below the ALMA and the ALMA is falling, the trend is considered bearish. -- **Dynamic Support and Resistance:** The line itself can act as a very reliable level of dynamic support in an uptrend or resistance in a downtrend. -- **Crossover Signals:** Crossovers of the price and the ALMA line can be used as trade signals. Due to its reduced lag, these signals are generally faster than those from traditional moving averages. -- **Caution:** While the ALMA is an advanced moving average, it is still a lagging indicator. It performs best in trending markets and can produce false signals in sideways or choppy conditions. diff --git a/Indicators/MyIndicators/ALMA.mq5 b/Indicators/MyIndicators/ALMA.mq5 deleted file mode 100644 index 57ff0b0..0000000 --- a/Indicators/MyIndicators/ALMA.mq5 +++ /dev/null @@ -1,134 +0,0 @@ -//+------------------------------------------------------------------+ -//| ALMA.mq5| -//| Copyright 2025, xxxxxxxx | -//| | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property link "" -#property version "2.00" // Refactored to be self-contained and stable -#property description "Arnaud Legoux Moving Average (ALMA)" - -//--- Indicator Window and Plot Properties --- -#property indicator_chart_window -#property indicator_buffers 1 -#property indicator_plots 1 - -//--- Plot 1: ALMA line -#property indicator_label1 "ALMA" -#property indicator_type1 DRAW_LINE -#property indicator_color1 clrMediumVioletRed -#property indicator_style1 STYLE_SOLID -#property indicator_width1 2 - -//--- Input Parameters --- -input int InpAlmaPeriod = 9; // Window size (period) -input ENUM_APPLIED_PRICE InpAppliedPrice = PRICE_CLOSE; // Applied price -input double InpAlmaOffset = 0.85; // Offset (0 to 1) -input double InpAlmaSigma = 6.0; // Sigma (smoothness) - -//--- Indicator Buffers --- -double BufferALMA[]; - -//--- Global Variables --- -int g_ExtAlmaPeriod; -double g_ExtAlmaOffset; -double g_ExtAlmaSigma; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { -//--- Validate and store input parameters - g_ExtAlmaPeriod = (InpAlmaPeriod < 1) ? 1 : InpAlmaPeriod; - g_ExtAlmaOffset = InpAlmaOffset; - g_ExtAlmaSigma = (InpAlmaSigma <= 0) ? 0.01 : InpAlmaSigma; - -//--- Map the buffer and set as non-timeseries - SetIndexBuffer(0, BufferALMA, INDICATOR_DATA); - ArraySetAsSeries(BufferALMA, false); - -//--- Set indicator display properties - IndicatorSetInteger(INDICATOR_DIGITS, _Digits); - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, g_ExtAlmaPeriod - 1); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("ALMA(%d, %.2f, %.1f)", g_ExtAlmaPeriod, g_ExtAlmaOffset, g_ExtAlmaSigma)); - - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Arnaud Legoux Moving Average 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_ExtAlmaPeriod) - return(0); - -//--- STEP 1: Prepare the source price array - double price_source[]; - ArrayResize(price_source, rates_total); - for(int i=0; i 0) - BufferALMA[i] = sum / norm; - else - BufferALMA[i] = 0.0; - } - - return(rates_total); - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/ALMA_HeikinAshi.mq5 b/Indicators/MyIndicators/ALMA_HeikinAshi.mq5 deleted file mode 100644 index 32ff240..0000000 --- a/Indicators/MyIndicators/ALMA_HeikinAshi.mq5 +++ /dev/null @@ -1,172 +0,0 @@ -//+------------------------------------------------------------------+ -//| ALMA_HeikinAshi.mq5 | -//| Copyright 2025, xxxxxxxx | -//| | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property link "" -#property version "2.01" // Fixed indexing logic in ALMA calculation -#property description "Arnaud Legoux Moving Average (ALMA) on Heikin Ashi data" - -#include - -//--- Indicator Window and Plot Properties --- -#property indicator_chart_window -#property indicator_buffers 1 -#property indicator_plots 1 - -//--- Plot 1: ALMA line -#property indicator_label1 "HA_ALMA" -#property indicator_type1 DRAW_LINE -#property indicator_color1 clrMediumVioletRed -#property indicator_style1 STYLE_SOLID -#property indicator_width1 2 - -//--- Enum for selecting Heikin Ashi price source --- -enum ENUM_HA_APPLIED_PRICE - { - HA_PRICE_CLOSE, // Heikin Ashi Close - HA_PRICE_OPEN, // Heikin Ashi Open - HA_PRICE_HIGH, // Heikin Ashi High - HA_PRICE_LOW, // Heikin Ashi Low - }; - -//--- Input Parameters --- -input int InpAlmaPeriod = 9; -input ENUM_HA_APPLIED_PRICE InpAppliedPrice = HA_PRICE_CLOSE; -input double InpAlmaOffset = 0.85; -input double InpAlmaSigma = 6.0; - -//--- Indicator Buffers --- -double BufferHA_ALMA[]; - -//--- Intermediate Heikin Ashi Buffers --- -double ExtHaOpenBuffer[]; -double ExtHaHighBuffer[]; -double ExtHaLowBuffer[]; -double ExtHaCloseBuffer[]; - -//--- Global Objects and Variables --- -int g_ExtAlmaPeriod; -double g_ExtAlmaOffset; -double g_ExtAlmaSigma; -CHeikinAshi_Calculator *g_ha_calculator; // Pointer to our Heikin Ashi calculator - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - g_ExtAlmaPeriod = (InpAlmaPeriod < 1) ? 1 : InpAlmaPeriod; - g_ExtAlmaOffset = InpAlmaOffset; - g_ExtAlmaSigma = (InpAlmaSigma <= 0) ? 0.01 : InpAlmaSigma; - - SetIndexBuffer(0, BufferHA_ALMA, INDICATOR_DATA); - ArraySetAsSeries(BufferHA_ALMA, false); - - IndicatorSetInteger(INDICATOR_DIGITS, _Digits); - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, g_ExtAlmaPeriod - 1); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA_ALMA(%d, %.2f, %.1f)", g_ExtAlmaPeriod, g_ExtAlmaOffset, g_ExtAlmaSigma)); - -//--- Create the calculator instance - g_ha_calculator = new CHeikinAshi_Calculator(); - if(CheckPointer(g_ha_calculator) == POINTER_INVALID) - { - Print("Error creating CHeikinAshi_Calculator object"); - return(INIT_FAILED); - } - - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { -//--- Free the calculator object to prevent memory leaks - if(CheckPointer(g_ha_calculator) != POINTER_INVALID) - { - delete g_ha_calculator; - g_ha_calculator = NULL; - } - } - -//+------------------------------------------------------------------+ -//| Arnaud Legoux Moving Average 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_ExtAlmaPeriod) - return(0); - -//--- Resize intermediate buffers to match the available bars - ArrayResize(ExtHaOpenBuffer, rates_total); - ArrayResize(ExtHaHighBuffer, rates_total); - ArrayResize(ExtHaLowBuffer, rates_total); - ArrayResize(ExtHaCloseBuffer, rates_total); - -//--- STEP 1: Calculate Heikin Ashi bars using our toolkit - g_ha_calculator.Calculate(rates_total, open, high, low, close, - ExtHaOpenBuffer, ExtHaHighBuffer, ExtHaLowBuffer, ExtHaCloseBuffer); - -//--- STEP 2: Select the source price array for ALMA calculation - double source_array[]; - switch(InpAppliedPrice) - { - case HA_PRICE_OPEN: - ArrayCopy(source_array, ExtHaOpenBuffer); - break; - case HA_PRICE_HIGH: - ArrayCopy(source_array, ExtHaHighBuffer); - break; - case HA_PRICE_LOW: - ArrayCopy(source_array, ExtHaLowBuffer); - break; - default: // HA_PRICE_CLOSE - ArrayCopy(source_array, ExtHaCloseBuffer); - break; - } - -//--- STEP 3: Calculate ALMA based on the selected HA price array - double m = g_ExtAlmaOffset * (g_ExtAlmaPeriod - 1.0); - double s = (double)g_ExtAlmaPeriod / g_ExtAlmaSigma; - -// The main loop iterates through all bars that can be calculated - for(int i = g_ExtAlmaPeriod - 1; i < rates_total; i++) - { - double sum = 0.0; - double norm = 0.0; - - // The inner loop calculates the weighted sum for the current bar 'i' - for(int j = 0; j < g_ExtAlmaPeriod; j++) - { - double weight = MathExp(-1 * MathPow(j - m, 2) / (2 * s * s)); - - // *** FIX: Reverted to the original, correct indexing logic *** - // This ensures the weight for position 'j' is applied to the correct price in the window. - int price_index = i - (g_ExtAlmaPeriod - 1) + j; - - sum += source_array[price_index] * weight; - norm += weight; - } - - if(norm > 0) - BufferHA_ALMA[i] = sum / norm; - else - BufferHA_ALMA[i] = 0.0; - } - - return(rates_total); - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/AMA.md b/Indicators/MyIndicators/AMA.md deleted file mode 100644 index 799ea5c..0000000 --- a/Indicators/MyIndicators/AMA.md +++ /dev/null @@ -1,64 +0,0 @@ -# Adaptive Moving Average (AMA) - -## 1. Summary (Introduction) - -The Adaptive Moving Average (AMA), developed by Perry J. Kaufman, is an advanced moving average designed to automatically adjust its speed based on market volatility. It addresses a core dilemma of traditional moving averages: the trade-off between lag and smoothness. - -The AMA's key feature is its ability to move very slowly when the market is consolidating or moving sideways (high noise, low directional movement), and to speed up and track prices closely when the market is trending (low noise, high directional movement). This adaptability helps to filter out false signals in choppy markets while remaining responsive during strong trends. - -## 2. Mathematical Foundations and Calculation Logic - -The AMA's adaptability is achieved through the **Efficiency Ratio (ER)**, which quantifies the amount of "noise" in the market. - -### Required Components - -- **AMA Period (N):** The lookback period for calculating the Efficiency Ratio. -- **Fast/Slow EMA Periods:** Used to define the fastest and slowest possible speeds for the AMA. -- **Source Price (P):** The price series used for the calculation. - -### Calculation Steps (Algorithm) - -1. **Calculate the Efficiency Ratio (ER):** The ER is the ratio of the net price change (Direction) to the sum of all individual price changes (Volatility) over the period `N`. - - - $\text{Direction}_i = \text{Abs}(\text{Price}_i - \text{Price}_{i-N})$ - - $\text{Volatility}_i = \sum_{k=i-N+1}^{i} \text{Abs}(\text{Price}_k - \text{Price}_{k-1})$ - - $\text{ER}_i = \frac{\text{Direction}_i}{\text{Volatility}_i}$ - - An ER value close to `1` indicates an efficient, trending market. A value close to `0` indicates an inefficient, noisy market. - -2. **Calculate the Scaled Smoothing Constant (SSC):** The ER is used to create a dynamic smoothing constant that varies between the constants of a fast and a slow EMA. - - - $\text{Fast SC} = \frac{2}{\text{Fast Period} + 1}$ - - $\text{Slow SC} = \frac{2}{\text{Slow Period} + 1}$ - - $\text{SSC}_i = (\text{ER}_i \times (\text{Fast SC} - \text{Slow SC})) + \text{Slow SC}$ - -3. **Calculate the Final AMA:** The AMA is calculated recursively. The `SSC` is squared to give more weight to the faster smoothing constant during trends. - $\text{AMA}_i = \text{AMA}_{i-1} + (\text{SSC}_i)^2 \times (P_i - \text{AMA}_{i-1})$ - -## 3. MQL5 Implementation Details - -Our MQL5 implementation is a self-contained, robust, and accurate representation of Kaufman's AMA. - -- **Stability via Full Recalculation:** We employ a "brute-force" full recalculation within the `OnCalculate` function. For a recursive indicator like the AMA, this is the most reliable method to ensure stability. - -- **Robust Initialization:** The recursive AMA calculation is carefully initialized. The **first valid value** of the AMA line (`BufferAMA[g_ExtAmaPeriod]`) is set directly to the current source price. This provides a simple and highly stable starting point for the subsequent recursive calculations. - -- **Self-Contained Logic:** The indicator is completely self-contained and does not use any external handles or libraries. The source price is prepared internally using a `switch` block that handles all `ENUM_APPLIED_PRICE` types. - -- **Clear, Staged Calculation:** The `OnCalculate` function is structured into clear, sequential steps. After preparing the source price array, a single, efficient `for` loop handles the entire AMA calculation, including the ER and SSC computations. - -- **Heikin Ashi Variant (`AMA_HeikinAshi.mq5`):** - - Our toolkit also includes a "pure" Heikin Ashi version. The calculation logic is identical, but it uses the smoothed Heikin Ashi price data as its input. - - **Behavioral Note:** This version can appear _more responsive_ than the standard version in strong trends. The smoothed Heikin Ashi data produces a very high Efficiency Ratio (close to 1), causing the AMA to switch to its fastest speed and closely track the underlying Heikin Ashi trend. - -## 4. Parameters - -- **AMA Period (`InpAmaPeriod`):** The lookback period for the Efficiency Ratio calculation. Default is `10`. -- **Fast EMA Period (`InpFastEmaPeriod`):** Defines the "fastest" speed of the AMA. Default is `2`. -- **Slow EMA Period (`InpSlowEmaPeriod`):** Defines the "slowest" speed of the AMA. Default is `30`. -- **Applied Price (`InpAppliedPrice`):** The source price used for the calculation. Default is `PRICE_CLOSE`. - -## 5. Usage and Interpretation - -- **Trend Identification:** The AMA is used as an adaptive trend line. When the price is above the AMA and the line is rising, the trend is bullish. When the price is below the line and it is falling, the trend is bearish. -- **Trend Filter:** The key advantage of the AMA is its ability to flatten out and move slowly during sideways markets. A flat AMA line is a clear signal to avoid trend-following strategies. When the line begins to angle up or down sharply, it indicates that the market has entered a more efficient, trending phase. -- **Crossover Signals:** Crossovers of the price and the AMA line can be used as trade signals. These signals are naturally filtered by the indicator itself, as crossovers are less likely to occur during choppy conditions when the AMA is moving slowly. diff --git a/Indicators/MyIndicators/AMA.mq5 b/Indicators/MyIndicators/AMA.mq5 deleted file mode 100644 index 449a1d7..0000000 --- a/Indicators/MyIndicators/AMA.mq5 +++ /dev/null @@ -1,139 +0,0 @@ -//+------------------------------------------------------------------+ -//| AMA.mq5 | -//| Copyright 2025, xxxxxxxx | -//| | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property link "" -#property version "1.01" // Corrected standard version -#property description "Adaptive Moving Average (AMA) by Perry Kaufman" - -//--- Indicator Window and Plot Properties --- -#property indicator_chart_window -#property indicator_buffers 1 -#property indicator_plots 1 -#property indicator_type1 DRAW_LINE -#property indicator_color1 clrRed -#property indicator_style1 STYLE_SOLID -#property indicator_width1 1 -#property indicator_label1 "AMA" - -//--- Input Parameters --- -input int InpAmaPeriod = 10; // AMA Efficiency Ratio Period -input int InpFastEmaPeriod= 2; // Fast EMA Period for scaling -input int InpSlowEmaPeriod= 30; // Slow EMA Period for scaling -input ENUM_APPLIED_PRICE InpAppliedPrice = PRICE_CLOSE; // Applied Price - -//--- Indicator Buffers --- -double BufferAMA[]; - -//--- Global Variables --- -int g_ExtAmaPeriod; -int g_ExtFastEmaPeriod; -int g_ExtSlowEmaPeriod; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - g_ExtAmaPeriod = (InpAmaPeriod < 1) ? 1 : InpAmaPeriod; - g_ExtFastEmaPeriod = (InpFastEmaPeriod < 1) ? 1 : InpFastEmaPeriod; - g_ExtSlowEmaPeriod = (InpSlowEmaPeriod < 1) ? 1 : InpSlowEmaPeriod; - - SetIndexBuffer(0, BufferAMA, INDICATOR_DATA); - ArraySetAsSeries(BufferAMA, false); - - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, g_ExtAmaPeriod); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("AMA(%d,%d,%d)", g_ExtAmaPeriod, g_ExtFastEmaPeriod, g_ExtSlowEmaPeriod)); - IndicatorSetInteger(INDICATOR_DIGITS, _Digits); - - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Adaptive Moving Average 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_ExtAmaPeriod) - return(0); - -//--- STEP 1: Prepare the source price array - double price_source[]; - ArrayResize(price_source, rates_total); - for(int i=0; i g_ExtAmaPeriod) - { - // --- Calculate Efficiency Ratio (ER) --- - double direction = MathAbs(price_source[i] - price_source[i - g_ExtAmaPeriod]); - double volatility = 0; - for(int j = 0; j < g_ExtAmaPeriod; j++) - { - volatility += MathAbs(price_source[i - j] - price_source[i - j - 1]); - } - double er = (volatility > 0) ? direction / volatility : 0; - - // --- Calculate Scaled Smoothing Constant (SSC) --- - double ssc = er * (fast_sc - slow_sc) + slow_sc; - double ssc_sq = ssc * ssc; - - // --- Calculate Final AMA --- - BufferAMA[i] = BufferAMA[i-1] + ssc_sq * (price_source[i] - BufferAMA[i-1]); - } - } - - return(rates_total); - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/AMA_HeikinAshi.mq5 b/Indicators/MyIndicators/AMA_HeikinAshi.mq5 deleted file mode 100644 index 8b47e9f..0000000 --- a/Indicators/MyIndicators/AMA_HeikinAshi.mq5 +++ /dev/null @@ -1,166 +0,0 @@ -//+------------------------------------------------------------------+ -//| AMA_HeikinAshi.mq5 | -//| Copyright 2025, xxxxxxxx | -//| | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property link "" -#property version "1.00" -#property description "Adaptive Moving Average (AMA) on Heikin Ashi data" - -#include - -//--- Indicator Window and Plot Properties --- -#property indicator_chart_window -#property indicator_buffers 1 -#property indicator_plots 1 -#property indicator_type1 DRAW_LINE -#property indicator_color1 clrRed -#property indicator_style1 STYLE_SOLID -#property indicator_width1 1 -#property indicator_label1 "HA_AMA" - -//--- Enum for selecting Heikin Ashi price source --- -enum ENUM_HA_APPLIED_PRICE - { - HA_PRICE_CLOSE, HA_PRICE_OPEN, HA_PRICE_HIGH, HA_PRICE_LOW, HA_PRICE_TYPICAL, HA_PRICE_MEDIAN - }; - -//--- Input Parameters --- -input int InpAmaPeriod = 10; -input int InpFastEmaPeriod= 2; -input int InpSlowEmaPeriod= 30; -input ENUM_HA_APPLIED_PRICE InpAppliedPrice = HA_PRICE_CLOSE; - -//--- Indicator Buffers --- -double BufferAMA[]; - -//--- Global Objects and Variables --- -int g_ExtAmaPeriod, g_ExtFastEmaPeriod, g_ExtSlowEmaPeriod; -CHeikinAshi_Calculator *g_ha_calculator; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - g_ExtAmaPeriod = (InpAmaPeriod < 1) ? 1 : InpAmaPeriod; - g_ExtFastEmaPeriod = (InpFastEmaPeriod < 1) ? 1 : InpFastEmaPeriod; - g_ExtSlowEmaPeriod = (InpSlowEmaPeriod < 1) ? 1 : InpSlowEmaPeriod; - - SetIndexBuffer(0, BufferAMA, INDICATOR_DATA); - ArraySetAsSeries(BufferAMA, false); - - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, g_ExtAmaPeriod); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA_AMA(%d,%d,%d)", g_ExtAmaPeriod, g_ExtFastEmaPeriod, g_ExtSlowEmaPeriod)); - IndicatorSetInteger(INDICATOR_DIGITS, _Digits); - - g_ha_calculator = new CHeikinAshi_Calculator(); - if(CheckPointer(g_ha_calculator) == POINTER_INVALID) - { - Print("Error creating CHeikinAshi_Calculator object"); - return(INIT_FAILED); - } - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { - if(CheckPointer(g_ha_calculator) != POINTER_INVALID) - { - delete g_ha_calculator; - g_ha_calculator = NULL; - } - } - -//+------------------------------------------------------------------+ -//| AMA on Heikin 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 <= g_ExtAmaPeriod) - return(0); - -//--- Intermediate Heikin Ashi Buffers - double ha_open[], ha_high[], ha_low[], ha_close[]; - ArrayResize(ha_open, rates_total); - ArrayResize(ha_high, rates_total); - ArrayResize(ha_low, rates_total); - ArrayResize(ha_close, rates_total); - -//--- STEP 1: Calculate Heikin Ashi bars - g_ha_calculator.Calculate(rates_total, open, high, low, close, ha_open, ha_high, ha_low, ha_close); - -//--- STEP 2: Prepare the Heikin Ashi source price array - double ha_price_source[]; - ArrayResize(ha_price_source, rates_total); - for(int i=0; i g_ExtAmaPeriod) - { - double direction = MathAbs(ha_price_source[i] - ha_price_source[i - g_ExtAmaPeriod]); - double volatility = 0; - for(int j = 0; j < g_ExtAmaPeriod; j++) - { - volatility += MathAbs(ha_price_source[i - j] - ha_price_source[i - j - 1]); - } - double er = (volatility > 0) ? direction / volatility : 0; - - double ssc = er * (fast_sc - slow_sc) + slow_sc; - double ssc_sq = ssc * ssc; - - BufferAMA[i] = BufferAMA[i-1] + ssc_sq * (ha_price_source[i] - BufferAMA[i-1]); - } - } - - return(rates_total); - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/AMA_TrendActivity.md b/Indicators/MyIndicators/AMA_TrendActivity.md deleted file mode 100644 index bef503b..0000000 --- a/Indicators/MyIndicators/AMA_TrendActivity.md +++ /dev/null @@ -1,66 +0,0 @@ -# AMA Trend Activity - -## 1. Summary (Introduction) - -The AMA Trend Activity is a custom-built "meta-indicator" designed to measure the directional strength and activity of the **Adaptive Moving Average (AMA)**. While the AMA line itself shows the trend, this oscillator quantifies _how trendy_ the market is according to the AMA's behavior, specifically its rate of change relative to volatility. - -Developed as part of our indicator toolkit, its primary purpose is to act as a **trend filter**. It generates high values when the AMA is moving decisively in one direction (indicating an efficient, trending market) and low values when the AMA line flattens out (indicating a sideways, noisy market). It helps traders to visually distinguish between trending and non-trending environments. - -## 2. Mathematical Foundations and Calculation Logic - -This indicator analyzes the behavior of two underlying indicators, AMA and ATR, to produce a final, normalized oscillator. - -### Required Components - -- **AMA:** The underlying adaptive moving average. Its slope is the primary input. -- **ATR (Average True Range):** Used as a normalization factor to make the indicator's output comparable across different instruments and timeframes. -- **Smoothing Period:** A final smoothing period for the oscillator output. - -### Calculation Steps (Algorithm) - -1. **Calculate AMA:** First, the standard Kaufman's AMA is calculated for the chart based on its parameters. - -2. **Calculate ATR:** Separately, the standard Wilder's ATR is calculated. - -3. **Calculate Raw Activity:** For each bar, the indicator measures the rate of change (slope) of the AMA line and normalizes it by the market's current volatility (ATR). This produces a raw, unbounded value representing the trend's relative strength. - $\text{Raw Activity}_i = \frac{\text{Abs}(\text{AMA}_i - \text{AMA}_{i-1})}{\text{ATR}_i}$ - -4. **Normalize with Arctan:** To solve the problem of scale across different timeframes, the `Raw Activity` value is passed through the inverse tangent (`Arctan`) function and then scaled to a consistent `0..1` range. The `Arctan` function elegantly maps any positive input into a predictable range, making the indicator robust on any timeframe. - $\text{Scaled Activity}_i = \frac{\text{Arctan}(\text{Raw Activity}_i)}{\pi/2}$ - -5. **Final Smoothing:** The `Scaled Activity` values are smoothed with a Simple Moving Average (SMA) to create the final, plotted histogram. - $\text{Final Activity}_i = \text{SMA}(\text{Scaled Activity}, \text{Smoothing Period})_i$ - -## 3. MQL5 Implementation Details - -Our MQL5 implementation is a completely self-contained indicator that internally calculates all its required components based on our established robust principles. - -- **Stability via Full Recalculation:** The indicator employs a "brute-force" full recalculation within the `OnCalculate` function for maximum stability. - -- **Internal Calculators:** The indicator does not use any external handles. It contains the full, robust, and manually implemented logic for calculating both the **AMA** and the **ATR**. All recursive calculations are carefully initialized to prevent floating-point overflows. - -- **Robust Normalization:** The use of the `MathArctan` function for normalization is a key feature. It ensures that the indicator's output remains consistent and comparable across all instruments and timeframes, from M1 to Weekly. - -- **Optimized Visualization:** The indicator's vertical scale is programmatically set to a `0.0` to `0.5` range. Our analysis showed that the vast majority of significant signals occur within this range. This "zooms in" on the most relevant area of activity, making the visual output much clearer and easier to interpret. - -- **Heikin Ashi Variant (`AMA_TrendActivity_HeikinAshi.mq5`):** - - Our toolkit also includes a "pure" Heikin Ashi version. The calculation logic is identical, but all its inputs (AMA and ATR) are derived from the smoothed Heikin Ashi price data. - -## 4. Parameters - -- **AMA Settings:** - - `InpAmaPeriod`: The period for the AMA's Efficiency Ratio. - - `InpFastEmaPeriod`: The "fast" period for the AMA's scaling. - - `InpSlowEmaPeriod`: The "slow" period for the AMA's scaling. - - `InpAppliedPrice`: The source price for the underlying AMA. -- **Activity Calculation Settings:** - - `InpAtrPeriod`: The period for the ATR used in normalization. - - `InpSmoothingPeriod`: The period for the final SMA smoothing of the oscillator. - -## 5. Usage and Interpretation - -- **Trend Filter:** This is the indicator's primary function. A trader can establish a threshold (e.g., 0.1 or 0.2). - - **Activity > Threshold:** The market is considered to be in a **trending phase**. Trend-following strategies are more likely to be effective. - - **Activity < Threshold:** The market is considered to be in a **ranging or consolidating phase**. Mean-reversion strategies may be more appropriate. -- **Identifying Trend Exhaustion:** A sharp decline in the activity histogram after a strong trend can signal that momentum is waning and the trend may be nearing exhaustion or entering a consolidation phase. -- **Confirming Breakouts:** A spike in the activity histogram accompanying a price breakout from a range can provide strong confirmation that the breakout has momentum behind it. diff --git a/Indicators/MyIndicators/AMA_TrendActivity.mq5 b/Indicators/MyIndicators/AMA_TrendActivity.mq5 deleted file mode 100644 index 25887b3..0000000 --- a/Indicators/MyIndicators/AMA_TrendActivity.mq5 +++ /dev/null @@ -1,190 +0,0 @@ -//+------------------------------------------------------------------+ -//| AMA_TrendActivity.mq5 | -//| Copyright 2025, xxxxxxxx | -//| | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property link "" -#property version "1.00" -#property description "Measures the trend activity (slope) of an AMA line using Arctan normalization." -#property description "High values suggest a trending market, low values suggest a flat/ranging market." - -//--- Indicator Window and Plot Properties --- -#property indicator_separate_window -#property indicator_buffers 1 -#property indicator_plots 1 -#property indicator_type1 DRAW_HISTOGRAM -#property indicator_color1 clrDodgerBlue -#property indicator_width1 2 -#property indicator_label1 "Activity" -#property indicator_minimum 0.0 -#property indicator_maximum 0.5 - -//--- Input Parameters --- -input group "AMA Settings" -input int InpAmaPeriod = 10; -input int InpFastEmaPeriod= 2; -input int InpSlowEmaPeriod= 30; -input ENUM_APPLIED_PRICE InpAppliedPrice = PRICE_CLOSE; -input group "Activity Calculation Settings" -input int InpAtrPeriod = 14; -input int InpSmoothingPeriod = 5; - -//--- Indicator Buffers --- -double BufferActivity[]; - -//--- Global Variables --- -int g_ExtAmaPeriod, g_ExtFastEmaPeriod, g_ExtSlowEmaPeriod, g_ExtAtrPeriod, g_ExtSmoothingPeriod; -double g_M_PI_2; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - g_ExtAmaPeriod = (InpAmaPeriod < 1) ? 1 : InpAmaPeriod; - g_ExtFastEmaPeriod = (InpFastEmaPeriod < 1) ? 1 : InpFastEmaPeriod; - g_ExtSlowEmaPeriod = (InpSlowEmaPeriod < 1) ? 1 : InpSlowEmaPeriod; - g_ExtAtrPeriod = (InpAtrPeriod < 1) ? 1 : InpAtrPeriod; - g_ExtSmoothingPeriod = (InpSmoothingPeriod < 1) ? 1 : InpSmoothingPeriod; - g_M_PI_2 = M_PI / 2.0; - - SetIndexBuffer(0, BufferActivity, INDICATOR_DATA); - ArraySetAsSeries(BufferActivity, false); - - int draw_begin = g_ExtAmaPeriod + g_ExtAtrPeriod + g_ExtSmoothingPeriod; - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, draw_begin); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("AMA Activity(%d,%d,%d)", g_ExtAmaPeriod, g_ExtAtrPeriod, g_ExtSmoothingPeriod)); - IndicatorSetInteger(INDICATOR_DIGITS, 4); - - IndicatorSetDouble(INDICATOR_MINIMUM, 0.0); - IndicatorSetDouble(INDICATOR_MAXIMUM, 0.5); - - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| AMA Trend Activity 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[]) - { - int start_pos = g_ExtAmaPeriod + g_ExtAtrPeriod + g_ExtSmoothingPeriod; - if(rates_total <= start_pos) - return(0); - -//--- STEP 1: Prepare the source price array for AMA - double price_source[]; - ArrayResize(price_source, rates_total); - for(int i=0; i g_ExtAmaPeriod) - { - double direction = MathAbs(price_source[i] - price_source[i - g_ExtAmaPeriod]); - double volatility = 0; - for(int j = 0; j < g_ExtAmaPeriod; j++) - { - volatility += MathAbs(price_source[i - j] - price_source[i - j - 1]); - } - double er = (volatility > 0) ? direction / volatility : 0; - double ssc = er * (fast_sc - slow_sc) + slow_sc; - double ssc_sq = ssc * ssc; - buffer_ama[i] = buffer_ama[i-1] + ssc_sq * (price_source[i] - buffer_ama[i-1]); - } - } - -//--- STEP 3: Calculate ATR - double buffer_atr[]; - ArrayResize(buffer_atr, rates_total); - double tr[]; - ArrayResize(tr, rates_total); - for(int i = 1; i < rates_total; i++) - { - tr[i] = MathMax(high[i], close[i-1]) - MathMin(low[i], close[i-1]); - } - for(int i = 1; i < rates_total; i++) - { - if(i == g_ExtAtrPeriod) - { - double sum_tr = 0; - for(int j = 1; j <= g_ExtAtrPeriod; j++) - sum_tr += tr[j]; - buffer_atr[i] = sum_tr / g_ExtAtrPeriod; - } - else - if(i > g_ExtAtrPeriod) - { - buffer_atr[i] = (buffer_atr[i-1] * (g_ExtAtrPeriod - 1) + tr[i]) / g_ExtAtrPeriod; - } - } - -//--- STEP 4: Calculate Raw Activity and Scale it using MathArctan - double scaled_activity[]; - ArrayResize(scaled_activity, rates_total); - for(int i = g_ExtAmaPeriod + 1; i < rates_total; i++) - { - if(buffer_atr[i] > 0) - { - double raw_activity = MathAbs(buffer_ama[i] - buffer_ama[i-1]) / buffer_atr[i]; - scaled_activity[i] = MathArctan(raw_activity) / g_M_PI_2; - } - } - -//--- STEP 5: Calculate Final Oscillator (SMA of Scaled Activity) - double sum = 0; - int final_start_pos = g_ExtAmaPeriod + g_ExtSmoothingPeriod; - for(int i = g_ExtAmaPeriod + 1; i < rates_total; i++) - { - sum += scaled_activity[i]; - if(i >= final_start_pos) - { - if(i > final_start_pos) - { - sum -= scaled_activity[i - g_ExtSmoothingPeriod]; - } - BufferActivity[i] = sum / g_ExtSmoothingPeriod; - } - } - - return(rates_total); - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/AMA_TrendActivity_HeikinAshi.mq5 b/Indicators/MyIndicators/AMA_TrendActivity_HeikinAshi.mq5 deleted file mode 100644 index 9fa556b..0000000 --- a/Indicators/MyIndicators/AMA_TrendActivity_HeikinAshi.mq5 +++ /dev/null @@ -1,224 +0,0 @@ -//+------------------------------------------------------------------+ -//| AMA_TrendActivity_HeikinAshi.mq5 | -//| Copyright 2025, xxxxxxxx | -//| | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property link "" -#property version "1.00" -#property description "Measures the trend activity of a Heikin Ashi AMA line using Arctan normalization." -#property description "High values suggest a trending market, low values suggest a flat/ranging market." - -#include - -//--- Indicator Window and Plot Properties --- -#property indicator_separate_window -#property indicator_buffers 1 -#property indicator_plots 1 -#property indicator_type1 DRAW_HISTOGRAM -#property indicator_color1 clrDodgerBlue -#property indicator_width1 2 -#property indicator_label1 "HA_Activity" -#property indicator_minimum 0.0 -#property indicator_maximum 0.5 - -//--- Enum for selecting Heikin Ashi price source --- -enum ENUM_HA_APPLIED_PRICE - { - HA_PRICE_CLOSE, HA_PRICE_OPEN, HA_PRICE_HIGH, HA_PRICE_LOW - }; - -//--- Input Parameters --- -input group "AMA Settings" -input int InpAmaPeriod = 10; -input int InpFastEmaPeriod= 2; -input int InpSlowEmaPeriod= 30; -input ENUM_HA_APPLIED_PRICE InpAppliedPrice = HA_PRICE_CLOSE; -input group "Activity Calculation Settings" -input int InpAtrPeriod = 14; -input int InpSmoothingPeriod = 5; - -//--- Indicator Buffers --- -double BufferActivity[]; - -//--- Global Objects and Variables --- -int g_ExtAmaPeriod, g_ExtFastEmaPeriod, g_ExtSlowEmaPeriod, g_ExtAtrPeriod, g_ExtSmoothingPeriod; -double g_M_PI_2; -CHeikinAshi_Calculator *g_ha_calculator; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - g_ExtAmaPeriod = (InpAmaPeriod < 1) ? 1 : InpAmaPeriod; - g_ExtFastEmaPeriod = (InpFastEmaPeriod < 1) ? 1 : InpFastEmaPeriod; - g_ExtSlowEmaPeriod = (InpSlowEmaPeriod < 1) ? 1 : InpSlowEmaPeriod; - g_ExtAtrPeriod = (InpAtrPeriod < 1) ? 1 : InpAtrPeriod; - g_ExtSmoothingPeriod = (InpSmoothingPeriod < 1) ? 1 : InpSmoothingPeriod; - g_M_PI_2 = M_PI / 2.0; - - SetIndexBuffer(0, BufferActivity, INDICATOR_DATA); - ArraySetAsSeries(BufferActivity, false); - - int draw_begin = g_ExtAmaPeriod + g_ExtAtrPeriod + g_ExtSmoothingPeriod; - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, draw_begin); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA AMA Activity(%d,%d,%d)", g_ExtAmaPeriod, g_ExtAtrPeriod, g_ExtSmoothingPeriod)); - IndicatorSetInteger(INDICATOR_DIGITS, 4); - - IndicatorSetDouble(INDICATOR_MINIMUM, 0.0); - IndicatorSetDouble(INDICATOR_MAXIMUM, 0.5); - - g_ha_calculator = new CHeikinAshi_Calculator(); - if(CheckPointer(g_ha_calculator) == POINTER_INVALID) - { - Print("Error creating CHeikinAshi_Calculator object"); - return(INIT_FAILED); - } - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { - if(CheckPointer(g_ha_calculator) != POINTER_INVALID) - { - delete g_ha_calculator; - g_ha_calculator = NULL; - } - } - -//+------------------------------------------------------------------+ -//| AMA Trend Activity on Heikin 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[]) - { - int start_pos = g_ExtAmaPeriod + g_ExtAtrPeriod + g_ExtSmoothingPeriod; - if(rates_total <= start_pos) - return(0); - -//--- Intermediate Heikin Ashi Buffers - double ha_open[], ha_high[], ha_low[], ha_close[]; - ArrayResize(ha_open, rates_total); - ArrayResize(ha_high, rates_total); - ArrayResize(ha_low, rates_total); - ArrayResize(ha_close, rates_total); - -//--- STEP 1: Calculate Heikin Ashi bars - g_ha_calculator.Calculate(rates_total, open, high, low, close, ha_open, ha_high, ha_low, ha_close); - -//--- STEP 2: Prepare the Heikin Ashi source price array for AMA - double ha_price_source[]; - ArrayResize(ha_price_source, rates_total); - switch(InpAppliedPrice) - { - case HA_PRICE_OPEN: - ArrayCopy(ha_price_source, ha_open); - break; - case HA_PRICE_HIGH: - ArrayCopy(ha_price_source, ha_high); - break; - case HA_PRICE_LOW: - ArrayCopy(ha_price_source, ha_low); - break; - default: - ArrayCopy(ha_price_source, ha_close); - break; - } - -//--- STEP 3: Calculate AMA on HA data - double buffer_ama[]; - ArrayResize(buffer_ama, rates_total); - double fast_sc = 2.0 / (g_ExtFastEmaPeriod + 1.0); - double slow_sc = 2.0 / (g_ExtSlowEmaPeriod + 1.0); - - for(int i = 1; i < rates_total; i++) - { - if(i == g_ExtAmaPeriod) - { - buffer_ama[i] = ha_price_source[i]; - continue; - } - if(i > g_ExtAmaPeriod) - { - double direction = MathAbs(ha_price_source[i] - ha_price_source[i - g_ExtAmaPeriod]); - double volatility = 0; - for(int j = 0; j < g_ExtAmaPeriod; j++) - { - volatility += MathAbs(ha_price_source[i - j] - ha_price_source[i - j - 1]); - } - double er = (volatility > 0) ? direction / volatility : 0; - double ssc = er * (fast_sc - slow_sc) + slow_sc; - double ssc_sq = ssc * ssc; - buffer_ama[i] = buffer_ama[i-1] + ssc_sq * (ha_price_source[i] - buffer_ama[i-1]); - } - } - -//--- STEP 4: Calculate Heikin Ashi ATR - double buffer_atr[]; - ArrayResize(buffer_atr, rates_total); - double ha_tr[]; - ArrayResize(ha_tr, rates_total); - for(int i = 1; i < rates_total; i++) - { - ha_tr[i] = MathMax(ha_high[i], ha_close[i-1]) - MathMin(ha_low[i], ha_close[i-1]); - } - for(int i = 1; i < rates_total; i++) - { - if(i == g_ExtAtrPeriod) - { - double sum_tr = 0; - for(int j = 1; j <= g_ExtAtrPeriod; j++) - sum_tr += ha_tr[j]; - buffer_atr[i] = sum_tr / g_ExtAtrPeriod; - } - else - if(i > g_ExtAtrPeriod) - { - buffer_atr[i] = (buffer_atr[i-1] * (g_ExtAtrPeriod - 1) + ha_tr[i]) / g_ExtAtrPeriod; - } - } - -//--- STEP 5: Calculate Raw Activity and Scale it using MathArctan - double scaled_activity[]; - ArrayResize(scaled_activity, rates_total); - for(int i = g_ExtAmaPeriod + 1; i < rates_total; i++) - { - if(buffer_atr[i] > 0) - { - double raw_activity = MathAbs(buffer_ama[i] - buffer_ama[i-1]) / buffer_atr[i]; - scaled_activity[i] = MathArctan(raw_activity) / g_M_PI_2; - } - } - -//--- STEP 6: Calculate Final Oscillator (SMA of Scaled Activity) - double sum = 0; - int final_start_pos = g_ExtAmaPeriod + g_ExtSmoothingPeriod; - for(int i = g_ExtAmaPeriod + 1; i < rates_total; i++) - { - sum += scaled_activity[i]; - if(i >= final_start_pos) - { - if(i > final_start_pos) - { - sum -= scaled_activity[i - g_ExtSmoothingPeriod]; - } - BufferActivity[i] = sum / g_ExtSmoothingPeriod; - } - } - - return(rates_total); - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/ATR.md b/Indicators/MyIndicators/ATR.md deleted file mode 100644 index 0952ff6..0000000 --- a/Indicators/MyIndicators/ATR.md +++ /dev/null @@ -1,64 +0,0 @@ -# Average True Range (ATR) - -## 1. Summary (Introduction) - -The Average True Range (ATR) is a technical analysis indicator developed by J. Welles Wilder, introduced in his 1978 book "New Concepts in Technical Trading Systems." The ATR is not used to indicate price direction; rather, it is a measure of **volatility**. - -It calculates the "true range" for each period and then smooths these values, providing a representation of the average size of the price range over a given time. High ATR values indicate high volatility, while low ATR values indicate low volatility or a period of consolidation. It is a foundational tool for many other indicators (like Supertrend, Keltner Channels) and for risk management strategies, such as setting stop-loss levels. - -## 2. Mathematical Foundations and Calculation Logic - -The ATR is based on the concept of the "True Range" (TR), which provides a more comprehensive measure of a single period's volatility than the simple High-Low range. - -### Required Components - -- **Period (N):** The lookback period for the smoothing calculation (e.g., 14). -- **Price Data:** The `High`, `Low`, and `Close` of each bar. - -### Calculation Steps (Algorithm) - -1. **Calculate the True Range (TR):** For each bar, the True Range is the **greatest** of the following three values: - - - The current High minus the current Low: $\text{High}_i - \text{Low}_i$ - - The absolute value of the current High minus the previous Close: $\text{Abs}(\text{High}_i - \text{Close}_{i-1})$ - - The absolute value of the current Low minus the previous Close: $\text{Abs}(\text{Low}_i - \text{Close}_{i-1})$ - $\text{TR}_i = \text{Max}[(\text{High}_i - \text{Low}_i), \text{Abs}(\text{High}_i - \text{Close}_{i-1}), \text{Abs}(\text{Low}_i - \text{Close}_{i-1})]$ - -2. **Calculate the Average True Range (ATR):** The ATR is a smoothed moving average of the True Range values, calculated using Wilder's specific smoothing method (also known as a Running Moving Average - RMA, or a specific type of Smoothed Moving Average - SMMA). - - **Initialization:** The first ATR value is a simple average of the first `N` TR values. - $\text{ATR}_{N} = \frac{1}{N} \sum_{i=1}^{N} \text{TR}_i$ - - **Recursive Calculation:** All subsequent values are calculated using the following formula: - $\text{ATR}_i = \frac{(\text{ATR}_{i-1} \times (N-1)) + \text{TR}_i}{N}$ - -_Note: This smoothing method is the globally accepted standard for ATR, as used by platforms like TradingView. The built-in `iATR` in MetaTrader uses a different, non-standard smoothing algorithm._ - -## 3. MQL5 Implementation Details - -Our MQL5 implementation is a self-contained, robust, and accurate representation of the classic Wilder's ATR. - -- **Stability via Full Recalculation:** We employ a "brute-force" full recalculation within the `OnCalculate` function. This ensures that the recursive ATR calculation remains stable and accurate, especially during timeframe changes or history loading. - -- **Consensus Wilder Algorithm:** The implementation strictly follows our established two-step algorithm for Wilder's smoothing: - - 1. **Robust Initialization:** The first ATR value (`BufferATR[g_ExtAtrPeriod]`) is calculated as a simple average of the first `N` True Range values. This provides a stable starting point for the recursive calculation. - 2. **Efficient Recursive Calculation:** All subsequent values are calculated using the efficient recursive formula, which is mathematically identical to Wilder's original method. - -- **Clear, Staged Calculation:** The `OnCalculate` function is structured into two clear, sequential steps: - - 1. **Step 1:** A `for` loop calculates the True Range for every bar and stores the results in a temporary `tr[]` array. - 2. **Step 2:** A second `for` loop iterates through the `tr[]` array and applies our robust Wilder's smoothing algorithm to calculate the final `BufferATR` values. - -- **Heikin Ashi Variant (`ATR_HeikinAshi.mq5`):** - - Our toolkit also includes a "pure" Heikin Ashi version of this indicator. The calculation logic is identical, but it uses the smoothed Heikin Ashi `ha_high`, `ha_low`, and `ha_close` values to calculate the True Range. - - This results in a "smoothed volatility" measure, which reflects the volatility of the underlying Heikin Ashi trend rather than the raw market price. This can be useful for setting stop-losses in a Heikin Ashi-based trading system. - -## 4. Parameters - -- **ATR Period (`InpAtrPeriod`):** The lookback and smoothing period for the indicator. Wilder's original recommendation and the most common value is `14`. - -## 5. Usage and Interpretation - -- **Volatility Gauge:** The ATR's primary function is to measure volatility. A rising ATR indicates that volatility is increasing, meaning daily trading ranges are widening. A falling ATR indicates that volatility is decreasing and the market is entering a period of consolidation. -- **Stop-Loss Placement:** ATR is a cornerstone of modern risk management. A common technique is to place a stop-loss at a multiple of the ATR (e.g., 2 x ATR) below a long entry price or above a short entry price. This adapts the stop-loss distance to the current market conditions. -- **Position Sizing:** ATR can be used to normalize position sizes across different instruments. By calculating a position size based on a fixed risk amount (e.g., 1% of account equity) and the instrument's ATR, a trader can take on similar levels of risk regardless of whether they are trading a volatile or a quiet instrument. -- **Caution:** ATR does not provide any information about trend direction. A high ATR could be present in a strong uptrend, a strong downtrend, or a volatile ranging market. It should always be used in conjunction with other trend or momentum indicators. diff --git a/Indicators/MyIndicators/ATR.mq5 b/Indicators/MyIndicators/ATR.mq5 deleted file mode 100644 index 8d05658..0000000 --- a/Indicators/MyIndicators/ATR.mq5 +++ /dev/null @@ -1,99 +0,0 @@ -//+------------------------------------------------------------------+ -//| ATR.mq5 | -//| Copyright 2025, xxxxxxxx | -//| | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property link "" -#property version "1.00" -#property description "Average True Range" - -//--- Indicator Window and Plot Properties --- -#property indicator_separate_window -#property indicator_buffers 1 -#property indicator_plots 1 - -//--- Plot 1: ATR line -#property indicator_label1 "ATR" -#property indicator_type1 DRAW_LINE -#property indicator_color1 clrDodgerBlue -#property indicator_style1 STYLE_SOLID -#property indicator_width1 1 - -//--- Input Parameters --- -input int InpAtrPeriod = 14; // ATR Period - -//--- Indicator Buffers --- -double BufferATR[]; - -//--- Global Variables --- -int g_ExtAtrPeriod; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - g_ExtAtrPeriod = (InpAtrPeriod < 1) ? 1 : InpAtrPeriod; - - SetIndexBuffer(0, BufferATR, INDICATOR_DATA); - ArraySetAsSeries(BufferATR, false); - - IndicatorSetInteger(INDICATOR_DIGITS, _Digits); - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, g_ExtAtrPeriod); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("ATR(%d)", g_ExtAtrPeriod)); - - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Average True Range 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_ExtAtrPeriod) - return(0); - -//--- STEP 1: Calculate True Range - double tr[]; - ArrayResize(tr, rates_total); - for(int i = 1; i < rates_total; i++) - { - double range1 = high[i] - low[i]; - double range2 = MathAbs(high[i] - close[i-1]); - double range3 = MathAbs(low[i] - close[i-1]); - tr[i] = MathMax(range1, MathMax(range2, range3)); - } - -//--- STEP 2: Calculate ATR (Wilder's Smoothing) - for(int i = 1; i < rates_total; i++) - { - if(i == g_ExtAtrPeriod) // Initialization with a simple average of TR - { - double sum_tr = 0; - for(int j = 1; j <= g_ExtAtrPeriod; j++) - { - sum_tr += tr[j]; - } - BufferATR[i] = sum_tr / g_ExtAtrPeriod; - } - else - if(i > g_ExtAtrPeriod) // Recursive calculation - { - BufferATR[i] = (BufferATR[i-1] * (g_ExtAtrPeriod - 1) + tr[i]) / g_ExtAtrPeriod; - } - } - - return(rates_total); - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/ATR_HeikinAshi.mq5 b/Indicators/MyIndicators/ATR_HeikinAshi.mq5 deleted file mode 100644 index 3809c95..0000000 --- a/Indicators/MyIndicators/ATR_HeikinAshi.mq5 +++ /dev/null @@ -1,131 +0,0 @@ -//+------------------------------------------------------------------+ -//| ATR_HeikinAshi.mq5 | -//| Copyright 2025, xxxxxxxx | -//| | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property link "" -#property version "1.00" -#property description "Average True Range on Heikin Ashi data" - -#include - -//--- Indicator Window and Plot Properties --- -#property indicator_separate_window -#property indicator_buffers 1 -#property indicator_plots 1 - -//--- Plot 1: ATR line -#property indicator_label1 "HA_ATR" -#property indicator_type1 DRAW_LINE -#property indicator_color1 clrDodgerBlue -#property indicator_style1 STYLE_SOLID -#property indicator_width1 1 - -//--- Input Parameters --- -input int InpAtrPeriod = 14; // ATR Period - -//--- Indicator Buffers --- -double BufferHA_ATR[]; - -//--- Global Objects and Variables --- -int g_ExtAtrPeriod; -CHeikinAshi_Calculator *g_ha_calculator; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - g_ExtAtrPeriod = (InpAtrPeriod < 1) ? 1 : InpAtrPeriod; - - SetIndexBuffer(0, BufferHA_ATR, INDICATOR_DATA); - ArraySetAsSeries(BufferHA_ATR, false); - - IndicatorSetInteger(INDICATOR_DIGITS, _Digits); - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, g_ExtAtrPeriod); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA_ATR(%d)", g_ExtAtrPeriod)); - - g_ha_calculator = new CHeikinAshi_Calculator(); - if(CheckPointer(g_ha_calculator) == POINTER_INVALID) - { - Print("Error creating CHeikinAshi_Calculator object"); - return(INIT_FAILED); - } - - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { - if(CheckPointer(g_ha_calculator) != POINTER_INVALID) - { - delete g_ha_calculator; - g_ha_calculator = NULL; - } - } - -//+------------------------------------------------------------------+ -//| Average True Range on Heikin 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 <= g_ExtAtrPeriod) - return(0); - -//--- Intermediate Heikin Ashi Buffers - double ha_open[], ha_high[], ha_low[], ha_close[]; - ArrayResize(ha_open, rates_total); - ArrayResize(ha_high, rates_total); - ArrayResize(ha_low, rates_total); - ArrayResize(ha_close, rates_total); - -//--- STEP 1: Calculate Heikin Ashi bars - g_ha_calculator.Calculate(rates_total, open, high, low, close, ha_open, ha_high, ha_low, ha_close); - -//--- STEP 2: Calculate Heikin Ashi True Range - double ha_tr[]; - ArrayResize(ha_tr, rates_total); - for(int i = 1; i < rates_total; i++) - { - double range1 = ha_high[i] - ha_low[i]; - double range2 = MathAbs(ha_high[i] - ha_close[i-1]); - double range3 = MathAbs(ha_low[i] - ha_close[i-1]); - ha_tr[i] = MathMax(range1, MathMax(range2, range3)); - } - -//--- STEP 3: Calculate ATR (Wilder's Smoothing) on HA_TR - for(int i = 1; i < rates_total; i++) - { - if(i == g_ExtAtrPeriod) // Initialization with a simple average of HA_TR - { - double sum_tr = 0; - for(int j = 1; j <= g_ExtAtrPeriod; j++) - { - sum_tr += ha_tr[j]; - } - BufferHA_ATR[i] = sum_tr / g_ExtAtrPeriod; - } - else - if(i > g_ExtAtrPeriod) // Recursive calculation - { - BufferHA_ATR[i] = (BufferHA_ATR[i-1] * (g_ExtAtrPeriod - 1) + ha_tr[i]) / g_ExtAtrPeriod; - } - } - - return(rates_total); - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/CCI.md b/Indicators/MyIndicators/CCI.md deleted file mode 100644 index ba1575a..0000000 --- a/Indicators/MyIndicators/CCI.md +++ /dev/null @@ -1,77 +0,0 @@ -# Commodity Channel Index (CCI) - -## 1. Summary (Introduction) - -The Commodity Channel Index (CCI) is a versatile momentum oscillator developed by Donald Lambert, first introduced in "Commodities" magazine in 1980. Despite its name, it is used effectively in any market, including stocks, forex, and futures. - -The CCI measures the current price level relative to an average price level over a specified period. It is designed to identify cyclical turns but is widely used to detect overbought and oversold conditions. High values indicate that the price is unusually high compared to its average, and low values indicate it is unusually low. - -The **CCI Oscillator** is a supplementary indicator that displays the difference between the main CCI line and its signal line as a histogram, providing a clearer visual of accelerating and decelerating momentum. - -## 2. Mathematical Foundations and Calculation Logic - -The CCI is based on the relationship between the price, its moving average, and the average deviation from that moving average. - -### Required Components - -- **Period (N):** The lookback period for all calculations (e.g., 20). -- **Source Price (P):** The price series used for the calculation. The classic definition uses the **Typical Price** `(High + Low + Close) / 3`. -- **Constant:** A statistical constant of `0.015` used to scale the result. - -### Calculation Steps (Algorithm) - -1. **Calculate the Source Price:** For each bar, calculate the source price (e.g., Typical Price). - $\text{P}_i = \frac{\text{High}_i + \text{Low}_i + \text{Close}_i}{3}$ - -2. **Calculate the Simple Moving Average (SMA):** Compute an `N`-period SMA of the source price. - $\text{SMA}_i = \text{SMA}(P, N)_i$ - -3. **Calculate the Mean Absolute Deviation (MAD):** For each bar, calculate the average absolute difference between the source price and its SMA over the `N` period. - $\text{MAD}_i = \frac{1}{N} \sum_{k=i-N+1}^{i} \text{Abs}(P_k - \text{SMA}_i)$ - -4. **Calculate the CCI Value:** Apply the final formula. - $\text{CCI}_i = \frac{P_i - \text{SMA}_i}{0.015 \times \text{MAD}_i}$ - -5. **Calculate the Signal Line & Oscillator:** The signal line is a moving average of the CCI line, and the oscillator is the difference between the two. - -## 3. MQL5 Implementation Details - -Our MQL5 toolkit includes two distinct standard implementations of the CCI, along with their Heikin Ashi counterparts and oscillator versions, to offer a choice between performance and perfect mathematical accuracy. - -- **Stability via Full Recalculation:** All versions employ a "brute-force" full recalculation within the `OnCalculate` function to ensure maximum stability. -- **Self-Contained Logic:** All versions are completely self-contained, with fully manual calculations for all components. -- **Optional Signal Line:** All line-based versions have been enhanced with an optional, user-configurable moving average signal line. - -### Our Two Calculation Methodologies - -1. **Efficient Version (`CCI.mq5`):** - - - **Concept:** A high-performance implementation suitable for most applications. - - **Logic:** This version uses an efficient **sliding window sum** technique to calculate both the SMA and the Mean Absolute Deviation (MAD). This is a very close approximation of the precise formula but avoids nested loops, making it significantly faster. - -2. **Precise Version (`CCI_Precise.mq5`):** - - **Concept:** A version that adheres strictly to the mathematical definition for maximum accuracy. - - **Logic:** This implementation uses nested `for` loops. For every single bar, it recalculates the precise SMA and then the precise MAD based on that SMA. - -### Indicator Family - -- **Line Versions:** `CCI.mq5` and `CCI_Precise.mq5` plot the CCI line and its signal line. -- **Oscillator Versions:** `CCI_Oscillator.mq5` and `CCI_Precise_Oscillator.mq5` plot the difference between the CCI and its signal line as a histogram. -- **Heikin Ashi Variants:** All four indicators have "pure" Heikin Ashi counterparts, which use smoothed Heikin Ashi price data as their input. - -## 4. Parameters - -- **CCI Period (`InpCCIPeriod`):** The lookback period for the SMA and MAD calculations. Common values are 14 or 20. -- **Applied Price (`InpAppliedPrice`):** The source price for the calculation. The classic and default is `PRICE_TYPICAL`. -- **Signal Line Settings:** - - `InpMAPeriod`: The lookback period for the optional signal line. - - `InpMAMethod`: The type of moving average for the signal line. - -## 5. Usage and Interpretation - -- **Overbought/Oversold Levels:** The primary use of the CCI is to identify extreme conditions. - - **Overbought:** Readings above **+100**. - - **Oversold:** Readings below **-100**. -- **Zero Line Crossovers:** A crossover of the CCI line above the zero line is a bullish signal; a crossover below zero is a bearish signal. -- **Divergence:** A powerful signal where price and the CCI move in opposite directions, often foreshadowing a reversal. -- **Oscillator (Histogram):** The histogram provides a clear visual of the relationship between the CCI and its signal line, highlighting the acceleration and deceleration of momentum. diff --git a/Indicators/MyIndicators/CCI.mq5 b/Indicators/MyIndicators/CCI.mq5 deleted file mode 100644 index d4fbd04..0000000 --- a/Indicators/MyIndicators/CCI.mq5 +++ /dev/null @@ -1,210 +0,0 @@ -//+------------------------------------------------------------------+ -//| CCI.mq5 | -//| Copyright 2025, xxxxxxxx | -//| | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property link "" -#property version "2.00" // Added selectable MA signal line -#property description "Commodity Channel Index with a signal line." - -//--- Indicator Window and Plot Properties --- -#property indicator_separate_window -#property indicator_buffers 2 // CCI and Signal Line -#property indicator_plots 2 -#property indicator_level1 -100.0 -#property indicator_level2 100.0 -#property indicator_level3 0.0 -#property indicator_levelstyle STYLE_DOT - -//--- Plot 1: CCI line -#property indicator_label1 "CCI" -#property indicator_type1 DRAW_LINE -#property indicator_color1 clrLightSeaGreen -#property indicator_style1 STYLE_SOLID -#property indicator_width1 1 - -//--- Plot 2: Signal line -#property indicator_label2 "Signal" -#property indicator_type2 DRAW_LINE -#property indicator_color2 clrOrangeRed -#property indicator_style2 STYLE_DOT -#property indicator_width2 1 - -//--- Input Parameters --- -input int InpCCIPeriod = 20; -input ENUM_APPLIED_PRICE InpAppliedPrice = PRICE_TYPICAL; -input group "Signal Line Settings" -input int InpMAPeriod = 14; -input ENUM_MA_METHOD InpMAMethod = MODE_SMA; - -//--- Indicator Buffers --- -double BufferCCI[]; -double BufferSignal[]; - -//--- Global Variables --- -int g_ExtCCIPeriod, g_ExtMAPeriod; -const double CCI_CONSTANT = 0.015; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - g_ExtCCIPeriod = (InpCCIPeriod < 1) ? 1 : InpCCIPeriod; - g_ExtMAPeriod = (InpMAPeriod < 1) ? 1 : InpMAPeriod; - - SetIndexBuffer(0, BufferCCI, INDICATOR_DATA); - SetIndexBuffer(1, BufferSignal, INDICATOR_DATA); - - ArraySetAsSeries(BufferCCI, false); - ArraySetAsSeries(BufferSignal, false); - - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, g_ExtCCIPeriod - 1); - PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, g_ExtCCIPeriod + g_ExtMAPeriod - 2); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("CCI(%d, %d)", g_ExtCCIPeriod, g_ExtMAPeriod)); - IndicatorSetInteger(INDICATOR_DIGITS, 2); - - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Commodity Channel 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[]) - { -// --- FIX: Correct the overall start position check --- - int start_pos = g_ExtCCIPeriod * 2 + g_ExtMAPeriod - 3; - if(rates_total <= start_pos) - return(0); - -//--- STEP 1: Prepare the source price array - double price_source[]; - ArrayResize(price_source, rates_total); - for(int i=0; i= g_ExtCCIPeriod) - { - sma_sum -= price_source[i - g_ExtCCIPeriod]; - } - if(i >= g_ExtCCIPeriod - 1) - { - buffer_sma[i] = sma_sum / g_ExtCCIPeriod; - } - } - -//--- STEP 3: Calculate the Mean Absolute Deviation (MAD) - double buffer_mad[]; - ArrayResize(buffer_mad, rates_total); - double deviation_sum = 0; - double abs_dev[]; - ArrayResize(abs_dev, rates_total); - for(int i = g_ExtCCIPeriod - 1; i < rates_total; i++) - { - abs_dev[i] = MathAbs(price_source[i] - buffer_sma[i]); - } - for(int i = g_ExtCCIPeriod - 1; i < rates_total; i++) - { - deviation_sum += abs_dev[i]; - if(i >= g_ExtCCIPeriod * 2 - 2) - { - if(i >= g_ExtCCIPeriod * 2 - 1) - { - deviation_sum -= abs_dev[i - g_ExtCCIPeriod]; - } - buffer_mad[i] = deviation_sum / g_ExtCCIPeriod; - } - } - -//--- STEP 4: Calculate the final CCI value - for(int i = g_ExtCCIPeriod * 2 - 2; i < rates_total; i++) - { - double mad_value = buffer_mad[i]; - if(mad_value > 0) - { - BufferCCI[i] = (price_source[i] - buffer_sma[i]) / (CCI_CONSTANT * mad_value); - } - } - -//--- STEP 5: Calculate the Signal Line (MA of CCI) -// --- FIX: Correct the starting position for the MA calculation --- - int ma_start_pos = g_ExtCCIPeriod * 2 + g_ExtMAPeriod - 3; - for(int i = ma_start_pos; i < rates_total; i++) - { - switch(InpMAMethod) - { - case MODE_EMA: - case MODE_SMMA: - if(i == ma_start_pos) - { - double sum=0; - for(int j=0; j0) - BufferSignal[i]=lwma_sum/weight_sum; - } - break; - default: // MODE_SMA - { - double sum=0; - for(int j=0; j - -//--- Indicator Window and Plot Properties --- -#property indicator_separate_window -#property indicator_buffers 2 // CCI and Signal Line -#property indicator_plots 2 -#property indicator_level1 -100.0 -#property indicator_level2 100.0 -#property indicator_level3 0.0 -#property indicator_levelstyle STYLE_DOT - -//--- Plot 1: CCI line -#property indicator_label1 "HA_CCI" -#property indicator_type1 DRAW_LINE -#property indicator_color1 clrLightSeaGreen -#property indicator_style1 STYLE_SOLID -#property indicator_width1 1 - -//--- Plot 2: Signal line -#property indicator_label2 "HA_Signal" -#property indicator_type2 DRAW_LINE -#property indicator_color2 clrOrangeRed -#property indicator_style2 STYLE_DOT -#property indicator_width2 1 - -//--- Enum for selecting Heikin Ashi price source --- -enum ENUM_HA_APPLIED_PRICE - { - HA_PRICE_TYPICAL, // (HA_H + HA_L + HA_C) / 3 - HA_PRICE_CLOSE, HA_PRICE_OPEN, HA_PRICE_HIGH, HA_PRICE_LOW - }; - -//--- Input Parameters --- -input int InpCCIPeriod = 20; -input ENUM_HA_APPLIED_PRICE InpAppliedPrice = HA_PRICE_TYPICAL; -input group "Signal Line Settings" -input int InpMAPeriod = 14; -input ENUM_MA_METHOD InpMAMethod = MODE_SMA; - -//--- Indicator Buffers --- -double BufferCCI[]; -double BufferSignal[]; - -//--- Global Objects and Variables --- -int g_ExtCCIPeriod, g_ExtMAPeriod; -const double CCI_CONSTANT = 0.015; -CHeikinAshi_Calculator *g_ha_calculator; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - g_ExtCCIPeriod = (InpCCIPeriod < 1) ? 1 : InpCCIPeriod; - g_ExtMAPeriod = (InpMAPeriod < 1) ? 1 : InpMAPeriod; - - SetIndexBuffer(0, BufferCCI, INDICATOR_DATA); - SetIndexBuffer(1, BufferSignal, INDICATOR_DATA); - - ArraySetAsSeries(BufferCCI, false); - ArraySetAsSeries(BufferSignal, false); - - int cci_draw_begin = g_ExtCCIPeriod * 2 - 2; - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, cci_draw_begin); - PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, cci_draw_begin + g_ExtMAPeriod - 1); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA_CCI(%d, %d)", g_ExtCCIPeriod, g_ExtMAPeriod)); - IndicatorSetInteger(INDICATOR_DIGITS, 2); - - g_ha_calculator = new CHeikinAshi_Calculator(); - if(CheckPointer(g_ha_calculator) == POINTER_INVALID) - { - Print("Error creating CHeikinAshi_Calculator object"); - return(INIT_FAILED); - } - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { - if(CheckPointer(g_ha_calculator) != POINTER_INVALID) - { - delete g_ha_calculator; - g_ha_calculator = NULL; - } - } - -//+------------------------------------------------------------------+ -//| CCI on Heikin 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[]) - { - int start_pos = g_ExtCCIPeriod * 2 + g_ExtMAPeriod - 2; - if(rates_total <= start_pos) - return(0); - -//--- Intermediate Heikin Ashi Buffers - double ha_open[], ha_high[], ha_low[], ha_close[]; - ArrayResize(ha_open, rates_total); - ArrayResize(ha_high, rates_total); - ArrayResize(ha_low, rates_total); - ArrayResize(ha_close, rates_total); - -//--- STEP 1: Calculate Heikin Ashi bars - g_ha_calculator.Calculate(rates_total, open, high, low, close, ha_open, ha_high, ha_low, ha_close); - -//--- STEP 2: Prepare the Heikin Ashi source price array - double ha_price_source[]; - ArrayResize(ha_price_source, rates_total); - for(int i=0; i= g_ExtCCIPeriod) - { - sma_sum -= ha_price_source[i - g_ExtCCIPeriod]; - } - if(i >= g_ExtCCIPeriod - 1) - { - buffer_sma[i] = sma_sum / g_ExtCCIPeriod; - } - } - -//--- STEP 4: Calculate the Mean Absolute Deviation (MAD) on HA data - double buffer_mad[]; - ArrayResize(buffer_mad, rates_total); - double deviation_sum = 0; - double abs_dev[]; - ArrayResize(abs_dev, rates_total); - for(int i = g_ExtCCIPeriod - 1; i < rates_total; i++) - { - abs_dev[i] = MathAbs(ha_price_source[i] - buffer_sma[i]); - } - for(int i = g_ExtCCIPeriod - 1; i < rates_total; i++) - { - deviation_sum += abs_dev[i]; - if(i >= g_ExtCCIPeriod * 2 - 2) - { - if(i >= g_ExtCCIPeriod * 2 - 1) - { - deviation_sum -= abs_dev[i - g_ExtCCIPeriod]; - } - buffer_mad[i] = deviation_sum / g_ExtCCIPeriod; - } - } - -//--- STEP 5: Calculate the final CCI value - for(int i = g_ExtCCIPeriod * 2 - 2; i < rates_total; i++) - { - double mad_value = buffer_mad[i]; - if(mad_value > 0) - { - BufferCCI[i] = (ha_price_source[i] - buffer_sma[i]) / (CCI_CONSTANT * mad_value); - } - } - -//--- STEP 6: Calculate the Signal Line (MA of CCI) - int ma_start_pos = g_ExtCCIPeriod * 2 + g_ExtMAPeriod - 3; - for(int i = ma_start_pos; i < rates_total; i++) - { - switch(InpMAMethod) - { - case MODE_EMA: - case MODE_SMMA: - if(i == ma_start_pos) - { - double sum=0; - for(int j=0; j0) - BufferSignal[i]=lwma_sum/weight_sum; - } - break; - default: // MODE_SMA - { - double sum=0; - for(int j=0; j= g_ExtCCIPeriod) - sma_sum -= price_source[i - g_ExtCCIPeriod]; - if(i >= g_ExtCCIPeriod - 1) - buffer_sma[i] = sma_sum / g_ExtCCIPeriod; - } - - double buffer_mad[]; - ArrayResize(buffer_mad, rates_total); - double deviation_sum = 0; - double abs_dev[]; - ArrayResize(abs_dev, rates_total); - for(int i = g_ExtCCIPeriod - 1; i < rates_total; i++) - abs_dev[i] = MathAbs(price_source[i] - buffer_sma[i]); - - for(int i = g_ExtCCIPeriod - 1; i < rates_total; i++) - { - deviation_sum += abs_dev[i]; - if(i >= g_ExtCCIPeriod * 2 - 2) - { - if(i >= g_ExtCCIPeriod * 2 - 1) - deviation_sum -= abs_dev[i - g_ExtCCIPeriod]; - buffer_mad[i] = deviation_sum / g_ExtCCIPeriod; - } - } - - for(int i = g_ExtCCIPeriod * 2 - 2; i < rates_total; i++) - { - if(buffer_mad[i] > 0) - buffer_cci[i] = (price_source[i] - buffer_sma[i]) / (CCI_CONSTANT * buffer_mad[i]); - } - } - -//--- STEP 2: Calculate the Signal Line (MA of CCI) --- - int ma_start_pos = g_ExtCCIPeriod * 2 + g_ExtMAPeriod - 3; - for(int i = ma_start_pos; i < rates_total; i++) - { - switch(InpMAMethod) - { - case MODE_EMA: - case MODE_SMMA: - if(i == ma_start_pos) - { - double sum=0; - for(int j=0; j0) - buffer_signal[i]=lwma_sum/weight_sum; - } - break; - default: // MODE_SMA - { - double sum=0; - for(int j=0; j - -//--- Indicator Window and Plot Properties --- -#property indicator_separate_window -#property indicator_buffers 1 -#property indicator_plots 1 -#property indicator_type1 DRAW_HISTOGRAM -#property indicator_color1 clrSilver -#property indicator_width1 1 -#property indicator_label1 "HA_CCI_Osc" -#property indicator_level1 0.0 -#property indicator_levelstyle STYLE_DOT - -//--- Enum for selecting Heikin Ashi price source --- -enum ENUM_HA_APPLIED_PRICE - { - HA_PRICE_TYPICAL, // (HA_H + HA_L + HA_C) / 3 - HA_PRICE_CLOSE, HA_PRICE_OPEN, HA_PRICE_HIGH, HA_PRICE_LOW - }; - -//--- Input Parameters --- -input int InpCCIPeriod = 20; -input ENUM_HA_APPLIED_PRICE InpAppliedPrice = HA_PRICE_TYPICAL; -input group "Signal Line Settings" -input int InpMAPeriod = 14; -input ENUM_MA_METHOD InpMAMethod = MODE_SMA; - -//--- Indicator Buffers --- -double BufferOscillator[]; - -//--- Global Objects and Variables --- -int g_ExtCCIPeriod, g_ExtMAPeriod; -const double CCI_CONSTANT = 0.015; -CHeikinAshi_Calculator *g_ha_calculator; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - g_ExtCCIPeriod = (InpCCIPeriod < 1) ? 1 : InpCCIPeriod; - g_ExtMAPeriod = (InpMAPeriod < 1) ? 1 : InpMAPeriod; - - SetIndexBuffer(0, BufferOscillator, INDICATOR_DATA); - ArraySetAsSeries(BufferOscillator, false); - - int cci_draw_begin = g_ExtCCIPeriod * 2 - 2; - int draw_begin = cci_draw_begin + g_ExtMAPeriod - 1; - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, draw_begin); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA_CCI_Osc(%d, %d)", g_ExtCCIPeriod, g_ExtMAPeriod)); - IndicatorSetInteger(INDICATOR_DIGITS, 2); - - g_ha_calculator = new CHeikinAshi_Calculator(); - if(CheckPointer(g_ha_calculator) == POINTER_INVALID) - { - Print("Error creating CHeikinAshi_Calculator object"); - return(INIT_FAILED); - } - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { - if(CheckPointer(g_ha_calculator) != POINTER_INVALID) - { - delete g_ha_calculator; - g_ha_calculator = NULL; - } - } - -//+------------------------------------------------------------------+ -//| CCI Oscillator on Heikin 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[]) - { - int start_pos = g_ExtCCIPeriod * 2 + g_ExtMAPeriod - 2; - if(rates_total <= start_pos) - return(0); - -//--- Internal Buffers for calculation --- - double buffer_cci[], buffer_signal[]; - ArrayResize(buffer_cci, rates_total); - ArrayResize(buffer_signal, rates_total); - -//--- STEP 1: Calculate Heikin Ashi CCI internally --- - { - double ha_open[], ha_high[], ha_low[], ha_close[]; - ArrayResize(ha_open, rates_total); - ArrayResize(ha_high, rates_total); - ArrayResize(ha_low, rates_total); - ArrayResize(ha_close, rates_total); - g_ha_calculator.Calculate(rates_total, open, high, low, close, ha_open, ha_high, ha_low, ha_close); - - double ha_price_source[]; - ArrayResize(ha_price_source, rates_total); - for(int i=0; i= g_ExtCCIPeriod) - sma_sum -= ha_price_source[i - g_ExtCCIPeriod]; - if(i >= g_ExtCCIPeriod - 1) - buffer_sma[i] = sma_sum / g_ExtCCIPeriod; - } - - double buffer_mad[]; - ArrayResize(buffer_mad, rates_total); - double deviation_sum = 0; - double abs_dev[]; - ArrayResize(abs_dev, rates_total); - for(int i = g_ExtCCIPeriod - 1; i < rates_total; i++) - abs_dev[i] = MathAbs(ha_price_source[i] - buffer_sma[i]); - - for(int i = g_ExtCCIPeriod - 1; i < rates_total; i++) - { - deviation_sum += abs_dev[i]; - if(i >= g_ExtCCIPeriod * 2 - 2) - { - if(i >= g_ExtCCIPeriod * 2 - 1) - deviation_sum -= abs_dev[i - g_ExtCCIPeriod]; - buffer_mad[i] = deviation_sum / g_ExtCCIPeriod; - } - } - - for(int i = g_ExtCCIPeriod * 2 - 2; i < rates_total; i++) - { - if(buffer_mad[i] > 0) - buffer_cci[i] = (ha_price_source[i] - buffer_sma[i]) / (CCI_CONSTANT * buffer_mad[i]); - } - } - -//--- STEP 2: Calculate the Signal Line (MA of CCI) --- - int ma_start_pos = g_ExtCCIPeriod * 2 + g_ExtMAPeriod - 3; - for(int i = ma_start_pos; i < rates_total; i++) - { - switch(InpMAMethod) - { - case MODE_EMA: - case MODE_SMMA: - if(i == ma_start_pos) - { - double sum=0; - for(int j=0; j0) - buffer_signal[i]=lwma_sum/weight_sum; - } - break; - default: // MODE_SMA - { - double sum=0; - for(int j=0; j 0) - { - BufferCCI[i] = (price_source[i] - sma) / (CCI_CONSTANT * mad); - } - } - -//--- STEP 3: Calculate the Signal Line (MA of CCI) - int ma_start_pos = g_ExtCCIPeriod + g_ExtMAPeriod - 2; - for(int i = ma_start_pos; i < rates_total; i++) - { - switch(InpMAMethod) - { - case MODE_EMA: - case MODE_SMMA: - if(i == ma_start_pos) - { - double sum=0; - for(int j=0; j0) - BufferSignal[i]=lwma_sum/weight_sum; - } - break; - default: // MODE_SMA - { - double sum=0; - for(int j=0; j - -//--- Indicator Window and Plot Properties --- -#property indicator_separate_window -#property indicator_buffers 2 // CCI and Signal Line -#property indicator_plots 2 -#property indicator_level1 -100.0 -#property indicator_level2 100.0 -#property indicator_level3 0.0 -#property indicator_levelstyle STYLE_DOT - -//--- Plot 1: CCI line -#property indicator_label1 "HA_CCI" -#property indicator_type1 DRAW_LINE -#property indicator_color1 clrLightSeaGreen -#property indicator_style1 STYLE_SOLID -#property indicator_width1 1 - -//--- Plot 2: Signal line -#property indicator_label2 "HA_Signal" -#property indicator_type2 DRAW_LINE -#property indicator_color2 clrOrangeRed -#property indicator_style2 STYLE_DOT -#property indicator_width2 1 - -//--- Enum for selecting Heikin Ashi price source --- -enum ENUM_HA_APPLIED_PRICE - { - HA_PRICE_TYPICAL, // (HA_H + HA_L + HA_C) / 3 - HA_PRICE_CLOSE, HA_PRICE_OPEN, HA_PRICE_HIGH, HA_PRICE_LOW - }; - -//--- Input Parameters --- -input int InpCCIPeriod = 20; -input ENUM_HA_APPLIED_PRICE InpAppliedPrice = HA_PRICE_TYPICAL; -input group "Signal Line Settings" -input int InpMAPeriod = 14; -input ENUM_MA_METHOD InpMAMethod = MODE_SMA; - -//--- Indicator Buffers --- -double BufferCCI[]; -double BufferSignal[]; - -//--- Global Objects and Variables --- -int g_ExtCCIPeriod, g_ExtMAPeriod; -const double CCI_CONSTANT = 0.015; -CHeikinAshi_Calculator *g_ha_calculator; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - g_ExtCCIPeriod = (InpCCIPeriod < 1) ? 1 : InpCCIPeriod; - g_ExtMAPeriod = (InpMAPeriod < 1) ? 1 : InpMAPeriod; - - SetIndexBuffer(0, BufferCCI, INDICATOR_DATA); - SetIndexBuffer(1, BufferSignal, INDICATOR_DATA); - - ArraySetAsSeries(BufferCCI, false); - ArraySetAsSeries(BufferSignal, false); - - int cci_draw_begin = g_ExtCCIPeriod - 1; - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, cci_draw_begin); - PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, cci_draw_begin + g_ExtMAPeriod - 1); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA_CCI_Precise(%d, %d)", g_ExtCCIPeriod, g_ExtMAPeriod)); - IndicatorSetInteger(INDICATOR_DIGITS, 2); - - g_ha_calculator = new CHeikinAshi_Calculator(); - if(CheckPointer(g_ha_calculator) == POINTER_INVALID) - { - Print("Error creating CHeikinAshi_Calculator object"); - return(INIT_FAILED); - } - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { - if(CheckPointer(g_ha_calculator) != POINTER_INVALID) - { - delete g_ha_calculator; - g_ha_calculator = NULL; - } - } - -//+------------------------------------------------------------------+ -//| CCI Precise on Heikin 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[]) - { - int start_pos = g_ExtCCIPeriod + g_ExtMAPeriod - 1; - if(rates_total < start_pos) - return(0); - -//--- Intermediate Heikin Ashi Buffers - double ha_open[], ha_high[], ha_low[], ha_close[]; - ArrayResize(ha_open, rates_total); - ArrayResize(ha_high, rates_total); - ArrayResize(ha_low, rates_total); - ArrayResize(ha_close, rates_total); - -//--- STEP 1: Calculate Heikin Ashi bars - g_ha_calculator.Calculate(rates_total, open, high, low, close, ha_open, ha_high, ha_low, ha_close); - -//--- STEP 2: Prepare the Heikin Ashi source price array - double ha_price_source[]; - ArrayResize(ha_price_source, rates_total); - for(int i=0; i 0) - { - BufferCCI[i] = (ha_price_source[i] - sma) / (CCI_CONSTANT * mad); - } - } - -//--- STEP 4: Calculate the Signal Line (MA of CCI) - int ma_start_pos = g_ExtCCIPeriod + g_ExtMAPeriod - 2; - for(int i = ma_start_pos; i < rates_total; i++) - { - switch(InpMAMethod) - { - case MODE_EMA: - case MODE_SMMA: - if(i == ma_start_pos) - { - double sum=0; - for(int j=0; j0) - BufferSignal[i]=lwma_sum/weight_sum; - } - break; - default: // MODE_SMA - { - double sum=0; - for(int j=0; j 0) - buffer_cci[i] = (price_source[i] - sma) / (CCI_CONSTANT * mad); - } - } - -//--- STEP 2: Calculate the Signal Line (MA of CCI) --- - int ma_start_pos = g_ExtCCIPeriod + g_ExtMAPeriod - 2; - for(int i = ma_start_pos; i < rates_total; i++) - { - switch(InpMAMethod) - { - case MODE_EMA: - case MODE_SMMA: - if(i == ma_start_pos) - { - double sum=0; - for(int j=0; j0) - buffer_signal[i]=lwma_sum/weight_sum; - } - break; - default: // MODE_SMA - { - double sum=0; - for(int j=0; j - -//--- Indicator Window and Plot Properties --- -#property indicator_separate_window -#property indicator_buffers 1 -#property indicator_plots 1 -#property indicator_type1 DRAW_HISTOGRAM -#property indicator_color1 clrSilver -#property indicator_width1 1 -#property indicator_label1 "HA_CCI_Osc_Precise" -#property indicator_level1 0.0 -#property indicator_levelstyle STYLE_DOT - -//--- Enum for selecting Heikin Ashi price source --- -enum ENUM_HA_APPLIED_PRICE - { - HA_PRICE_TYPICAL, // (HA_H + HA_L + HA_C) / 3 - HA_PRICE_CLOSE, HA_PRICE_OPEN, HA_PRICE_HIGH, HA_PRICE_LOW - }; - -//--- Input Parameters --- -input int InpCCIPeriod = 20; -input ENUM_HA_APPLIED_PRICE InpAppliedPrice = HA_PRICE_TYPICAL; -input group "Signal Line Settings" -input int InpMAPeriod = 14; -input ENUM_MA_METHOD InpMAMethod = MODE_SMA; - -//--- Indicator Buffers --- -double BufferOscillator[]; - -//--- Global Objects and Variables --- -int g_ExtCCIPeriod, g_ExtMAPeriod; -const double CCI_CONSTANT = 0.015; -CHeikinAshi_Calculator *g_ha_calculator; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - g_ExtCCIPeriod = (InpCCIPeriod < 1) ? 1 : InpCCIPeriod; - g_ExtMAPeriod = (InpMAPeriod < 1) ? 1 : InpMAPeriod; - - SetIndexBuffer(0, BufferOscillator, INDICATOR_DATA); - ArraySetAsSeries(BufferOscillator, false); - - int cci_draw_begin = g_ExtCCIPeriod - 1; - int draw_begin = cci_draw_begin + g_ExtMAPeriod - 1; - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, draw_begin); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA_CCI_Osc_Precise(%d, %d)", g_ExtCCIPeriod, g_ExtMAPeriod)); - IndicatorSetInteger(INDICATOR_DIGITS, 2); - - g_ha_calculator = new CHeikinAshi_Calculator(); - if(CheckPointer(g_ha_calculator) == POINTER_INVALID) - { - Print("Error creating CHeikinAshi_Calculator object"); - return(INIT_FAILED); - } - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { - if(CheckPointer(g_ha_calculator) != POINTER_INVALID) - { - delete g_ha_calculator; - g_ha_calculator = NULL; - } - } - -//+------------------------------------------------------------------+ -//| CCI Oscillator (Precise) on Heikin 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[]) - { - int start_pos = g_ExtCCIPeriod + g_ExtMAPeriod - 1; - if(rates_total < start_pos) - return(0); - -//--- Internal Buffers for calculation --- - double buffer_cci[], buffer_signal[]; - ArrayResize(buffer_cci, rates_total); - ArrayResize(buffer_signal, rates_total); - -//--- STEP 1: Calculate Heikin Ashi CCI internally --- - { - double ha_open[], ha_high[], ha_low[], ha_close[]; - ArrayResize(ha_open, rates_total); - ArrayResize(ha_high, rates_total); - ArrayResize(ha_low, rates_total); - ArrayResize(ha_close, rates_total); - g_ha_calculator.Calculate(rates_total, open, high, low, close, ha_open, ha_high, ha_low, ha_close); - - double ha_price_source[]; - ArrayResize(ha_price_source, rates_total); - for(int i=0; i 0) - buffer_cci[i] = (ha_price_source[i] - sma) / (CCI_CONSTANT * mad); - } - } - -//--- STEP 2: Calculate the Signal Line (MA of CCI) --- - int ma_start_pos = g_ExtCCIPeriod + g_ExtMAPeriod - 2; - for(int i = ma_start_pos; i < rates_total; i++) - { - switch(InpMAMethod) - { - case MODE_EMA: - case MODE_SMMA: - if(i == ma_start_pos) - { - double sum=0; - for(int j=0; j0) - buffer_signal[i]=lwma_sum/weight_sum; - } - break; - default: // MODE_SMA - { - double sum=0; - for(int j=0; j ADL -> EMAs -> CHO) remains stable and accurate. - -- **Self-Contained Logic:** The indicator is completely self-contained and does not use any external handles (like `iAD`). All calculations, including the underlying ADL and the subsequent moving averages, are performed manually within the `OnCalculate` function. - -- **Flexible MA Types:** While the classic CHO uses EMAs, our "Pro" version allows the user to select from four different moving average types (**SMA, EMA, SMMA, LWMA**) via the `InpMaMethod` input parameter, providing greater flexibility. - -- **Robust MA Calculations:** All moving average calculations are performed manually to ensure 100% accuracy and consistency within our `non-timeseries` model. Recursive MA types (EMA, SMMA) are carefully initialized with a manual Simple Moving Average (SMA) to prevent floating-point overflows. - -- **Heikin Ashi Variant (`CHO_HeikinAshi.mq5`):** - - Our toolkit also includes a "pure" Heikin Ashi version. The calculation logic is identical, but the underlying ADL is calculated from the smoothed Heikin Ashi `ha_high`, `ha_low`, and `ha_close` values. - - This results in a significantly smoother oscillator that filters out price noise and can provide clearer signals regarding the momentum of the underlying Heikin Ashi trend. - -## 4. Parameters - -- **Fast Period (`InpFastPeriod`):** The period for the shorter-term MA of the ADL. Default is `3`. -- **Slow Period (`InpSlowPeriod`):** The period for the longer-term MA of the ADL. Default is `10`. -- **MA Method (`InpMaMethod`):** The type of moving average to use for the Fast and Slow MAs. Default is `MODE_EMA`. -- **Volume Type (`InpVolumeType`):** Allows the user to select between Tick Volume and Real Volume. - -## 5. Usage and Interpretation - -- **Zero Line Crossovers:** This is the most direct signal from the CHO. - - **Bullish Crossover:** When the oscillator crosses above the zero line, it indicates that buying pressure (accumulation) is strengthening. This can be used to confirm an uptrend or a bullish reversal. - - **Bearish Crossover:** When the oscillator crosses below the zero line, it indicates that selling pressure (distribution) is strengthening. This can confirm a downtrend or a bearish reversal. -- **Divergence:** This is the CHO's most powerful signal. - - **Bullish Divergence:** Price makes a lower low, but the CHO makes a higher low. This suggests that selling pressure is waning despite the lower price, often foreshadowing a bottom. - - **Bearish Divergénce:** Price makes a higher high, but the CHO makes a lower high. This suggests that the rally is not supported by strong buying pressure and may be nearing exhaustion. -- **Caution:** The Chaikin Oscillator is a momentum indicator, not a trend indicator. It should be used in conjunction with price action analysis or trend-following tools to confirm signals and avoid trading against the primary trend. diff --git a/Indicators/MyIndicators/CHO.mq5 b/Indicators/MyIndicators/CHO.mq5 deleted file mode 100644 index c4f4451..0000000 --- a/Indicators/MyIndicators/CHO.mq5 +++ /dev/null @@ -1,210 +0,0 @@ -//+------------------------------------------------------------------+ -//| CHO.mq5 | -//| Copyright 2025, xxxxxxxx | -//| | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property link "" -#property version "1.01" // Added selectable MA Method -#property description "Chaikin Oscillator with selectable MA type" - -//--- Indicator Window and Plot Properties --- -#property indicator_separate_window -#property indicator_buffers 4 // CHO, ADL, FastMA, SlowMA -#property indicator_plots 1 -#property indicator_type1 DRAW_LINE -#property indicator_color1 clrLightSeaGreen -#property indicator_label1 "CHO" -#property indicator_level1 0.0 -#property indicator_levelstyle STYLE_DOT - -//--- Input Parameters --- -input int InpFastPeriod = 3; -input int InpSlowPeriod = 10; -input ENUM_MA_METHOD InpMaMethod = MODE_EMA; -input ENUM_APPLIED_VOLUME InpVolumeType = VOLUME_TICK; - -//--- Indicator Buffers --- -double BufferCHO[]; -double BufferADL[]; -double BufferFastMA[]; -double BufferSlowMA[]; - -//--- Global Variables --- -int g_ExtFastPeriod, g_ExtSlowPeriod; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - g_ExtFastPeriod = (InpFastPeriod < 1) ? 1 : InpFastPeriod; - g_ExtSlowPeriod = (InpSlowPeriod < 1) ? 1 : InpSlowPeriod; - - if(g_ExtFastPeriod > g_ExtSlowPeriod) - { - int temp = g_ExtFastPeriod; - g_ExtFastPeriod = g_ExtSlowPeriod; - g_ExtSlowPeriod = temp; - } - - SetIndexBuffer(0, BufferCHO, INDICATOR_DATA); - SetIndexBuffer(1, BufferADL, INDICATOR_CALCULATIONS); - SetIndexBuffer(2, BufferFastMA, INDICATOR_CALCULATIONS); - SetIndexBuffer(3, BufferSlowMA, INDICATOR_CALCULATIONS); - - ArraySetAsSeries(BufferCHO, false); - ArraySetAsSeries(BufferADL, false); - ArraySetAsSeries(BufferFastMA, false); - ArraySetAsSeries(BufferSlowMA, false); - - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, g_ExtSlowPeriod - 1); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("CHO(%d,%d)", g_ExtFastPeriod, g_ExtSlowPeriod)); - IndicatorSetInteger(INDICATOR_DIGITS, 0); - - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Chaikin Oscillator 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_ExtSlowPeriod) - return(0); - -//--- STEP 1: Calculate Accumulation/Distribution Line (ADL) - for(int i = 0; i < rates_total; i++) - { - double mfm = 0; - double range = high[i] - low[i]; - if(range > 0) - { - mfm = ((close[i] - low[i]) - (high[i] - close[i])) / range; - } - long current_volume = (InpVolumeType == VOLUME_TICK) ? tick_volume[i] : volume[i]; - double mfv = mfm * current_volume; - - if(i > 0) - BufferADL[i] = BufferADL[i-1] + mfv; - else - BufferADL[i] = mfv; - } - -//--- STEP 2: Calculate Fast MA on ADL - for(int i = g_ExtFastPeriod - 1; i < rates_total; i++) - { - switch(InpMaMethod) - { - case MODE_EMA: - case MODE_SMMA: - if(i == g_ExtFastPeriod - 1) - { - double sum=0; - for(int j=0; j0) - BufferFastMA[i]=lwma_sum/weight_sum; - } - break; - default: // MODE_SMA - { - double sum=0; - for(int j=0; j0) - BufferSlowMA[i]=lwma_sum/weight_sum; - } - break; - default: // MODE_SMA - { - double sum=0; - for(int j=0; j - -//--- Indicator Window and Plot Properties --- -#property indicator_separate_window -#property indicator_buffers 4 // CHO, ADL, FastMA, SlowMA -#property indicator_plots 1 -#property indicator_type1 DRAW_LINE -#property indicator_color1 clrLightSeaGreen -#property indicator_label1 "HA_CHO" -#property indicator_level1 0.0 -#property indicator_levelstyle STYLE_DOT - -//--- Input Parameters --- -input int InpFastPeriod = 3; -input int InpSlowPeriod = 10; -input ENUM_MA_METHOD InpMaMethod = MODE_EMA; -input ENUM_APPLIED_VOLUME InpVolumeType = VOLUME_TICK; - -//--- Indicator Buffers --- -double BufferCHO[]; -double BufferADL[]; -double BufferFastMA[]; -double BufferSlowMA[]; - -//--- Global Objects and Variables --- -int g_ExtFastPeriod, g_ExtSlowPeriod; -CHeikinAshi_Calculator *g_ha_calculator; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - g_ExtFastPeriod = (InpFastPeriod < 1) ? 1 : InpFastPeriod; - g_ExtSlowPeriod = (InpSlowPeriod < 1) ? 1 : InpSlowPeriod; - - if(g_ExtFastPeriod > g_ExtSlowPeriod) - { - int temp = g_ExtFastPeriod; - g_ExtFastPeriod = g_ExtSlowPeriod; - g_ExtSlowPeriod = temp; - } - - SetIndexBuffer(0, BufferCHO, INDICATOR_DATA); - SetIndexBuffer(1, BufferADL, INDICATOR_CALCULATIONS); - SetIndexBuffer(2, BufferFastMA, INDICATOR_CALCULATIONS); - SetIndexBuffer(3, BufferSlowMA, INDICATOR_CALCULATIONS); - - ArraySetAsSeries(BufferCHO, false); - ArraySetAsSeries(BufferADL, false); - ArraySetAsSeries(BufferFastMA, false); - ArraySetAsSeries(BufferSlowMA, false); - - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, g_ExtSlowPeriod - 1); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA_CHO(%d,%d)", g_ExtFastPeriod, g_ExtSlowPeriod)); - IndicatorSetInteger(INDICATOR_DIGITS, 0); - - g_ha_calculator = new CHeikinAshi_Calculator(); - if(CheckPointer(g_ha_calculator) == POINTER_INVALID) - { - Print("Error creating CHeikinAshi_Calculator object"); - return(INIT_FAILED); - } - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { - if(CheckPointer(g_ha_calculator) != POINTER_INVALID) - { - delete g_ha_calculator; - g_ha_calculator = NULL; - } - } - -//+------------------------------------------------------------------+ -//| Chaikin Oscillator on Heikin 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 < g_ExtSlowPeriod) - return(0); - -//--- Intermediate Heikin Ashi Buffers - double ha_open[], ha_high[], ha_low[], ha_close[]; - ArrayResize(ha_open, rates_total); - ArrayResize(ha_high, rates_total); - ArrayResize(ha_low, rates_total); - ArrayResize(ha_close, rates_total); - -//--- STEP 1: Calculate Heikin Ashi bars - g_ha_calculator.Calculate(rates_total, open, high, low, close, ha_open, ha_high, ha_low, ha_close); - -//--- STEP 2: Calculate Accumulation/Distribution Line (ADL) on HA data - for(int i = 0; i < rates_total; i++) - { - double mfm = 0; - double range = ha_high[i] - ha_low[i]; - if(range > 0) - { - mfm = ((ha_close[i] - ha_low[i]) - (ha_high[i] - ha_close[i])) / range; - } - long current_volume = (InpVolumeType == VOLUME_TICK) ? tick_volume[i] : volume[i]; - double mfv = mfm * current_volume; - - if(i > 0) - BufferADL[i] = BufferADL[i-1] + mfv; - else - BufferADL[i] = mfv; - } - -//--- STEP 3: Calculate Fast MA on ADL - for(int i = g_ExtFastPeriod - 1; i < rates_total; i++) - { - switch(InpMaMethod) - { - case MODE_EMA: - case MODE_SMMA: - if(i == g_ExtFastPeriod - 1) - { - double sum=0; - for(int j=0; j0) - BufferFastMA[i]=lwma_sum/weight_sum; - } - break; - default: // MODE_SMA - { - double sum=0; - for(int j=0; j0) - BufferSlowMA[i]=lwma_sum/weight_sum; - } - break; - default: // MODE_SMA - { - double sum=0; - for(int j=0; j 0$, then $\text{Positive Change}_i = \text{Change}_i$ and $\text{Negative Change}_i = 0$. - - If $\text{Change}_i < 0$, then $\text{Positive Change}_i = 0$ and $\text{Negative Change}_i = \text{Abs}(\text{Change}_i)$. - -3. **Calculate the Simple Moving Average of Changes:** This is the defining step. Apply an SMA with period `N` to both the positive and negative change series. - $\text{Avg Positive}_i = \text{SMA}(\text{Positive Change}, N)_i$ - $\text{Avg Negative}_i = \text{SMA}(\text{Negative Change}, N)_i$ - -4. **Calculate the Relative Strength (RS) and Final RSI:** - $\text{RS}_i = \frac{\text{Avg Positive}_i}{\text{Avg Negative}_i}$ - $\text{Cutler's RSI}_i = 100 - \frac{100}{1 + \text{RS}_i}$ - -5. **Calculate the Signal Line & Oscillator:** The signal line is a moving average of the Cutler's RSI line, and the oscillator is the difference between the two. - -## 3. MQL5 Implementation Details - -Our MQL5 implementations were refactored for maximum stability, clarity, and computational efficiency. - -- **Stability via Full Recalculation:** We employ a "brute-force" full recalculation within the `OnCalculate` function for maximum stability. - -- **Efficient RSI Calculation:** Instead of using multiple loops or inefficient `SimpleMA` calls on every bar, we calculate the Cutler's RSI in a single `for` loop using an efficient **sliding window sum** technique. This is mathematically equivalent to an SMA but significantly faster. - -- **Self-Contained Logic:** The indicators are completely self-contained. They do not use external handles and directly process the price arrays provided by `OnCalculate`. - -- **Fully Manual MA Calculations:** To guarantee 100% accuracy and consistency, all moving average calculations for the signal line (**SMA, EMA, SMMA, LWMA**) are performed **manually**. This makes the indicators independent of the `` library and ensures robust behavior on `non-timeseries` arrays. - -- **Indicator Family:** - - **Line Versions:** `CutlerRSI_MA.mq5` plots the RSI line and its signal line. - - **Oscillator Versions:** `CutlerRSI_Oscillator.mq5` plots the difference between the two lines as a histogram. - - **Heikin Ashi Variants:** Both indicators have "pure" Heikin Ashi counterparts, which use the smoothed Heikin Ashi `ha_close` values as their input. - -## 4. Parameters - -- **RSI Period (`InpPeriodRSI`):** The lookback period for the SMA of price changes. Default is `14`. -- **Applied Price (`InpAppliedPrice`):** The source price for the calculation. Default is `PRICE_CLOSE`. -- **Signal Line Settings:** - - `InpPeriodMA`: The lookback period for the optional signal line. - - `InpMethodMA`: The type of moving average for the signal line. - -## 5. Usage and Interpretation - -The interpretation of Cutler's RSI is identical to the standard RSI. - -- **Overbought/Oversold Levels:** The primary use is to identify overbought (typically above 70) and oversold (typically below 30) conditions. -- **Crossovers:** - - **Signal Line Crossover:** When the Cutler's RSI line crosses above its moving average, it can be seen as a bullish signal. A cross below is a bearish signal. - - **Centerline Crossover:** A crossover of the RSI line above the 50 level indicates that momentum is shifting to bullish. A crossover below 50 indicates bearish momentum. -- **Divergence:** Look for divergences between the RSI and the price action. -- **Oscillator (Histogram):** The histogram provides a clear visual of the relationship between the Cutler's RSI and its signal line, highlighting the acceleration and deceleration of momentum. diff --git a/Indicators/MyIndicators/CutlerRSI_MA.mq5 b/Indicators/MyIndicators/CutlerRSI_MA.mq5 deleted file mode 100644 index 187ddaf..0000000 --- a/Indicators/MyIndicators/CutlerRSI_MA.mq5 +++ /dev/null @@ -1,220 +0,0 @@ -//+------------------------------------------------------------------+ -//| CutlerRSI_MA.mq5 | -//| Copyright 2025, xxxxxxxx | -//| | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property link "" -#property version "2.00" // Refactored for stability and efficiency -#property description "Cutler's RSI (SMA-based) with a signal line." - -#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 2 // CutlerRSI and its MA -#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 "Cutler's RSI" -#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 ENUM_APPLIED_PRICE InpAppliedPrice = PRICE_CLOSE; // RSI Applied Price -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[]; - -//--- Global Variables --- -int g_ExtPeriodRSI; -int g_ExtPeriodMA; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - g_ExtPeriodRSI = (InpPeriodRSI < 1) ? 1 : InpPeriodRSI; - g_ExtPeriodMA = (InpPeriodMA < 1) ? 1 : InpPeriodMA; - - SetIndexBuffer(0, BufferCutlerRSI_MA, INDICATOR_DATA); - SetIndexBuffer(1, BufferCutlerRSI, INDICATOR_DATA); - - ArraySetAsSeries(BufferCutlerRSI_MA, false); - ArraySetAsSeries(BufferCutlerRSI, false); - - IndicatorSetInteger(INDICATOR_DIGITS, 2); - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, g_ExtPeriodRSI + g_ExtPeriodMA - 1); - PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, g_ExtPeriodRSI); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("CutlerRSI(%d,%d)", g_ExtPeriodRSI, g_ExtPeriodMA)); - - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { -// No handles to release, but good practice to have the function - } - -//+------------------------------------------------------------------+ -//| Cutler's RSI 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[]) - { - int start_pos = g_ExtPeriodRSI + g_ExtPeriodMA - 1; - if(rates_total <= start_pos) - return(0); - -//--- STEP 1: Prepare the source price array - double price_source[]; - ArrayResize(price_source, rates_total); - for(int i=0; i 0) ? diff : 0; - double neg_change = (diff < 0) ? -diff : 0; - - sum_pos += pos_change; - sum_neg += neg_change; - - // Remove the oldest value from the sum once the window is full - if(i > g_ExtPeriodRSI) - { - double old_diff = price_source[i - g_ExtPeriodRSI] - price_source[i - g_ExtPeriodRSI - 1]; - sum_pos -= (old_diff > 0) ? old_diff : 0; - sum_neg -= (old_diff < 0) ? -old_diff : 0; - } - - if(i >= g_ExtPeriodRSI) - { - if(sum_neg > 0) - { - double rs = (sum_pos / g_ExtPeriodRSI) / (sum_neg / g_ExtPeriodRSI); - BufferCutlerRSI[i] = 100.0 - (100.0 / (1.0 + rs)); - } - else - { - BufferCutlerRSI[i] = 100.0; - } - } - } - -//--- STEP 3: Calculate the signal line (MA of Cutler's RSI) - int ma_start_pos = g_ExtPeriodRSI + g_ExtPeriodMA - 1; - for(int i = ma_start_pos; i < rates_total; i++) - { - // --- FIX: Full, robust switch block for all MA types --- - switch(InpMethodMA) - { - case MODE_EMA: - case MODE_SMMA: - if(i == ma_start_pos) - { - double sum=0; - for(int j=0; j0) - BufferCutlerRSI_MA[i]=lwma_sum/weight_sum; - } - break; - default: // MODE_SMA - { - double sum=0; - for(int j=0; j -#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 2 // CutlerRSI and its MA -#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[]; - -//--- Global Objects and Variables --- -int g_ExtPeriodRSI; -int g_ExtPeriodMA; -CHeikinAshi_Calculator *g_ha_calculator; // Pointer to our Heikin Ashi calculator - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - g_ExtPeriodRSI = (InpPeriodRSI < 1) ? 1 : InpPeriodRSI; - g_ExtPeriodMA = (InpPeriodMA < 1) ? 1 : InpPeriodMA; - - SetIndexBuffer(0, BufferCutlerRSI_MA, INDICATOR_DATA); - SetIndexBuffer(1, BufferCutlerRSI, INDICATOR_DATA); - - ArraySetAsSeries(BufferCutlerRSI_MA, false); - ArraySetAsSeries(BufferCutlerRSI, false); - - IndicatorSetInteger(INDICATOR_DIGITS, 2); -// Correct the draw begin for the signal line - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, g_ExtPeriodRSI + g_ExtPeriodMA - 1); - PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, g_ExtPeriodRSI); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA_CutlerRSI(%d,%d)", g_ExtPeriodRSI, g_ExtPeriodMA)); - -//--- Create the calculator instance - g_ha_calculator = new CHeikinAshi_Calculator(); - if(CheckPointer(g_ha_calculator) == POINTER_INVALID) - { - Print("Error creating CHeikinAshi_Calculator object"); - return(INIT_FAILED); - } - - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { -//--- Free the calculator object to prevent memory leaks - if(CheckPointer(g_ha_calculator) != POINTER_INVALID) - { - delete g_ha_calculator; - g_ha_calculator = NULL; - } - } - -//+------------------------------------------------------------------+ -//| Cutler's RSI on Heikin 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 <= g_ExtPeriodRSI) - return(0); - -//--- Intermediate Heikin Ashi Buffers - double ha_open[], ha_high[], ha_low[], ha_close[]; - ArrayResize(ha_open, rates_total); - ArrayResize(ha_high, rates_total); - ArrayResize(ha_low, rates_total); - ArrayResize(ha_close, rates_total); - -//--- STEP 1: Calculate Heikin Ashi bars - g_ha_calculator.Calculate(rates_total, open, high, low, close, ha_open, ha_high, ha_low, ha_close); - -//--- STEP 2: Calculate Cutler's RSI (SMA-based) - double sum_pos = 0, sum_neg = 0; - for(int i = 1; i < rates_total; i++) - { - double diff = ha_close[i] - ha_close[i-1]; - double pos_change = (diff > 0) ? diff : 0; - double neg_change = (diff < 0) ? -diff : 0; - - sum_pos += pos_change; - sum_neg += neg_change; - - // Remove the oldest value from the sum once the window is full - if(i > g_ExtPeriodRSI) - { - double old_diff = ha_close[i - g_ExtPeriodRSI] - ha_close[i - g_ExtPeriodRSI - 1]; - sum_pos -= (old_diff > 0) ? old_diff : 0; - sum_neg -= (old_diff < 0) ? -old_diff : 0; - } - - if(i >= g_ExtPeriodRSI) - { - if(sum_neg > 0) - { - double rs = (sum_pos / g_ExtPeriodRSI) / (sum_neg / g_ExtPeriodRSI); - BufferCutlerRSI[i] = 100.0 - (100.0 / (1.0 + rs)); - } - else - { - BufferCutlerRSI[i] = 100.0; - } - } - } - -//--- STEP 3: Calculate the signal line (MA of Cutler's RSI) - int ma_start_pos = g_ExtPeriodRSI + g_ExtPeriodMA - 1; - for(int i = ma_start_pos; i < rates_total; i++) - { - // --- FIX: Full, robust switch block for all MA types --- - switch(InpMethodMA) - { - case MODE_EMA: - case MODE_SMMA: - if(i == ma_start_pos) - { - double sum=0; - for(int j=0; j0) - BufferCutlerRSI_MA[i]=lwma_sum/weight_sum; - } - break; - default: // MODE_SMA - { - double sum=0; - for(int j=0; j 0) ? diff : 0; - double neg_change = (diff < 0) ? -diff : 0; - sum_pos += pos_change; - sum_neg += neg_change; - if(i > g_ExtPeriodRSI) - { - double old_diff = price_source[i - g_ExtPeriodRSI] - price_source[i - g_ExtPeriodRSI - 1]; - sum_pos -= (old_diff > 0) ? old_diff : 0; - sum_neg -= (old_diff < 0) ? -old_diff : 0; - } - if(i >= g_ExtPeriodRSI) - { - if(sum_neg > 0) - { - double rs = (sum_pos / g_ExtPeriodRSI) / (sum_neg / g_ExtPeriodRSI); - buffer_rsi[i] = 100.0 - (100.0 / (1.0 + rs)); - } - else - buffer_rsi[i] = 100.0; - } - } - } - -//--- STEP 2: Calculate the Signal Line (MA of Cutler's RSI) --- - for(int i = start_pos; i < rates_total; i++) - { - switch(InpMethodMA) - { - case MODE_EMA: - case MODE_SMMA: - if(i == start_pos) - { - double sum=0; - for(int j=0; j0) - buffer_signal[i]=lwma_sum/weight_sum; - } - break; - default: // MODE_SMA - { - double sum=0; - for(int j=0; j - -//--- Indicator Window and Plot Properties --- -#property indicator_separate_window -#property indicator_buffers 1 -#property indicator_plots 1 -#property indicator_type1 DRAW_HISTOGRAM -#property indicator_color1 clrSilver -#property indicator_width1 1 -#property indicator_label1 "HA_CutlerRSI_Osc" -#property indicator_level1 0.0 -#property indicator_levelstyle STYLE_DOT - -//--- Input Parameters --- -input int InpPeriodRSI = 14; -input group "Signal Line Settings" -input int InpPeriodMA = 14; -input ENUM_MA_METHOD InpMethodMA = MODE_SMA; - -//--- Indicator Buffers --- -double BufferOscillator[]; - -//--- Global Objects and Variables --- -int g_ExtPeriodRSI, g_ExtPeriodMA; -CHeikinAshi_Calculator *g_ha_calculator; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - g_ExtPeriodRSI = (InpPeriodRSI < 1) ? 1 : InpPeriodRSI; - g_ExtPeriodMA = (InpPeriodMA < 1) ? 1 : InpPeriodMA; - - SetIndexBuffer(0, BufferOscillator, INDICATOR_DATA); - ArraySetAsSeries(BufferOscillator, false); - - int draw_begin = g_ExtPeriodRSI + g_ExtPeriodMA - 1; - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, draw_begin); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA_CutlerRSI_Osc(%d,%d)", g_ExtPeriodRSI, g_ExtPeriodMA)); - IndicatorSetInteger(INDICATOR_DIGITS, 2); - - g_ha_calculator = new CHeikinAshi_Calculator(); - if(CheckPointer(g_ha_calculator) == POINTER_INVALID) - { - Print("Error creating CHeikinAshi_Calculator object"); - return(INIT_FAILED); - } - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { - if(CheckPointer(g_ha_calculator) != POINTER_INVALID) - { - delete g_ha_calculator; - g_ha_calculator = NULL; - } - } - -//+------------------------------------------------------------------+ -//| Cutler's RSI Oscillator on Heikin 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[]) - { - int start_pos = g_ExtPeriodRSI + g_ExtPeriodMA - 1; - if(rates_total <= start_pos) - return(0); - -//--- Internal Buffers for calculation --- - double buffer_rsi[], buffer_signal[]; - ArrayResize(buffer_rsi, rates_total); - ArrayResize(buffer_signal, rates_total); - -//--- STEP 1: Calculate Heikin Ashi Cutler's RSI internally --- - { - double ha_open[], ha_high[], ha_low[], ha_close[]; - ArrayResize(ha_open, rates_total); - ArrayResize(ha_high, rates_total); - ArrayResize(ha_low, rates_total); - ArrayResize(ha_close, rates_total); - g_ha_calculator.Calculate(rates_total, open, high, low, close, ha_open, ha_high, ha_low, ha_close); - - double sum_pos = 0, sum_neg = 0; - for(int i = 1; i < rates_total; i++) - { - double diff = ha_close[i] - ha_close[i-1]; - double pos_change = (diff > 0) ? diff : 0; - double neg_change = (diff < 0) ? -diff : 0; - sum_pos += pos_change; - sum_neg += neg_change; - if(i > g_ExtPeriodRSI) - { - double old_diff = ha_close[i - g_ExtPeriodRSI] - ha_close[i - g_ExtPeriodRSI - 1]; - sum_pos -= (old_diff > 0) ? old_diff : 0; - sum_neg -= (old_diff < 0) ? -old_diff : 0; - } - if(i >= g_ExtPeriodRSI) - { - if(sum_neg > 0) - { - double rs = (sum_pos / g_ExtPeriodRSI) / (sum_neg / g_ExtPeriodRSI); - buffer_rsi[i] = 100.0 - (100.0 / (1.0 + rs)); - } - else - buffer_rsi[i] = 100.0; - } - } - } - -//--- STEP 2: Calculate the Signal Line (MA of Cutler's RSI) --- - for(int i = start_pos; i < rates_total; i++) - { - switch(InpMethodMA) - { - case MODE_EMA: - case MODE_SMMA: - if(i == start_pos) - { - double sum=0; - for(int j=0; j0) - buffer_signal[i]=lwma_sum/weight_sum; - } - break; - default: // MODE_SMA - { - double sum=0; - for(int j=0; j - -//--- Plot 1: Fibonacci WMA Line -#property indicator_label1 "Fibonacci WMA" -#property indicator_type1 DRAW_LINE -#property indicator_color1 clrDodgerBlue -#property indicator_style1 STYLE_SOLID -#property indicator_width1 2 - -//--- Input Parameters --- -input int InpPeriod = 21; -input ENUM_APPLIED_PRICE InpSourcePrice = PRICE_CLOSE; - -//--- Indicator Buffers --- -double BufferWMA[]; - -//--- Global calculator object --- -CFibonacciWMACalculator *g_calculator; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - SetIndexBuffer(0, BufferWMA, INDICATOR_DATA); - ArraySetAsSeries(BufferWMA, false); - - g_calculator = new CFibonacciWMACalculator(); - if(CheckPointer(g_calculator) == POINTER_INVALID || !g_calculator.Init(InpPeriod)) - { - Print("Failed to initialize Fibonacci WMA Calculator."); - return(INIT_FAILED); - } - - int actual_period = InpPeriod > 40 ? 40 : InpPeriod; - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, actual_period - 1); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("FibonacciWMA(%d)", InpPeriod)); - - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { - if(CheckPointer(g_calculator) != POINTER_INVALID) - delete g_calculator; - } - -//+------------------------------------------------------------------+ -//| Custom indicator iteration function. | -//+------------------------------------------------------------------+ -int OnCalculate(const int rates_total, const int, const datetime&[], const double &open[], const double &high[], const double &low[], const double &close[], const long&[], const long&[], const int&[]) - { - if(CheckPointer(g_calculator) != POINTER_INVALID) - { - g_calculator.Calculate(rates_total, InpSourcePrice, open, high, low, close, BufferWMA); - } - return(rates_total); - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/Fibonacci_WMA_HeikinAshi.mq5 b/Indicators/MyIndicators/Fibonacci_WMA_HeikinAshi.mq5 deleted file mode 100644 index 2e9d61a..0000000 --- a/Indicators/MyIndicators/Fibonacci_WMA_HeikinAshi.mq5 +++ /dev/null @@ -1,76 +0,0 @@ -//+------------------------------------------------------------------+ -//| Fibonacci_WMA_HeikinAshi.mq5 | -//| Copyright 2025, xxxxxxxx| -//| | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property version "1.00" -#property description "Fibonacci Weighted Moving Average on Heikin Ashi data." - -#property indicator_chart_window -#property indicator_buffers 1 -#property indicator_plots 1 - -#include - -//--- Plot 1: Fibonacci WMA Line -#property indicator_label1 "Fibonacci WMA (HA)" -#property indicator_type1 DRAW_LINE -#property indicator_color1 clrDodgerBlue -#property indicator_style1 STYLE_SOLID -#property indicator_width1 2 - -//--- Input Parameters --- -input int InpPeriod = 21; - -//--- Indicator Buffers --- -double BufferWMA[]; - -//--- Global calculator object --- -CFibonacciWMACalculator_HA *g_calculator; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - SetIndexBuffer(0, BufferWMA, INDICATOR_DATA); - ArraySetAsSeries(BufferWMA, false); - - g_calculator = new CFibonacciWMACalculator_HA(); - if(CheckPointer(g_calculator) == POINTER_INVALID || !g_calculator.Init(InpPeriod)) - { - Print("Failed to initialize Fibonacci WMA HA Calculator."); - return(INIT_FAILED); - } - - int actual_period = InpPeriod > 40 ? 40 : InpPeriod; - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, actual_period - 1); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("FibonacciWMA_HA(%d)", InpPeriod)); - - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { - if(CheckPointer(g_calculator) != POINTER_INVALID) - delete g_calculator; - } - -//+------------------------------------------------------------------+ -//| Custom indicator iteration function. | -//+------------------------------------------------------------------+ -int OnCalculate(const int rates_total, const int, const datetime&[], const double &open[], const double &high[], const double &low[], const double &close[], const long&[], const long&[], const int&[]) - { - if(CheckPointer(g_calculator) != POINTER_INVALID) - { - //--- The price_type parameter is ignored by the HA calculator, so we can pass a default - g_calculator.Calculate(rates_total, PRICE_CLOSE, open, high, low, close, BufferWMA); - } - return(rates_total); - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/FisherTransform.md b/Indicators/MyIndicators/FisherTransform.md deleted file mode 100644 index 1b9de09..0000000 --- a/Indicators/MyIndicators/FisherTransform.md +++ /dev/null @@ -1,66 +0,0 @@ -# Fisher Transform - -## 1. Summary (Introduction) - -The Fisher Transform is a technical indicator created by J.H. Ehlers that converts price into a Gaussian normal distribution. The primary purpose of this transformation is to create sharp, clear turning points that are less prone to the lag and ambiguity of many other oscillators. - -The indicator consists of two lines: the Fisher line and a signal line (which is typically the Fisher line's value from the previous bar). It is an unbound oscillator, meaning its values can theoretically extend to infinity, but in practice, it tends to fluctuate around a zero line. Extreme readings suggest that a price reversal is more likely. - -## 2. Mathematical Foundations and Calculation Logic - -The Fisher Transform uses a mathematical formula to normalize price data, making extreme price moves more apparent. - -### Required Components - -- **Period (N):** The lookback period for finding the highest and lowest prices. -- **Source Price:** The indicator typically uses the median price `(High + Low) / 2` as its input. - -### Calculation Steps (Algorithm) - -1. **Transform Price to a Level between -1 and +1:** First, the source price is converted into a value that fluctuates primarily between -1 and +1. This is done by determining the price's position within its highest and lowest range over the last `N` periods. - - - $\text{Price Position}_i = \frac{\text{Source Price}_i - \text{Lowest Price}_{N}}{\text{Highest Price}_{N} - \text{Lowest Price}_{N}} - 0.5$ - - This value is then smoothed, often with a weighted or exponential moving average. The classic formula uses a specific recursive smoothing: - $\text{Value}_i = (0.33 \times 2 \times \text{Price Position}_i) + (0.67 \times \text{Value}_{i-1})$ - - The resulting `Value` is clamped to a range just inside -1 and +1 (e.g., -0.999 to 0.999) to avoid mathematical errors in the next step. - -2. **Apply the Fisher Transform:** The core of the indicator is the application of the Fisher Transform formula to the smoothed `Value` from the previous step. - $\text{Fisher}_i = 0.5 \times \ln\left(\frac{1 + \text{Value}_i}{1 - \text{Value}_i}\right)$ - Where `ln` is the natural logarithm. - -3. **Final Smoothing and Signal Line:** The resulting Fisher value is often smoothed again with its own previous value to create the final, plotted line. The signal line is simply the Fisher line from the previous bar. - $\text{Final Fisher}_i = \text{Fisher}_i + (0.5 \times \text{Final Fisher}_{i-1})$ - $\text{Signal}_i = \text{Final Fisher}_{i-1}$ - -## 3. MQL5 Implementation Details - -Our MQL5 implementation was refactored to be highly robust, especially concerning the multiple recursive calculations involved. - -- **Stability via Full Recalculation:** We employ a "brute-force" full recalculation within the `OnCalculate` function. This is our standard practice for indicators with recursive logic to ensure maximum stability and prevent calculation errors. - -- **Robust Initialization:** This is the most critical part of the implementation. The final, recursive calculation of the `BufferFisher` line is highly susceptible to floating-point overflows if not initialized correctly. Our code explicitly handles this: - - - The **first valid value** of the `BufferFisher` line is calculated **without** the recursive component (`+ 0.5 * BufferFisher[i-1]`). - - All subsequent values are then calculated using the full recursive formula, ensuring the calculation chain starts with a stable, valid number. - -- **Clear, Staged Calculation:** The `OnCalculate` function is structured into two clear, sequential steps: - - 1. **Step 1:** A `for` loop prepares the source price data (`hl2`) for the main calculation. - 2. **Step 2:** A single, efficient `for` loop handles the entire Fisher Transform calculation, including the smoothing of the intermediate `Value` buffer and the final, robustly initialized `BufferFisher` calculation. - -- **Heikin Ashi Variant (`FisherTransform_HeikinAshi.mq5`):** - - Our toolkit also includes a Heikin Ashi version of this indicator. The calculation logic is identical, but it uses the smoothed Heikin Ashi `ha_high` and `ha_low` values to calculate the source price. - - This results in a significantly smoother oscillator, as the input data itself is already filtered, which can help in identifying more significant, underlying momentum shifts. - -## 4. Parameters - -- **Length (`InpLength`):** The lookback period for finding the highest and lowest prices. A shorter period results in a more sensitive, faster-reacting oscillator, while a longer period creates a smoother, slower line. Default is `9`. - -## 5. Usage and Interpretation - -- **Identifying Extremes:** The primary use of the Fisher Transform is to identify extreme price levels that may signal an impending reversal. High positive values (e.g., above +1.5) are considered overbought, and high negative values (e.g., below -1.5) are considered oversold. -- **Crossovers:** - - **Fisher / Signal Line Crossover:** When the Fisher line (blue) crosses above its signal line (orange), it can be considered a buy signal. When it crosses below, it's a sell signal. These are the most common signals generated by the indicator. - - **Zero Line Crossover:** A crossover of the Fisher line above the zero line can also be interpreted as a bullish signal, and a cross below as bearish, though these are less common. -- **Divergence:** Look for divergences between the Fisher Transform and the price action. A bearish divergence (higher price highs, lower Fisher highs) can signal a potential top, while a bullish divergence (lower price lows, higher Fisher lows) can signal a potential bottom. -- **Caution:** The Fisher Transform is a very fast-reacting oscillator and can produce many signals. It is often recommended to wait for the Fisher line to form a clear peak or trough beyond the extreme levels before acting on a signal, rather than trading every crossover. diff --git a/Indicators/MyIndicators/FisherTransform.mq5 b/Indicators/MyIndicators/FisherTransform.mq5 deleted file mode 100644 index 6260cd6..0000000 --- a/Indicators/MyIndicators/FisherTransform.mq5 +++ /dev/null @@ -1,181 +0,0 @@ -//+------------------------------------------------------------------+ -//| FisherTransform.mq5 | -//| Copyright 2025, xxxxxxxx | -//| | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property link "" -#property version "2.00" // Refactored for stability and robust initialization -#property description "Fisher Transform Oscillator" - -//--- 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 "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 "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 BufferFisher[]; -double BufferTrigger[]; -double BufferValue[]; // Calculation buffer for the intermediate 'value' - -//--- Global Variables --- -int g_ExtLength; - -//--- 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. | -//+------------------------------------------------------------------+ -int OnInit() - { -//--- Validate and store input - g_ExtLength = (InpLength < 1) ? 1 : InpLength; - -//--- Map the buffers - SetIndexBuffer(0, BufferFisher, INDICATOR_DATA); - SetIndexBuffer(1, BufferTrigger, INDICATOR_DATA); - SetIndexBuffer(2, BufferValue, INDICATOR_CALCULATIONS); - -//--- Set all buffers to non-timeseries for stable calculation - ArraySetAsSeries(BufferFisher, false); - ArraySetAsSeries(BufferTrigger, false); - ArraySetAsSeries(BufferValue, false); - -//--- Set indicator properties - IndicatorSetInteger(INDICATOR_DIGITS, 4); - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, g_ExtLength); - PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, g_ExtLength + 1); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("Fisher(%d)", g_ExtLength)); - - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Fisher Transform 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_ExtLength) - return(0); - -//--- STEP 1: Create a buffer for HL2 price - double hl2[]; - ArrayResize(hl2, rates_total); - for(int i=0; i 0.999) - BufferValue[i] = 0.999; - if(BufferValue[i] < -0.999) - BufferValue[i] = -0.999; - - // --- FIX: Robust initialization for the recursive Fisher calculation --- - double log_val = 0.5 * MathLog((1 + BufferValue[i]) / (1 - BufferValue[i])); - - if(i == g_ExtLength) // First calculation (initialization) - { - BufferFisher[i] = log_val; - } - else // Subsequent calculations use the full recursive formula - { - BufferFisher[i] = log_val + 0.5 * BufferFisher[i-1]; - } - - // The trigger is the previous Fisher value - BufferTrigger[i] = BufferFisher[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/FisherTransform_HeikinAshi.mq5 b/Indicators/MyIndicators/FisherTransform_HeikinAshi.mq5 deleted file mode 100644 index 07ba811..0000000 --- a/Indicators/MyIndicators/FisherTransform_HeikinAshi.mq5 +++ /dev/null @@ -1,226 +0,0 @@ -//+------------------------------------------------------------------+ -//| FisherTransform_HeikinAshi.mq5| -//| Copyright 2025, xxxxxxxx | -//| | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property link "" -#property version "2.00" // Refactored for full recalculation and stability -#property description "Fisher Transform Oscillator on Heikin 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' - -//--- Intermediate Heikin Ashi Buffers --- -double ExtHaOpenBuffer[]; -double ExtHaHighBuffer[]; -double ExtHaLowBuffer[]; -double ExtHaCloseBuffer[]; - -//--- Global Objects and Variables --- -int g_ExtLength; -CHeikinAshi_Calculator *g_ha_calculator; // Pointer to our Heikin 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. | -//+------------------------------------------------------------------+ -int OnInit() - { -//--- Validate and store input - g_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, g_ExtLength); - PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, g_ExtLength + 1); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA_Fisher(%d)", g_ExtLength)); - -//--- Create the calculator instance - g_ha_calculator = new CHeikinAshi_Calculator(); - if(CheckPointer(g_ha_calculator) == POINTER_INVALID) - { - Print("Error creating CHeikinAshi_Calculator object"); - return(INIT_FAILED); - } - - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { -//--- Free the calculator object to prevent memory leaks - if(CheckPointer(g_ha_calculator) != POINTER_INVALID) - { - delete g_ha_calculator; - g_ha_calculator = NULL; - } - } - -//+------------------------------------------------------------------+ -//| Fisher Transform on Heikin 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 <= g_ExtLength) - return(0); - -//--- Resize intermediate buffers - ArrayResize(ExtHaOpenBuffer, rates_total); - ArrayResize(ExtHaHighBuffer, rates_total); - ArrayResize(ExtHaLowBuffer, rates_total); - ArrayResize(ExtHaCloseBuffer, rates_total); - -//--- STEP 1: Calculate Heikin Ashi bars - g_ha_calculator.Calculate(rates_total, open, high, low, close, - ExtHaOpenBuffer, ExtHaHighBuffer, ExtHaLowBuffer, ExtHaCloseBuffer); - -//--- STEP 2: Create a buffer for Heikin Ashi HL2 price - double ha_hl2[]; - ArrayResize(ha_hl2, rates_total); - for(int i=0; i 0.999) - BufferValue[i] = 0.999; - if(BufferValue[i] < -0.999) - BufferValue[i] = -0.999; - - // --- FIX: Robust initialization for the recursive calculation --- - double log_val = 0.5 * MathLog((1 + BufferValue[i]) / (1 - BufferValue[i])); - - if(i == g_ExtLength) // First calculation (initialization) - { - // For the very first value, we don't use the recursive part - BufferHA_Fisher[i] = log_val; - } - else // Subsequent calculations use the full recursive formula - { - 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.md b/Indicators/MyIndicators/Gann_HiLo.md deleted file mode 100644 index d3b7eeb..0000000 --- a/Indicators/MyIndicators/Gann_HiLo.md +++ /dev/null @@ -1,66 +0,0 @@ -# Gann HiLo Activator - -## 1. Summary (Introduction) - -The Gann HiLo Activator is a simple yet effective trend-following indicator developed by Robert Krausz. Despite its name, it is not directly based on the complex methods of W.D. Gann, but rather follows the core principle of using moving averages of previous highs and lows to identify the trend direction. - -The indicator is plotted on the price chart as a single line that changes color and position relative to the price, providing clear, visual signals for trend direction, potential entry points, and trailing stop-loss levels. - -## 2. Mathematical Foundations and Calculation Logic - -The Gann HiLo Activator is based on two separate moving averages: one calculated on the previous `N` bars' high prices, and the other on the previous `N` bars' low prices. The indicator then uses the closing price to determine which of these two moving averages to follow. - -### Required Components - -- **Period (N):** The lookback period for the high and low moving averages. -- **MA Method:** The type of moving average to use (Simple, Exponential, etc.). -- **Source Prices:** The `High[]` and `Low[]` price series. - -### Calculation Steps (Algorithm) - -1. **Calculate the Moving Average of Highs:** Compute the moving average of the high prices over the last `N` bars. - $\text{HiAvg}_i = \text{MA}(\text{High}, N)_i$ - -2. **Calculate the Moving Average of Lows:** Compute the moving average of the low prices over the last `N` bars. - $\text{LoAvg}_i = \text{MA}(\text{Low}, N)_i$ - -3. **Determine the Trend Direction:** The trend is determined by comparing the current closing price to the moving averages of the _previous_ bar. - - - If the current `Close` is **above** the previous bar's `HiAvg`, the trend is **up**. - - If the current `Close` is **below** the previous bar's `LoAvg`, the trend is **down**. - - If the `Close` is between the two previous averages, the trend **continues** from the previous bar. - -4. **Plot the Gann HiLo Activator Line:** - - If the trend is **up**, the indicator line is plotted at the level of the **LoAvg**. - - If the trend is **down**, the indicator line is plotted at the level of the **HiAvg**. - -## 3. MQL5 Implementation Details - -Our MQL5 implementation was refactored to be a completely self-contained, robust, and accurate indicator, consistent with our established coding principles. - -- **Stability via Full Recalculation:** We employ a "brute-force" full recalculation within the `OnCalculate` function. For a state-dependent indicator like the Gann HiLo, this is the most reliable method to prevent calculation errors and ensure stability. - -- **Fully Manual MA Calculations:** To guarantee 100% accuracy and consistency within our `non-timeseries` calculation model, we have implemented all moving average types (**SMA, EMA, SMMA, LWMA**) **manually**. The indicator is completely independent of the `` standard library. This approach provides full control and ensures predictable behavior. - - - **Recursive MAs (EMA/SMMA)** are carefully initialized with a manual Simple Moving Average to prevent floating-point overflows. - - **SMA** is calculated using an efficient sliding-window sum technique. - -- **Integrated Calculation Loop:** The `OnCalculate` function uses a single, efficient `for` loop to perform all calculations. Within each iteration, it first computes the `HiAvg` and `LoAvg`, then immediately determines the trend direction and sets the final `GannHiLo` value. This integrated approach is clear and performant. - -- **Visual Representation:** The implementation ensures that trend changes are represented by a clean, vertical line connecting the previous trend's endpoint to the new trend's starting point, providing continuous visual information. - -- **Heikin Ashi Variant (`Gann_HiLo_HeikinAshi.mq5`):** - - Our toolkit also includes a Heikin Ashi version of this indicator. The calculation logic is identical, but it uses the smoothed Heikin Ashi `ha_high` and `ha_low` values for the moving average calculations and the `ha_close` for determining the trend. - - This results in a significantly smoother indicator, ideal for traders who want to focus on the primary trend and filter out market noise. - -## 4. Parameters - -- **Period (`InpPeriod`):** The lookback period for the high and low moving averages. A shorter period will result in a more responsive line that follows the price closely, while a longer period will create a smoother line that is less sensitive to minor fluctuations. Default is `10`. -- **MA Method (`InpMAMethod`):** The type of moving average to use for the high and low calculations (SMA, EMA, SMMA, LWMA). Default is `MODE_SMA`. - -## 5. Usage and Interpretation - -- **Trend Identification:** The primary use of the Gann HiLo is to identify the current market trend. A blue line below the price indicates an uptrend. A red line above the price indicates a downtrend. -- **Trailing Stop-Loss:** The indicator is exceptionally well-suited for use as a trailing stop-loss. In an uptrend, a trader might place their stop-loss just below the blue line. In a downtrend, the stop-loss could be placed just above the red line. -- **Trade Signals:** A change in the indicator's color can be interpreted as a trade signal. A flip from red to blue suggests a potential buy signal, while a flip from blue to red suggests a potential sell signal. -- **Caution:** Like all trend-following indicators, the Gann HiLo is most effective in trending markets. In sideways or ranging markets, it can produce frequent false signals ("whipsaws") as the price oscillates around the two moving averages. diff --git a/Indicators/MyIndicators/Gann_HiLo.mq5 b/Indicators/MyIndicators/Gann_HiLo.mq5 deleted file mode 100644 index 98c0187..0000000 --- a/Indicators/MyIndicators/Gann_HiLo.mq5 +++ /dev/null @@ -1,189 +0,0 @@ -//+------------------------------------------------------------------+ -//| Gann_HiLo.mq5 | -//| Copyright 2025, xxxxxxxx | -//| | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property link "" -#property version "2.00" // Refactored for stability with fully manual MA calculations -#property description "Gann HiLo Activator with selectable MA for trend following" - -//--- 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 "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 BufferGannHiLo[]; -double BufferColor[]; -double BufferHiAvg[]; -double BufferLoAvg[]; -double BufferTrend[]; - -//--- Global Variables --- -int g_ExtPeriod; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - g_ExtPeriod = (InpPeriod < 1) ? 1 : InpPeriod; - - SetIndexBuffer(0, BufferGannHiLo, INDICATOR_DATA); - SetIndexBuffer(1, BufferColor, INDICATOR_COLOR_INDEX); - SetIndexBuffer(2, BufferHiAvg, INDICATOR_CALCULATIONS); - SetIndexBuffer(3, BufferLoAvg, INDICATOR_CALCULATIONS); - SetIndexBuffer(4, BufferTrend, INDICATOR_CALCULATIONS); - - ArraySetAsSeries(BufferGannHiLo, false); - ArraySetAsSeries(BufferColor, false); - ArraySetAsSeries(BufferHiAvg, false); - ArraySetAsSeries(BufferLoAvg, false); - ArraySetAsSeries(BufferTrend, false); - - IndicatorSetInteger(INDICATOR_DIGITS, _Digits); - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, g_ExtPeriod); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("Gann_HiLo(%d)", g_ExtPeriod)); - - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Gann HiLo Activator 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_ExtPeriod) - return(0); - -//--- Variables for manual SMA calculation - double sma_sum_high = 0; - double sma_sum_low = 0; - -//--- Main calculation loop - for(int i = 1; i < rates_total; i++) - { - if(i < g_ExtPeriod - 1) - continue; - - // --- STEP 1: Calculate the two moving averages (High and Low) --- - switch(InpMAMethod) - { - case MODE_EMA: - case MODE_SMMA: - if(i == g_ExtPeriod - 1) // Initialization with manual SMA - { - double sum_h=0, sum_l=0; - for(int j=0; j 0) - { - BufferHiAvg[i] = lwma_sum_h / weight_sum; - BufferLoAvg[i] = lwma_sum_l / weight_sum; - } - } - break; - default: // MODE_SMA - if(i == g_ExtPeriod - 1) - { - for(int j=0; j BufferHiAvg[i-1]) - BufferTrend[i] = 1; - else - if(close[i] < BufferLoAvg[i-1]) - BufferTrend[i] = -1; - else - BufferTrend[i] = BufferTrend[i-1]; - - if(BufferTrend[i] == 1) - { - BufferGannHiLo[i] = BufferLoAvg[i]; - BufferColor[i] = 0; - if(BufferTrend[i-1] == -1) - BufferGannHiLo[i-1] = BufferLoAvg[i]; - } - else - { - BufferGannHiLo[i] = BufferHiAvg[i]; - BufferColor[i] = 1; - if(BufferTrend[i-1] == 1) - BufferGannHiLo[i-1] = BufferHiAvg[i]; - } - } - - return(rates_total); - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/Gann_HiLo_HeikinAshi.mq5 b/Indicators/MyIndicators/Gann_HiLo_HeikinAshi.mq5 deleted file mode 100644 index d4b60b2..0000000 --- a/Indicators/MyIndicators/Gann_HiLo_HeikinAshi.mq5 +++ /dev/null @@ -1,190 +0,0 @@ -//+------------------------------------------------------------------+ -//| Gann_HiLo_HeikinAshi.mq5 | -//| Copyright 2025, xxxxxxxx | -//| | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property link "" -#property version "2.00" // Refactored for full recalculation and stability -#property description "Gann HiLo Activator on Heikin 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[]; - -//--- Intermediate Heikin Ashi Buffers --- -double ExtHaOpenBuffer[]; -double ExtHaHighBuffer[]; -double ExtHaLowBuffer[]; -double ExtHaCloseBuffer[]; - -//--- Global Objects and Variables --- -int g_ExtPeriod; -CHeikinAshi_Calculator *g_ha_calculator; // Pointer to our Heikin Ashi calculator - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - g_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, g_ExtPeriod); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA_Gann_HiLo(%d)", g_ExtPeriod)); - -//--- Create the calculator instance - g_ha_calculator = new CHeikinAshi_Calculator(); - if(CheckPointer(g_ha_calculator) == POINTER_INVALID) - { - Print("Error creating CHeikinAshi_Calculator object"); - return(INIT_FAILED); - } - - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { -//--- Free the calculator object to prevent memory leaks - if(CheckPointer(g_ha_calculator) != POINTER_INVALID) - { - delete g_ha_calculator; - g_ha_calculator = NULL; - } - } - -//+------------------------------------------------------------------+ -//| Gann HiLo on Heikin 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 <= g_ExtPeriod) - return(0); - -//--- Resize intermediate buffers - ArrayResize(ExtHaOpenBuffer, rates_total); - ArrayResize(ExtHaHighBuffer, rates_total); - ArrayResize(ExtHaLowBuffer, rates_total); - ArrayResize(ExtHaCloseBuffer, rates_total); - -//--- STEP 1: Calculate Heikin Ashi bars - g_ha_calculator.Calculate(rates_total, open, high, low, close, - ExtHaOpenBuffer, ExtHaHighBuffer, ExtHaLowBuffer, ExtHaCloseBuffer); - -//--- STEP 2 & 3: Calculate MAs, determine trend, and set final value in a single loop - for(int i = 1; i < rates_total; i++) - { - // Skip bars that don't have enough history for the period - if(i < g_ExtPeriod) - continue; - - // --- Calculate the two moving averages on HA High and HA Low --- - switch(InpMAMethod) - { - case MODE_EMA: - if(i == g_ExtPeriod) // Initialization - { - BufferHiAvg[i] = SimpleMA(i, g_ExtPeriod, ExtHaHighBuffer); - BufferLoAvg[i] = SimpleMA(i, g_ExtPeriod, ExtHaLowBuffer); - } - else // Recursive calculation - { - double pr = 2.0 / (g_ExtPeriod + 1.0); - BufferHiAvg[i] = ExtHaHighBuffer[i] * pr + BufferHiAvg[i-1] * (1.0 - pr); - BufferLoAvg[i] = ExtHaLowBuffer[i] * pr + BufferLoAvg[i-1] * (1.0 - pr); - } - break; - case MODE_SMMA: - if(i == g_ExtPeriod) // Initialization - { - BufferHiAvg[i] = SimpleMA(i, g_ExtPeriod, ExtHaHighBuffer); - BufferLoAvg[i] = SimpleMA(i, g_ExtPeriod, ExtHaLowBuffer); - } - else // Recursive calculation - { - BufferHiAvg[i] = (BufferHiAvg[i-1] * (g_ExtPeriod - 1) + ExtHaHighBuffer[i]) / g_ExtPeriod; - BufferLoAvg[i] = (BufferLoAvg[i-1] * (g_ExtPeriod - 1) + ExtHaLowBuffer[i]) / g_ExtPeriod; - } - break; - case MODE_LWMA: - BufferHiAvg[i] = LinearWeightedMA(i, g_ExtPeriod, ExtHaHighBuffer); - BufferLoAvg[i] = LinearWeightedMA(i, g_ExtPeriod, ExtHaLowBuffer); - break; - default: // MODE_SMA - BufferHiAvg[i] = SimpleMA(i, g_ExtPeriod, ExtHaHighBuffer); - BufferLoAvg[i] = SimpleMA(i, g_ExtPeriod, ExtHaLowBuffer); - break; - } - - // --- Determine trend and set the final Gann HiLo value --- - if(ExtHaCloseBuffer[i] > BufferHiAvg[i-1]) // Trend turns up - BufferTrend[i] = 1; - else - if(ExtHaCloseBuffer[i] < BufferLoAvg[i-1]) // Trend turns down - BufferTrend[i] = -1; - else // Trend continues - BufferTrend[i] = BufferTrend[i-1]; - - if(BufferTrend[i] == 1) - { - BufferHA_GannHiLo[i] = BufferLoAvg[i]; - BufferColor[i] = 0; // Blue for up trend - } - else - { - BufferHA_GannHiLo[i] = BufferHiAvg[i]; - BufferColor[i] = 1; // Tomato for down trend - } - } - - return(rates_total); - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/HMA.md b/Indicators/MyIndicators/HMA.md deleted file mode 100644 index b70f2a0..0000000 --- a/Indicators/MyIndicators/HMA.md +++ /dev/null @@ -1,60 +0,0 @@ -# Hull Moving Average (HMA) - -## 1. Summary (Introduction) - -The Hull Moving Average (HMA) was developed by Alan Hull in 2005. Its primary goal is to create a moving average that is both extremely responsive to current price activity and simultaneously smooths out price data effectively. Traditional moving averages often present a trade-off between smoothness and lag; a smoother average lags more, while a faster average is more prone to "whipsaws" or noise. - -The HMA aims to solve this problem by using a unique calculation involving multiple weighted moving averages (WMAs), resulting in a line that closely follows the price while maintaining a high degree of smoothness. - -## 2. Mathematical Foundations and Calculation Logic - -The HMA's formula cleverly combines three separate Weighted Moving Averages (WMAs) to nearly eliminate lag and improve smoothness. - -### Required Components - -- **HMA Period (N):** The main lookback period for the indicator. -- **Source Price (P):** The price series used for the calculation (e.g., Close). - -### Calculation Steps (Algorithm) - -1. **Calculate a WMA with period (N/2):** First, calculate a WMA with a period of half the main HMA period, rounded to the nearest integer. - $\text{WMA}_{\text{half}} = \text{WMA}(P, \text{integer}(\frac{N}{2}))$ - -2. **Calculate a WMA with period (N):** Second, calculate a WMA with the full HMA period. - $\text{WMA}_{\text{full}} = \text{WMA}(P, N)$ - -3. **Calculate the Raw HMA:** Create a new, un-smoothed "raw" HMA series by taking two times the half-period WMA and subtracting the full-period WMA. This step significantly reduces lag. - $\text{Raw HMA}_i = (2 \times \text{WMA}_{\text{half}, i}) - \text{WMA}_{\text{full}, i}$ - -4. **Calculate the Final HMA:** Smooth the `Raw HMA` series with another WMA, this time using a period equal to the square root of the main HMA period, rounded to the nearest integer. This final step reintroduces smoothness to the fast-moving raw line. - $\text{Final HMA}_i = \text{WMA}(\text{Raw HMA}, \text{integer}(\sqrt{N}))_i$ - -## 3. MQL5 Implementation Details - -Our MQL5 implementation was refactored to be a completely self-contained, robust, and accurate indicator. - -- **Stability via Full Recalculation:** We employ a "brute-force" full recalculation within the `OnCalculate` function. This is our standard practice to ensure maximum stability and prevent calculation errors during timeframe changes or history loading. - -- **Fully Manual WMA Calculation:** To guarantee 100% accuracy and consistency within our `non-timeseries` calculation model, we have implemented the Weighted Moving Average calculation **manually**. The indicator does **not** use the `` standard library. This approach avoids any potential inconsistencies that might arise from using library functions on `non-timeseries` arrays and gives us full control over the calculation logic. - -- **Clear, Staged Calculation:** The `OnCalculate` function is structured into clear, sequential steps: - - 1. **Step 1 (Price Preparation):** A single source price array (`price_source[]`) is prepared based on the user's `InpAppliedPrice` selection, including all standard and calculated price types (e.g., `PRICE_TYPICAL`). - 2. **Step 2 (Base WMAs & Raw HMA):** The first `for` loop calculates the two base WMAs (half-period and full-period) and the resulting `Raw HMA`, storing them in their respective calculation buffers. - 3. **Step 3 (Final HMA):** A second `for` loop performs the final smoothing step, calculating a WMA on the `Raw HMA` buffer to produce the final, plotted HMA line. - -- **Heikin Ashi Variant (`HMA_HeikinAshi.mq5`):** - - Our toolkit also includes a Heikin Ashi version of this indicator. The calculation logic is identical, but it uses the smoothed Heikin Ashi price data (e.g., `ha_close`) as its input. - - This results in an exceptionally smooth trend line, combining the advanced smoothing of the HMA formula with the noise-filtering properties of Heikin Ashi candles. - -## 4. Parameters - -- **HMA Period (`InpPeriodHMA`):** The main lookback period for the indicator. This single parameter controls all three internal WMA calculations. Default is `14`. -- **Applied Price (`InpAppliedPrice`):** The source price used for the calculation (e.g., `PRICE_CLOSE`). - -## 5. Usage and Interpretation - -- **Trend Identification:** The HMA is primarily used as a fast and smooth trend line. When the price is above the HMA and the HMA is rising, the trend is considered bullish. When the price is below the HMA and the HMA is falling, the trend is considered bearish. -- **Crossover Signals:** Crossovers of the price and the HMA line can be used as trade signals. Due to its responsiveness, these signals occur with less lag than with traditional moving averages. -- **Trend Direction Filter:** The slope of the HMA itself can be used as a trend filter. A simple rule could be to only consider long trades when the HMA is rising and short trades when it is falling. -- **Caution:** While the HMA is very responsive, it is still a lagging indicator. Its primary strength is in trending markets. In sideways or choppy markets, it can still produce false signals. diff --git a/Indicators/MyIndicators/HMA.mq5 b/Indicators/MyIndicators/HMA.mq5 deleted file mode 100644 index a6a1bcf..0000000 --- a/Indicators/MyIndicators/HMA.mq5 +++ /dev/null @@ -1,163 +0,0 @@ -//+------------------------------------------------------------------+ -//| HMA.mq5 | -//| Copyright 2025, xxxxxxxx | -//| | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property link "" -#property version "3.00" // Fully manual, self-contained, and accurate -#property description "Hull Moving Average (HMA)" - -//--- Indicator Window and Plot Properties --- -#property indicator_chart_window -#property indicator_buffers 4 // HMA, and 3 calculation buffers -#property indicator_plots 1 - -//--- Plot 1: HMA line -#property indicator_label1 "HMA" -#property indicator_type1 DRAW_LINE -#property indicator_color1 clrDeepPink -#property indicator_style1 STYLE_SOLID -#property indicator_width1 2 - -//--- Input Parameters --- -input int InpPeriodHMA = 14; -input ENUM_APPLIED_PRICE InpAppliedPrice = PRICE_CLOSE; - -//--- Indicator Buffers --- -double BufferHMA[]; -double BufferWMA_Half[]; -double BufferWMA_Full[]; -double BufferRawHMA[]; - -//--- Global Variables --- -int g_ExtPeriodHMA; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - g_ExtPeriodHMA = (InpPeriodHMA < 1) ? 1 : InpPeriodHMA; - - SetIndexBuffer(0, BufferHMA, INDICATOR_DATA); - SetIndexBuffer(1, BufferWMA_Half, INDICATOR_CALCULATIONS); - SetIndexBuffer(2, BufferWMA_Full, INDICATOR_CALCULATIONS); - SetIndexBuffer(3, BufferRawHMA, INDICATOR_CALCULATIONS); - - ArraySetAsSeries(BufferHMA, false); - ArraySetAsSeries(BufferWMA_Half, false); - ArraySetAsSeries(BufferWMA_Full, false); - ArraySetAsSeries(BufferRawHMA, false); - - IndicatorSetInteger(INDICATOR_DIGITS, _Digits); - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, g_ExtPeriodHMA + (int)MathFloor(MathSqrt(g_ExtPeriodHMA)) - 2); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HMA(%d)", g_ExtPeriodHMA)); - - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Hull Moving Average 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[]) - { - int start_pos = g_ExtPeriodHMA + (int)MathFloor(MathSqrt(g_ExtPeriodHMA)) - 2; - if(rates_total <= start_pos) - return(0); - -//--- STEP 1: Prepare the source price array - double price_source[]; - ArrayResize(price_source, rates_total); - for(int i=0; i 0) - BufferWMA_Half[i] = lwma_sum_half / weight_sum_half; - - // Manual WMA for full period - double lwma_sum_full = 0; - double weight_sum_full = 0; - for(int j=0; j 0) - BufferWMA_Full[i] = lwma_sum_full / weight_sum_full; - - // Calculate Raw HMA - BufferRawHMA[i] = 2 * BufferWMA_Half[i] - BufferWMA_Full[i]; - } - -// --- Second Pass: Calculate final HMA --- - for(int i = start_pos; i < rates_total; i++) - { - // Manual WMA for sqrt period on Raw HMA data - double lwma_sum_sqrt = 0; - double weight_sum_sqrt = 0; - for(int j=0; j 0) - BufferHMA[i] = lwma_sum_sqrt / weight_sum_sqrt; - } - - return(rates_total); - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/HMA_HeikinAshi.mq5 b/Indicators/MyIndicators/HMA_HeikinAshi.mq5 deleted file mode 100644 index 11f9018..0000000 --- a/Indicators/MyIndicators/HMA_HeikinAshi.mq5 +++ /dev/null @@ -1,169 +0,0 @@ -//+------------------------------------------------------------------+ -//| HMA_HeikinAshi.mq5 | -//| Copyright 2025, xxxxxxxx | -//| | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property link "" -#property version "2.00" // Refactored for full recalculation and stability -#property description "Hull Moving Average (HMA) on Heikin Ashi data" - -#include -#include - -//--- Indicator Window and Plot Properties --- -#property indicator_chart_window -#property indicator_buffers 4 -#property indicator_plots 1 - -//--- Plot 1: HMA line -#property indicator_label1 "HA_HMA" -#property indicator_type1 DRAW_LINE -#property indicator_color1 clrDeepPink -#property indicator_style1 STYLE_SOLID -#property indicator_width1 2 - -//--- Enum for selecting Heikin Ashi price source --- -enum ENUM_HA_APPLIED_PRICE - { - HA_PRICE_CLOSE, // Heikin Ashi Close - HA_PRICE_OPEN, // Heikin Ashi Open - HA_PRICE_HIGH, // Heikin Ashi High - HA_PRICE_LOW, // Heikin Ashi Low - }; - -//--- Input Parameters --- -input int InpPeriodHMA = 14; -input ENUM_HA_APPLIED_PRICE InpAppliedPrice = HA_PRICE_CLOSE; - -//--- Indicator Buffers --- -double BufferHA_HMA[]; -double BufferWMA_Half[]; -double BufferWMA_Full[]; -double BufferRawHMA[]; - -//--- Intermediate Heikin Ashi Buffers --- -double ExtHaOpenBuffer[]; -double ExtHaHighBuffer[]; -double ExtHaLowBuffer[]; -double ExtHaCloseBuffer[]; - -//--- Global Objects and Variables --- -int g_ExtPeriodHMA; -CHeikinAshi_Calculator *g_ha_calculator; // Pointer to our Heikin Ashi calculator - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - g_ExtPeriodHMA = (InpPeriodHMA < 1) ? 1 : InpPeriodHMA; - - SetIndexBuffer(0, BufferHA_HMA, INDICATOR_DATA); - SetIndexBuffer(1, BufferWMA_Half, INDICATOR_CALCULATIONS); - SetIndexBuffer(2, BufferWMA_Full, INDICATOR_CALCULATIONS); - SetIndexBuffer(3, BufferRawHMA, INDICATOR_CALCULATIONS); - - ArraySetAsSeries(BufferHA_HMA, false); - ArraySetAsSeries(BufferWMA_Half, false); - ArraySetAsSeries(BufferWMA_Full, false); - ArraySetAsSeries(BufferRawHMA, false); - - IndicatorSetInteger(INDICATOR_DIGITS, _Digits); - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, g_ExtPeriodHMA + (int)MathFloor(MathSqrt(g_ExtPeriodHMA)) - 2); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA_HMA(%d)", g_ExtPeriodHMA)); - -//--- Create the calculator instance - g_ha_calculator = new CHeikinAshi_Calculator(); - if(CheckPointer(g_ha_calculator) == POINTER_INVALID) - { - Print("Error creating CHeikinAshi_Calculator object"); - return(INIT_FAILED); - } - - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { -//--- Free the calculator object to prevent memory leaks - if(CheckPointer(g_ha_calculator) != POINTER_INVALID) - { - delete g_ha_calculator; - g_ha_calculator = NULL; - } - } - -//+------------------------------------------------------------------+ -//| Hull Moving Average on Heikin 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[]) - { - int start_pos = g_ExtPeriodHMA + (int)MathFloor(MathSqrt(g_ExtPeriodHMA)) - 2; - if(rates_total <= start_pos) - return(0); - -//--- Resize intermediate buffers - ArrayResize(ExtHaOpenBuffer, rates_total); - ArrayResize(ExtHaHighBuffer, rates_total); - ArrayResize(ExtHaLowBuffer, rates_total); - ArrayResize(ExtHaCloseBuffer, rates_total); - -//--- STEP 1: Calculate Heikin Ashi bars - g_ha_calculator.Calculate(rates_total, open, high, low, close, - ExtHaOpenBuffer, ExtHaHighBuffer, ExtHaLowBuffer, ExtHaCloseBuffer); - -//--- STEP 2: Select the source Heikin Ashi price array - double ha_price_source[]; - switch(InpAppliedPrice) - { - case HA_PRICE_OPEN: - ArrayCopy(ha_price_source, ExtHaOpenBuffer); - break; - case HA_PRICE_HIGH: - ArrayCopy(ha_price_source, ExtHaHighBuffer); - break; - case HA_PRICE_LOW: - ArrayCopy(ha_price_source, ExtHaLowBuffer); - break; - default: - ArrayCopy(ha_price_source, ExtHaCloseBuffer); - break; - } - -//--- STEP 3: Calculate all HMA components in a single, efficient loop - int period_half = (int)MathMax(1, MathRound(g_ExtPeriodHMA / 2.0)); - int period_sqrt = (int)MathMax(1, MathRound(MathSqrt(g_ExtPeriodHMA))); - - for(int i = g_ExtPeriodHMA - 1; i < rates_total; i++) - { - // Calculate the two base WMAs - BufferWMA_Half[i] = LinearWeightedMA(i, period_half, ha_price_source); - BufferWMA_Full[i] = LinearWeightedMA(i, g_ExtPeriodHMA, ha_price_source); - - // Calculate the raw HMA - BufferRawHMA[i] = 2 * BufferWMA_Half[i] - BufferWMA_Full[i]; - } - -//--- STEP 4: Smooth the raw HMA with the final WMA - for(int i = start_pos; i < rates_total; i++) - { - BufferHA_HMA[i] = LinearWeightedMA(i, period_sqrt, BufferRawHMA); - } - - return(rates_total); - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/Holt_Channel.mq5 b/Indicators/MyIndicators/Holt_Channel.mq5 deleted file mode 100644 index 198c669..0000000 --- a/Indicators/MyIndicators/Holt_Channel.mq5 +++ /dev/null @@ -1,125 +0,0 @@ -//+------------------------------------------------------------------+ -//| Holt_Channel.mq5 | -//| Copyright 2025, xxxxxxxx| -//| | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property version "1.00" -#property description "Holt's Forecast Channel. Displays a channel based on" -#property description "the multi-period forecast of the Holt's Linear Trend model." - -#property indicator_chart_window -#property indicator_buffers 3 -#property indicator_plots 3 - -#include - -//--- Plot 1: Upper Band -#property indicator_label1 "Upper Channel" -#property indicator_type1 DRAW_LINE -#property indicator_color1 clrSilver -#property indicator_style1 STYLE_DOT -#property indicator_width1 1 - -//--- Plot 2: Lower Band -#property indicator_label2 "Lower Channel" -#property indicator_type2 DRAW_LINE -#property indicator_color2 clrSilver -#property indicator_style2 STYLE_DOT -#property indicator_width2 1 - -//--- Plot 3: Center Line (Holt MA) -#property indicator_label3 "Center Line" -#property indicator_type3 DRAW_LINE -#property indicator_color3 clrMediumSeaGreen -#property indicator_style3 STYLE_SOLID -#property indicator_width3 2 - -//--- Input Parameters --- -input int InpPeriod = 20; -input double InpAlpha = 0.1; -input double InpBeta = 0.05; -input int InpForecastPeriod = 5; // Forecast period for the channel -input ENUM_APPLIED_PRICE InpSourcePrice = PRICE_CLOSE; - -//--- Indicator Buffers --- -double BufferUpperBand[]; -double BufferLowerBand[]; -double BufferCenterLine[]; - -//--- Global calculator object --- -CHoltMACalculator *g_calculator; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - SetIndexBuffer(0, BufferUpperBand, INDICATOR_DATA); - SetIndexBuffer(1, BufferLowerBand, INDICATOR_DATA); - SetIndexBuffer(2, BufferCenterLine, INDICATOR_DATA); - - ArraySetAsSeries(BufferUpperBand, false); - ArraySetAsSeries(BufferLowerBand, false); - ArraySetAsSeries(BufferCenterLine, false); - - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, 2); - PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, 2); - PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, 2); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("Holt Channel(%d, %d)", InpPeriod, InpForecastPeriod)); - - g_calculator = new CHoltMACalculator(); - if(CheckPointer(g_calculator) == POINTER_INVALID || !g_calculator.Init(InpPeriod, InpAlpha, InpBeta)) - { - Print("Failed to initialize Holt MA Calculator."); - return(INIT_FAILED); - } - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { - if(CheckPointer(g_calculator) != POINTER_INVALID) - delete g_calculator; - } - -//+------------------------------------------------------------------+ -//| Custom indicator iteration 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(CheckPointer(g_calculator) != POINTER_INVALID) - { - //--- Step 1: Run the main calculation to get the core components - double trend_buffer[]; - g_calculator.Calculate(rates_total, InpSourcePrice, open, high, low, close, BufferCenterLine, trend_buffer); - - //--- Step 2: Calculate the channel bands based on the forecast and trend - int forecast_period = (InpForecastPeriod < 1) ? 1 : InpForecastPeriod; - - for(int i = 2; i < rates_total; i++) - { - // Reconstruct the Level component: Level = Forecast - Trend - double level = BufferCenterLine[i] - trend_buffer[i]; - - // Calculate the multi-period forecast for the bands - BufferUpperBand[i] = level + forecast_period * trend_buffer[i]; - BufferLowerBand[i] = level - forecast_period * trend_buffer[i]; - } - } - return(rates_total); - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/Holt_Channel_HeikinAshi.mq5 b/Indicators/MyIndicators/Holt_Channel_HeikinAshi.mq5 deleted file mode 100644 index 0ca8695..0000000 --- a/Indicators/MyIndicators/Holt_Channel_HeikinAshi.mq5 +++ /dev/null @@ -1,107 +0,0 @@ -//+------------------------------------------------------------------+ -//| Holt_Channel_HeikinAshi.mq5 | -//| Copyright 2025, xxxxxxxx| -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property version "1.00" -#property description "Holt's Forecast Channel on Heikin Ashi data." - -#property indicator_chart_window -#property indicator_buffers 3 -#property indicator_plots 3 - -#include - -//--- Plot 1: Upper Band -#property indicator_label1 "Upper Channel (HA)" -#property indicator_type1 DRAW_LINE -#property indicator_color1 clrSilver -#property indicator_style1 STYLE_DOT -#property indicator_width1 1 - -//--- Plot 2: Lower Band -#property indicator_label2 "Lower Channel (HA)" -#property indicator_type2 DRAW_LINE -#property indicator_color2 clrSilver -#property indicator_style2 STYLE_DOT -#property indicator_width2 1 - -//--- Plot 3: Center Line (Holt MA) -#property indicator_label3 "Center Line (HA)" -#property indicator_type3 DRAW_LINE -#property indicator_color3 clrMediumSeaGreen -#property indicator_style3 STYLE_SOLID -#property indicator_width3 2 - -//--- Input Parameters --- -input int InpPeriod = 20; -input double InpAlpha = 0.1; -input double InpBeta = 0.05; -input int InpForecastPeriod = 5; - -//--- Indicator Buffers --- -double BufferUpperBand[]; -double BufferLowerBand[]; -double BufferCenterLine[]; - -//--- Global calculator object --- -CHoltMACalculator_HA *g_calculator; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - SetIndexBuffer(0, BufferUpperBand, INDICATOR_DATA); - SetIndexBuffer(1, BufferLowerBand, INDICATOR_DATA); - SetIndexBuffer(2, BufferCenterLine, INDICATOR_DATA); - - ArraySetAsSeries(BufferUpperBand, false); - ArraySetAsSeries(BufferLowerBand, false); - ArraySetAsSeries(BufferCenterLine, false); - - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, 2); - PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, 2); - PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, 2); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("Holt Channel HA(%d, %d)", InpPeriod, InpForecastPeriod)); - - g_calculator = new CHoltMACalculator_HA(); - if(CheckPointer(g_calculator) == POINTER_INVALID || !g_calculator.Init(InpPeriod, InpAlpha, InpBeta)) - { - Print("Failed to initialize Holt MA HA Calculator."); - return(INIT_FAILED); - } - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { - if(CheckPointer(g_calculator) != POINTER_INVALID) - delete g_calculator; - } - -//+------------------------------------------------------------------+ -//| Custom indicator iteration function. | -//+------------------------------------------------------------------+ -int OnCalculate(const int rates_total, const int, const datetime&[], const double &open[], const double &high[], const double &low[], const double &close[], const long&[], const long&[], const int&[]) - { - if(CheckPointer(g_calculator) != POINTER_INVALID) - { - double trend_buffer[], level_buffer[]; - g_calculator.Calculate(rates_total, PRICE_CLOSE, open, high, low, close, BufferCenterLine, trend_buffer, level_buffer); - - int forecast_period = (InpForecastPeriod < 1) ? 1 : InpForecastPeriod; - - for(int i = 2; i < rates_total; i++) - { - BufferUpperBand[i] = level_buffer[i] + forecast_period * trend_buffer[i]; - BufferLowerBand[i] = level_buffer[i] - forecast_period * trend_buffer[i]; - } - } - return(rates_total); - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/Holt_MA.mq5 b/Indicators/MyIndicators/Holt_MA.mq5 deleted file mode 100644 index c346738..0000000 --- a/Indicators/MyIndicators/Holt_MA.mq5 +++ /dev/null @@ -1,85 +0,0 @@ -//+------------------------------------------------------------------+ -//| Holt_MA.mq5 | -//| Copyright 2025, xxxxxxxx| -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property version "2.00" -#property description "Holt's Linear Trend Method (Double Exponential Smoothing)." - -#property indicator_chart_window -#property indicator_buffers 1 -#property indicator_plots 1 - -#include - -//--- Plot 1: Holt MA Forecast Line -#property indicator_label1 "Holt MA" -#property indicator_type1 DRAW_LINE -#property indicator_color1 clrMediumSeaGreen -#property indicator_style1 STYLE_SOLID -#property indicator_width1 2 - -//--- Input Parameters --- -input int InpPeriod = 20; -input double InpAlpha = 0.1; -input double InpBeta = 0.05; -input ENUM_APPLIED_PRICE InpSourcePrice = PRICE_CLOSE; - -//--- Indicator Buffers --- -double BufferHoltMA[]; - -//--- Global calculator object --- -CHoltMACalculator *g_calculator; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - SetIndexBuffer(0, BufferHoltMA, INDICATOR_DATA); - ArraySetAsSeries(BufferHoltMA, false); - - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, 2); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("Holt MA(%d, %.2f, %.2f)", InpPeriod, InpAlpha, InpBeta)); - - g_calculator = new CHoltMACalculator(); - if(CheckPointer(g_calculator) == POINTER_INVALID || !g_calculator.Init(InpPeriod, InpAlpha, InpBeta)) - { - Print("Failed to initialize Holt MA Calculator."); - return(INIT_FAILED); - } - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { - if(CheckPointer(g_calculator) != POINTER_INVALID) - delete g_calculator; - } - -//+------------------------------------------------------------------+ -//| Custom indicator iteration 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(CheckPointer(g_calculator) != POINTER_INVALID) - { - double dummy_trend[]; - g_calculator.Calculate(rates_total, InpSourcePrice, open, high, low, close, BufferHoltMA, dummy_trend); - } - return(rates_total); - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/Holt_MA_HeikinAshi.mq5 b/Indicators/MyIndicators/Holt_MA_HeikinAshi.mq5 deleted file mode 100644 index 708b5d6..0000000 --- a/Indicators/MyIndicators/Holt_MA_HeikinAshi.mq5 +++ /dev/null @@ -1,75 +0,0 @@ -//+------------------------------------------------------------------+ -//| Holt_MA_HeikinAshi.mq5 | -//| Copyright 2025, xxxxxxxx| -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property version "1.00" -#property description "Holt's Linear Trend Method on Heikin Ashi data." - -#property indicator_chart_window -#property indicator_buffers 1 -#property indicator_plots 1 - -#include - -//--- Plot 1: Holt MA Forecast Line -#property indicator_label1 "Holt MA (HA)" -#property indicator_type1 DRAW_LINE -#property indicator_color1 clrMediumSeaGreen -#property indicator_style1 STYLE_SOLID -#property indicator_width1 2 - -//--- Input Parameters --- -input int InpPeriod = 20; -input double InpAlpha = 0.1; -input double InpBeta = 0.05; - -//--- Indicator Buffers --- -double BufferHoltMA[]; - -//--- Global calculator object --- -CHoltMACalculator_HA *g_calculator; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - SetIndexBuffer(0, BufferHoltMA, INDICATOR_DATA); - ArraySetAsSeries(BufferHoltMA, false); - - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, 2); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("Holt MA HA(%d, %.2f, %.2f)", InpPeriod, InpAlpha, InpBeta)); - - g_calculator = new CHoltMACalculator_HA(); - if(CheckPointer(g_calculator) == POINTER_INVALID || !g_calculator.Init(InpPeriod, InpAlpha, InpBeta)) - { - Print("Failed to initialize Holt MA HA Calculator."); - return(INIT_FAILED); - } - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { - if(CheckPointer(g_calculator) != POINTER_INVALID) - delete g_calculator; - } - -//+------------------------------------------------------------------+ -//| Custom indicator iteration function. | -//+------------------------------------------------------------------+ -int OnCalculate(const int rates_total, const int, const datetime&[], const double &open[], const double &high[], const double &low[], const double &close[], const long&[], const long&[], const int&[]) - { - if(CheckPointer(g_calculator) != POINTER_INVALID) - { - double dummy_trend[], dummy_level[]; - g_calculator.Calculate(rates_total, PRICE_CLOSE, open, high, low, close, BufferHoltMA, dummy_trend, dummy_level); - } - return(rates_total); - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/Holt_Oscillator.mq5 b/Indicators/MyIndicators/Holt_Oscillator.mq5 deleted file mode 100644 index 4895dd7..0000000 --- a/Indicators/MyIndicators/Holt_Oscillator.mq5 +++ /dev/null @@ -1,89 +0,0 @@ -//+------------------------------------------------------------------+ -//| Holt_Oscillator.mq5 | -//| Copyright 2025, xxxxxxxx| -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property version "2.00" -#property description "Holt's Trend Oscillator. Shows the smoothed trend component." - -#property indicator_separate_window -#property indicator_buffers 1 -#property indicator_plots 1 -#property indicator_level1 0.0 -#property indicator_levelstyle STYLE_DOT -#property indicator_levelcolor clrGray - -#include - -//--- Plot 1: Holt Trend Oscillator -#property indicator_label1 "Holt Trend" -#property indicator_type1 DRAW_HISTOGRAM -#property indicator_color1 clrSeaGreen, clrTomato -#property indicator_style1 STYLE_SOLID -#property indicator_width1 2 - -//--- Input Parameters --- -input int InpPeriod = 20; -input double InpAlpha = 0.1; -input double InpBeta = 0.05; -input ENUM_APPLIED_PRICE InpSourcePrice = PRICE_CLOSE; - -//--- Indicator Buffers --- -double BufferOscillator[]; - -//--- Global calculator object --- -CHoltMACalculator *g_calculator; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - SetIndexBuffer(0, BufferOscillator, INDICATOR_DATA); - ArraySetAsSeries(BufferOscillator, false); - - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, 2); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("Holt Osc(%d, %.2f, %.2f)", InpPeriod, InpAlpha, InpBeta)); - IndicatorSetInteger(INDICATOR_DIGITS, _Digits+2); - - g_calculator = new CHoltMACalculator(); - if(CheckPointer(g_calculator) == POINTER_INVALID || !g_calculator.Init(InpPeriod, InpAlpha, InpBeta)) - { - Print("Failed to initialize Holt MA Calculator."); - return(INIT_FAILED); - } - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { - if(CheckPointer(g_calculator) != POINTER_INVALID) - delete g_calculator; - } - -//+------------------------------------------------------------------+ -//| Custom indicator iteration 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(CheckPointer(g_calculator) != POINTER_INVALID) - { - double dummy_forecast[]; - g_calculator.Calculate(rates_total, InpSourcePrice, open, high, low, close, dummy_forecast, BufferOscillator); - } - return(rates_total); - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/Holt_Oscillator_HeikinAshi.mq5 b/Indicators/MyIndicators/Holt_Oscillator_HeikinAshi.mq5 deleted file mode 100644 index 29cee5c..0000000 --- a/Indicators/MyIndicators/Holt_Oscillator_HeikinAshi.mq5 +++ /dev/null @@ -1,79 +0,0 @@ -//+------------------------------------------------------------------+ -//| Holt_Oscillator_HeikinAshi.mq5 | -//| Copyright 2025, xxxxxxxx| -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property version "1.00" -#property description "Holt's Trend Oscillator on Heikin Ashi data." - -#property indicator_separate_window -#property indicator_buffers 1 -#property indicator_plots 1 -#property indicator_level1 0.0 -#property indicator_levelstyle STYLE_DOT -#property indicator_levelcolor clrGray - -#include - -//--- Plot 1: Holt Trend Oscillator -#property indicator_label1 "Holt Trend (HA)" -#property indicator_type1 DRAW_HISTOGRAM -#property indicator_color1 clrSeaGreen, clrTomato -#property indicator_style1 STYLE_SOLID -#property indicator_width1 2 - -//--- Input Parameters --- -input int InpPeriod = 20; -input double InpAlpha = 0.1; -input double InpBeta = 0.05; - -//--- Indicator Buffers --- -double BufferOscillator[]; - -//--- Global calculator object --- -CHoltMACalculator_HA *g_calculator; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - SetIndexBuffer(0, BufferOscillator, INDICATOR_DATA); - ArraySetAsSeries(BufferOscillator, false); - - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, 2); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("Holt Osc HA(%d, %.2f, %.2f)", InpPeriod, InpAlpha, InpBeta)); - IndicatorSetInteger(INDICATOR_DIGITS, _Digits+2); - - g_calculator = new CHoltMACalculator_HA(); - if(CheckPointer(g_calculator) == POINTER_INVALID || !g_calculator.Init(InpPeriod, InpAlpha, InpBeta)) - { - Print("Failed to initialize Holt MA HA Calculator."); - return(INIT_FAILED); - } - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { - if(CheckPointer(g_calculator) != POINTER_INVALID) - delete g_calculator; - } - -//+------------------------------------------------------------------+ -//| Custom indicator iteration function. | -//+------------------------------------------------------------------+ -int OnCalculate(const int rates_total, const int, const datetime&[], const double &open[], const double &high[], const double &low[], const double &close[], const long&[], const long&[], const int&[]) - { - if(CheckPointer(g_calculator) != POINTER_INVALID) - { - double dummy_forecast[], dummy_level[]; - g_calculator.Calculate(rates_total, PRICE_CLOSE, open, high, low, close, dummy_forecast, BufferOscillator, dummy_level); - } - return(rates_total); - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/KeltnerChannel.md b/Indicators/MyIndicators/KeltnerChannel.md deleted file mode 100644 index 4d3be96..0000000 --- a/Indicators/MyIndicators/KeltnerChannel.md +++ /dev/null @@ -1,72 +0,0 @@ -# Keltner Channel - -## 1. Summary (Introduction) - -The Keltner Channel is a volatility-based technical indicator developed by Chester W. Keltner in his 1960 book "How to Make Money in Commodities." The modern version was later updated by Linda Bradford Raschke, who introduced the use of an Exponential Moving Average (EMA) for the centerline and the Average True Range (ATR) for calculating the channel width. - -The indicator consists of three lines: a central moving average line, an upper band, and a lower band. It is primarily used to identify trend direction, spot potential trend reversals or continuations through breakouts, and gauge volatility. - -## 2. Mathematical Foundations and Calculation Logic - -The Keltner Channel is constructed by creating a channel around a central moving average, with the width of the channel determined by the market's volatility. - -### Required Components - -- **Middle Line (Basis):** A moving average of a selected price. The most common version uses an Exponential Moving Average (EMA) of the Typical Price `(High + Low + Close) / 3`. -- **ATR (Average True Range):** A measure of market volatility. -- **Factor (Multiplier):** A user-defined multiplier that adjusts the width of the channel. - -### Calculation Steps (Algorithm) - -1. **Calculate the Middle Line:** Compute the moving average (e.g., 20-period EMA) of the selected source price. - $\text{Middle Line}_i = \text{MA}(\text{Source Price}, \text{MA Period})_i$ - -2. **Calculate the Average True Range (ATR):** Compute the ATR for a given period (e.g., 10). - -3. **Calculate the Upper and Lower Bands:** Add and subtract a multiple of the ATR from the middle line. - $\text{Upper Band}_i = \text{Middle Line}_i + (\text{Factor} \times \text{ATR}_i)$ - $\text{Lower Band}_i = \text{Middle Line}_i - (\text{Factor} \times \text{ATR}_i)$ - -## 3. MQL5 Implementation Details - -Our MQL5 implementations were refactored based on our core principles to create three distinct, robust, and stable versions of the Keltner Channel. - -- **Stability via Full Recalculation:** All versions employ a "brute-force" full recalculation within the `OnCalculate` function. This is our standard practice to ensure maximum stability and prevent calculation errors, especially with the recursive calculations involved in EMA and ATR. - -- **Robust Manual Calculations:** To ensure 100% accuracy and stability within our `non-timeseries` calculation model, we use fully manual implementations for all moving average types (SMA, EMA, SMMA, LWMA) and for the Wilder's smoothing used in the ATR calculation. Each recursive calculation (EMA, SMMA, ATR) is carefully initialized with a simple average to prevent floating-point overflows. - -- **Clear, Staged Calculation:** The `OnCalculate` function in each version is structured into clear, sequential steps (e.g., Price Preparation, TR Calculation, Integrated MA/ATR/Band Calculation), which improves code readability and maintainability. - -### Our Three Keltner Channel Versions - -1. **Standard Version (`KeltnerChannel.mq5`):** - - - **Concept:** The classic, industry-standard implementation. - - **Logic:** The middle line is a moving average of **standard prices** (e.g., Typical Price). The channel width is determined by the ATR of **standard candlesticks**. - - **Implementation:** To guarantee perfect accuracy with the MetaTrader platform's built-in indicators, this version uses an `iMA` handle for the middle line while calculating the standard ATR manually for consistency. - -2. **Hybrid Heikin Ashi Version (`KeltnerChannel_HeikinAshi.mq5`):** - - - **Concept:** Combines a smoothed Heikin Ashi trend line with real market volatility. - - **Logic:** The middle line is a moving average of **Heikin Ashi prices**. The channel width is determined by the ATR of **standard candlesticks**. - - **Implementation:** Fully self-contained. It uses our `CHeikinAshi_Calculator` for the price data and calculates both the HA-based MA and the standard ATR manually. - -3. **"Pure" Heikin Ashi Version (`KeltnerChannel_HeikinAshi_Pure.mq5`):** - - **Concept:** A fully smoothed channel that reflects the volatility of the underlying Heikin Ashi trend. - - **Logic:** The middle line is a moving average of **Heikin Ashi prices**. The channel width is determined by the ATR calculated from the **Heikin Ashi candlesticks**. - - **Implementation:** Fully self-contained and manual. This version results in narrower, smoother channels compared to the other two. - -## 4. Parameters - -- **MA Period (`InpMaPeriod`):** The lookback period for the middle line moving average. Default is `20`. -- **MA Method (`InpMaMethod`):** The type of moving average for the middle line. Default is `MODE_EMA`. -- **Applied Price (`InpAppliedPrice`):** The source price for the middle line. Default is `PRICE_TYPICAL`. -- **ATR Period (`InpAtrPeriod`):** The lookback period for the ATR calculation. Default is `10`. -- **Multiplier (`InpMultiplier`):** The factor to multiply the ATR by. Default is `2.0`. - -## 5. Usage and Interpretation - -- **Trend Identification:** The slope of the channel helps identify the trend. An upward-sloping channel suggests an uptrend, while a downward-sloping one suggests a downtrend. The middle line acts as the mean of the trend. -- **Breakouts:** A strong close above the upper band can signal the start or continuation of an uptrend. A strong close below the lower band can signal the start or continuation of a downtrend. -- **Overbought/Oversold (in Ranges):** In a sideways market, moves to the upper band can be seen as overbought, and moves to the lower band can be seen as oversold, presenting potential reversal opportunities. -- **Caution:** Like all channel indicators, Keltner Channels can give false breakout signals. It is often used in conjunction with momentum oscillators (like RSI or Stochastics) to confirm the strength of a move. diff --git a/Indicators/MyIndicators/KeltnerChannel.mq5 b/Indicators/MyIndicators/KeltnerChannel.mq5 deleted file mode 100644 index 9654958..0000000 --- a/Indicators/MyIndicators/KeltnerChannel.mq5 +++ /dev/null @@ -1,158 +0,0 @@ -//+------------------------------------------------------------------+ -//| KeltnerChannel.mq5 | -//| Copyright 2025, xxxxxxxx | -//| | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property version "4.00" // Final Consensus: iMA handle for Middle Line, manual ATR -#property description "Keltner Channels based on ATR" - -#include // Only needed for manual ATR's SMA init - -//--- Indicator Window and Plot Properties --- -#property indicator_chart_window -#property indicator_buffers 4 // Upper, Lower, Middle, and ATR -#property indicator_plots 3 - -//--- Plot 1: Upper Band -#property indicator_label1 "Upper Band" -#property indicator_type1 DRAW_LINE -#property indicator_color1 clrDodgerBlue -#property indicator_style1 STYLE_DOT - -//--- Plot 2: Lower Band -#property indicator_label2 "Lower Band" -#property indicator_type2 DRAW_LINE -#property indicator_color2 clrDodgerBlue -#property indicator_style2 STYLE_DOT - -//--- Plot 3: Middle Band (Basis) -#property indicator_label3 "Basis" -#property indicator_type3 DRAW_LINE -#property indicator_color3 clrDodgerBlue -#property indicator_style3 STYLE_SOLID -#property indicator_width3 1 - -//--- Input Parameters --- -input int InpMaPeriod = 20; -input ENUM_MA_METHOD InpMaMethod = MODE_EMA; -input ENUM_APPLIED_PRICE InpAppliedPrice = PRICE_TYPICAL; -input int InpAtrPeriod = 10; -input double InpMultiplier = 2.0; - -//--- Indicator Buffers --- -double BufferUpper[]; -double BufferLower[]; -double BufferMiddle[]; -double BufferATR[]; - -//--- Global Variables --- -int g_ExtMaPeriod, g_ExtAtrPeriod; -double g_ExtMultiplier; -int g_handle_ma; // Handle for the middle line MA - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - g_ExtMaPeriod = (InpMaPeriod < 1) ? 1 : InpMaPeriod; - g_ExtAtrPeriod = (InpAtrPeriod < 1) ? 1 : InpAtrPeriod; - g_ExtMultiplier = (InpMultiplier <= 0) ? 2.0 : InpMultiplier; - - SetIndexBuffer(0, BufferUpper, INDICATOR_DATA); - SetIndexBuffer(1, BufferLower, INDICATOR_DATA); - SetIndexBuffer(2, BufferMiddle, INDICATOR_DATA); - SetIndexBuffer(3, BufferATR, INDICATOR_CALCULATIONS); - - ArraySetAsSeries(BufferUpper, false); - ArraySetAsSeries(BufferLower, false); - ArraySetAsSeries(BufferMiddle, false); - ArraySetAsSeries(BufferATR, false); - - g_handle_ma = iMA(_Symbol, _Period, g_ExtMaPeriod, 0, InpMaMethod, InpAppliedPrice); - if(g_handle_ma == INVALID_HANDLE) - { - Print("Error creating iMA handle."); - return(INIT_FAILED); - } - - IndicatorSetInteger(INDICATOR_DIGITS, _Digits); - int draw_begin = MathMax(g_ExtMaPeriod, g_ExtAtrPeriod); - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, draw_begin); - PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, draw_begin); - PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, g_ExtMaPeriod - 1); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("KC(%d,%d,%.1f)", g_ExtMaPeriod, g_ExtAtrPeriod, g_ExtMultiplier)); - - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { - IndicatorRelease(g_handle_ma); - } - -//+------------------------------------------------------------------+ -//| Keltner Channel 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[]) - { - int start_pos = MathMax(g_ExtMaPeriod, g_ExtAtrPeriod); - if(rates_total <= start_pos) - return(0); - -//--- STEP 1: Get Middle Line (MA) values from handle for perfect accuracy - if(CopyBuffer(g_handle_ma, 0, 0, rates_total, BufferMiddle) < rates_total) - { - Print("Error copying iMA buffer data."); - } - -//--- STEP 2: Calculate True Range manually - double tr[]; - ArrayResize(tr, rates_total); - for(int i = 1; i < rates_total; i++) - { - tr[i] = MathMax(high[i], close[i-1]) - MathMin(low[i], close[i-1]); - } - -//--- STEP 3: Calculate ATR and Bands - for(int i = 1; i < rates_total; i++) - { - // --- Calculate ATR (using Wilder's smoothing) --- - if(i == g_ExtAtrPeriod) // Initialization with SMA - { - double atr_sum = 0; - for(int j=1; j<=g_ExtAtrPeriod; j++) - atr_sum += tr[j]; - BufferATR[i] = atr_sum / g_ExtAtrPeriod; - } - else - if(i > g_ExtAtrPeriod) // Recursive calculation - { - BufferATR[i] = (BufferATR[i-1] * (g_ExtAtrPeriod - 1) + tr[i]) / g_ExtAtrPeriod; - } - - // --- Calculate Upper and Lower bands --- - if(i >= start_pos) - { - BufferUpper[i] = BufferMiddle[i] + (BufferATR[i] * g_ExtMultiplier); - BufferLower[i] = BufferMiddle[i] - (BufferATR[i] * g_ExtMultiplier); - } - } - - return(rates_total); - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/KeltnerChannel_HeikinAshi.mq5 b/Indicators/MyIndicators/KeltnerChannel_HeikinAshi.mq5 deleted file mode 100644 index 94dd21f..0000000 --- a/Indicators/MyIndicators/KeltnerChannel_HeikinAshi.mq5 +++ /dev/null @@ -1,255 +0,0 @@ -//+------------------------------------------------------------------+ -//| KeltnerChannel_HeikinAshi.mq5 | -//| Copyright 2025, xxxxxxxx | -//| | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property link "" -#property version "3.01" // Corrected OnCalculate signature and SMA logic -#property description "Keltner Channels with HA middle line and Standard ATR" - -#include - -//--- Indicator Window and Plot Properties --- -#property indicator_chart_window -#property indicator_buffers 4 // Upper, Lower, Middle, and ATR -#property indicator_plots 3 - -//--- Plot 1: Upper Band -#property indicator_label1 "HA_Upper" -#property indicator_type1 DRAW_LINE -#property indicator_color1 clrDodgerBlue -#property indicator_style1 STYLE_DOT - -//--- Plot 2: Lower Band -#property indicator_label2 "HA_Lower" -#property indicator_type2 DRAW_LINE -#property indicator_color2 clrDodgerBlue -#property indicator_style2 STYLE_DOT - -//--- Plot 3: Middle Band (Basis) -#property indicator_label3 "HA_Basis" -#property indicator_type3 DRAW_LINE -#property indicator_color3 clrDodgerBlue -#property indicator_style3 STYLE_SOLID -#property indicator_width3 1 - -//--- Enum for selecting Heikin Ashi price source for the middle line --- -enum ENUM_HA_APPLIED_PRICE - { - HA_PRICE_CLOSE, // Heikin Ashi Close - HA_PRICE_OPEN, // Heikin Ashi Open - HA_PRICE_HIGH, // Heikin Ashi High - HA_PRICE_LOW, // Heikin Ashi Low - }; - -//--- Input Parameters --- -input int InpMaPeriod = 20; -input ENUM_MA_METHOD InpMaMethod = MODE_EMA; -input ENUM_HA_APPLIED_PRICE InpAppliedPrice = HA_PRICE_CLOSE; -input int InpAtrPeriod = 10; -input double InpMultiplier = 2.0; - -//--- Indicator Buffers --- -double BufferUpper[]; -double BufferLower[]; -double BufferMiddle[]; -double BufferATR[]; - -//--- Global Objects and Variables --- -int g_ExtMaPeriod, g_ExtAtrPeriod; -double g_ExtMultiplier; -CHeikinAshi_Calculator *g_ha_calculator; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - g_ExtMaPeriod = (InpMaPeriod < 1) ? 1 : InpMaPeriod; - g_ExtAtrPeriod = (InpAtrPeriod < 1) ? 1 : InpAtrPeriod; - g_ExtMultiplier = (InpMultiplier <= 0) ? 2.0 : InpMultiplier; - - SetIndexBuffer(0, BufferUpper, INDICATOR_DATA); - SetIndexBuffer(1, BufferLower, INDICATOR_DATA); - SetIndexBuffer(2, BufferMiddle, INDICATOR_DATA); - SetIndexBuffer(3, BufferATR, INDICATOR_CALCULATIONS); - - ArraySetAsSeries(BufferUpper, false); - ArraySetAsSeries(BufferLower, false); - ArraySetAsSeries(BufferMiddle, false); - ArraySetAsSeries(BufferATR, false); - - IndicatorSetInteger(INDICATOR_DIGITS, _Digits); - int draw_begin = MathMax(g_ExtMaPeriod, g_ExtAtrPeriod); - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, draw_begin); - PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, draw_begin); - PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, g_ExtMaPeriod - 1); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA_KC(%d,%d,%.1f)", g_ExtMaPeriod, g_ExtAtrPeriod, g_ExtMultiplier)); - - g_ha_calculator = new CHeikinAshi_Calculator(); - if(CheckPointer(g_ha_calculator) == POINTER_INVALID) - { - Print("Error creating CHeikinAshi_Calculator object"); - return(INIT_FAILED); - } - - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { - if(CheckPointer(g_ha_calculator) != POINTER_INVALID) - { - delete g_ha_calculator; - g_ha_calculator = NULL; - } - } - -//+------------------------------------------------------------------+ -//| Keltner Channel on Heikin Ashi calculation function. | -//+------------------------------------------------------------------+ -// --- FIX: Restored the full, correct function signature --- -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[]) - { - int start_pos = MathMax(g_ExtMaPeriod, g_ExtAtrPeriod); - if(rates_total <= start_pos) - return(0); - -//--- Intermediate Heikin Ashi Buffers - double ha_open[], ha_high[], ha_low[], ha_close[]; - ArrayResize(ha_open, rates_total); - ArrayResize(ha_high, rates_total); - ArrayResize(ha_low, rates_total); - ArrayResize(ha_close, rates_total); - -//--- STEP 1: Calculate Heikin Ashi bars - g_ha_calculator.Calculate(rates_total, open, high, low, close, ha_open, ha_high, ha_low, ha_close); - -//--- STEP 2: Calculate Standard True Range manually - double tr[]; - ArrayResize(tr, rates_total); - for(int i = 1; i < rates_total; i++) - { - tr[i] = MathMax(high[i], close[i-1]) - MathMin(low[i], close[i-1]); - } - -//--- STEP 3: Prepare HA price source for the middle line - double ha_price_source[]; - ArrayResize(ha_price_source, rates_total); - switch(InpAppliedPrice) - { - case HA_PRICE_OPEN: - ArrayCopy(ha_price_source, ha_open); - break; - case HA_PRICE_HIGH: - ArrayCopy(ha_price_source, ha_high); - break; - case HA_PRICE_LOW: - ArrayCopy(ha_price_source, ha_low); - break; - default: - ArrayCopy(ha_price_source, ha_close); - break; - } - -//--- STEP 4: Calculate ATR, Middle, Upper, and Lower bands - double sma_sum = 0; - for(int i = 1; i < rates_total; i++) - { - // --- Calculate Standard ATR (using Wilder's smoothing) --- - if(i == g_ExtAtrPeriod) // Initialization with manual SMA - { - double atr_sum = 0; - for(int j=1; j<=g_ExtAtrPeriod; j++) - atr_sum += tr[j]; - BufferATR[i] = atr_sum / g_ExtAtrPeriod; - } - else - if(i > g_ExtAtrPeriod) // Recursive calculation - { - BufferATR[i] = (BufferATR[i-1] * (g_ExtAtrPeriod - 1) + tr[i]) / g_ExtAtrPeriod; - } - - // --- Calculate the middle line (MA on HA price) --- - if(i >= g_ExtMaPeriod - 1) - { - switch(InpMaMethod) - { - case MODE_EMA: - case MODE_SMMA: - if(i == g_ExtMaPeriod - 1) - { - double sum = 0; - for(int j=0; j 0) - BufferMiddle[i] = lwma_sum / weight_sum; - } - break; - default: // MODE_SMA - if(i == g_ExtMaPeriod - 1) // First calculation - { - sma_sum = 0; // Re-initialize sum for the first calculation point - for(int j=0; j= start_pos) - { - BufferUpper[i] = BufferMiddle[i] + (BufferATR[i] * g_ExtMultiplier); - BufferLower[i] = BufferMiddle[i] - (BufferATR[i] * g_ExtMultiplier); - } - } - - return(rates_total); - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/KeltnerChannel_HeikinAshi_Pure.mq5 b/Indicators/MyIndicators/KeltnerChannel_HeikinAshi_Pure.mq5 deleted file mode 100644 index 1352dd1..0000000 --- a/Indicators/MyIndicators/KeltnerChannel_HeikinAshi_Pure.mq5 +++ /dev/null @@ -1,230 +0,0 @@ -//+------------------------------------------------------------------+ -//| KeltnerChannel_HeikinAshi_Pure.mq5| -//| Copyright 2025, xxxxxxxx | -//| | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property link "" -#property version "3.01" // Corrected include and completed switch-case -#property description "Keltner Channels based entirely on Heikin Ashi data (including ATR)" - -#include -#include // <-- FIX: Corrected filename - -//--- Indicator Window and Plot Properties --- -#property indicator_chart_window -#property indicator_buffers 4 // Upper, Lower, Middle, and Smoothed ATR -#property indicator_plots 3 - -//--- Plot 1: Upper Band -#property indicator_label1 "HA_Upper" -#property indicator_type1 DRAW_LINE -#property indicator_color1 clrDodgerBlue -#property indicator_style1 STYLE_DOT - -//--- Plot 2: Lower Band -#property indicator_label2 "HA_Lower" -#property indicator_type2 DRAW_LINE -#property indicator_color2 clrDodgerBlue -#property indicator_style2 STYLE_DOT - -//--- Plot 3: Middle Band (Basis) -#property indicator_label3 "HA_Basis" -#property indicator_type3 DRAW_LINE -#property indicator_color3 clrDodgerBlue -#property indicator_style3 STYLE_SOLID -#property indicator_width3 1 - -//--- Enum for selecting Heikin Ashi price source for the middle line --- -enum ENUM_HA_APPLIED_PRICE - { - HA_PRICE_CLOSE, // Heikin Ashi Close - HA_PRICE_OPEN, // Heikin Ashi Open - HA_PRICE_HIGH, // Heikin Ashi High - HA_PRICE_LOW, // Heikin Ashi Low - }; - -//--- Input Parameters --- -input int InpMaPeriod = 20; -input ENUM_MA_METHOD InpMaMethod = MODE_EMA; -input ENUM_HA_APPLIED_PRICE InpAppliedPrice = HA_PRICE_CLOSE; // HA price for the middle line -input int InpAtrPeriod = 10; -input double InpMultiplier = 2.0; - -//--- Indicator Buffers --- -double BufferUpper[]; -double BufferLower[]; -double BufferMiddle[]; -double BufferHA_ATR[]; // Buffer for Heikin Ashi ATR - -//--- Intermediate Heikin Ashi Buffers --- -double ExtHaOpenBuffer[]; -double ExtHaHighBuffer[]; -double ExtHaLowBuffer[]; -double ExtHaCloseBuffer[]; - -//--- Global Objects and Variables --- -int g_ExtMaPeriod, g_ExtAtrPeriod; -double g_ExtMultiplier; -CHeikinAshi_Calculator *g_ha_calculator; // Pointer to our Heikin Ashi calculator - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - g_ExtMaPeriod = (InpMaPeriod < 1) ? 1 : InpMaPeriod; - g_ExtAtrPeriod = (InpAtrPeriod < 1) ? 1 : InpAtrPeriod; - g_ExtMultiplier = (InpMultiplier <= 0) ? 2.0 : InpMultiplier; - - SetIndexBuffer(0, BufferUpper, INDICATOR_DATA); - SetIndexBuffer(1, BufferLower, INDICATOR_DATA); - SetIndexBuffer(2, BufferMiddle, INDICATOR_DATA); - SetIndexBuffer(3, BufferHA_ATR, INDICATOR_CALCULATIONS); - - ArraySetAsSeries(BufferUpper, false); - ArraySetAsSeries(BufferLower, false); - ArraySetAsSeries(BufferMiddle, false); - ArraySetAsSeries(BufferHA_ATR, false); - - IndicatorSetInteger(INDICATOR_DIGITS, _Digits); - int draw_begin = MathMax(g_ExtMaPeriod, g_ExtAtrPeriod); - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, draw_begin); - PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, draw_begin); - PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, g_ExtMaPeriod - 1); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA_KC_Pure(%d,%d,%.1f)", g_ExtMaPeriod, g_ExtAtrPeriod, g_ExtMultiplier)); - -//--- Create the calculator instance - g_ha_calculator = new CHeikinAshi_Calculator(); - if(CheckPointer(g_ha_calculator) == POINTER_INVALID) - { - Print("Error creating CHeikinAshi_Calculator object"); - return(INIT_FAILED); - } - - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { -//--- Free the calculator object - if(CheckPointer(g_ha_calculator) != POINTER_INVALID) - { - delete g_ha_calculator; - g_ha_calculator = NULL; - } - } - -//+------------------------------------------------------------------+ -//| Keltner Channel on Heikin 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[]) - { - int start_pos = MathMax(g_ExtMaPeriod, g_ExtAtrPeriod); - if(rates_total <= start_pos) - return(0); - -//--- Resize intermediate buffers - ArrayResize(ExtHaOpenBuffer, rates_total); - ArrayResize(ExtHaHighBuffer, rates_total); - ArrayResize(ExtHaLowBuffer, rates_total); - ArrayResize(ExtHaCloseBuffer, rates_total); - -//--- STEP 1: Calculate Heikin Ashi bars - g_ha_calculator.Calculate(rates_total, open, high, low, close, - ExtHaOpenBuffer, ExtHaHighBuffer, ExtHaLowBuffer, ExtHaCloseBuffer); - -//--- STEP 2: Calculate Heikin Ashi True Range - double ha_tr[]; - ArrayResize(ha_tr, rates_total); - for(int i = 1; i < rates_total; i++) - { - ha_tr[i] = MathMax(ExtHaHighBuffer[i], ExtHaCloseBuffer[i-1]) - MathMin(ExtHaLowBuffer[i], ExtHaCloseBuffer[i-1]); - } - -//--- STEP 3: Select the source Heikin Ashi price array for the middle line - double ha_price_source[]; - switch(InpAppliedPrice) - { - case HA_PRICE_OPEN: - ArrayCopy(ha_price_source, ExtHaOpenBuffer); - break; - case HA_PRICE_HIGH: - ArrayCopy(ha_price_source, ExtHaHighBuffer); - break; - case HA_PRICE_LOW: - ArrayCopy(ha_price_source, ExtHaLowBuffer); - break; - default: - ArrayCopy(ha_price_source, ExtHaCloseBuffer); - break; - } - -//--- STEP 4: Calculate HA_ATR, Middle, Upper, and Lower bands in a single loop - for(int i = 1; i < rates_total; i++) - { - // --- Calculate Heikin Ashi ATR (using Wilder's smoothing) --- - if(i == g_ExtAtrPeriod) // Initialization with SMA - { - BufferHA_ATR[i] = SimpleMA(i, g_ExtAtrPeriod, ha_tr); - } - else - if(i > g_ExtAtrPeriod) // Recursive calculation - { - BufferHA_ATR[i] = (BufferHA_ATR[i-1] * (g_ExtAtrPeriod - 1) + ha_tr[i]) / g_ExtAtrPeriod; - } - - // --- Calculate the middle line (MA on HA price) --- - if(i >= g_ExtMaPeriod - 1) - { - switch(InpMaMethod) - { - case MODE_EMA: - if(i == g_ExtMaPeriod - 1) - BufferMiddle[i] = SimpleMA(i, g_ExtMaPeriod, ha_price_source); - else - { - double pr = 2.0 / (g_ExtMaPeriod + 1.0); - BufferMiddle[i] = ha_price_source[i] * pr + BufferMiddle[i-1] * (1.0 - pr); - } - break; - // --- FIX: Added missing cases --- - case MODE_SMMA: - if(i == g_ExtMaPeriod - 1) - BufferMiddle[i] = SimpleMA(i, g_ExtMaPeriod, ha_price_source); - else - BufferMiddle[i] = (BufferMiddle[i-1] * (g_ExtMaPeriod - 1) + ha_price_source[i]) / g_ExtMaPeriod; - break; - case MODE_LWMA: - BufferMiddle[i] = LinearWeightedMA(i, g_ExtMaPeriod, ha_price_source); - break; - default: // MODE_SMA - BufferMiddle[i] = SimpleMA(i, g_ExtMaPeriod, ha_price_source); - break; - } - } - - // --- Calculate Upper and Lower bands --- - if(i >= start_pos) - { - BufferUpper[i] = BufferMiddle[i] + (BufferHA_ATR[i] * g_ExtMultiplier); - BufferLower[i] = BufferMiddle[i] - (BufferHA_ATR[i] * g_ExtMultiplier); - } - } - - return(rates_total); - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/LinearRegressionChannel.md b/Indicators/MyIndicators/LinearRegressionChannel.md deleted file mode 100644 index 717c2cb..0000000 --- a/Indicators/MyIndicators/LinearRegressionChannel.md +++ /dev/null @@ -1,47 +0,0 @@ -# Linear Regression Channel - -## 1. Summary (Introduction) - -The Linear Regression Channel is a technical analysis tool that consists of three parallel lines plotted on a price chart. It is a statistically-based indicator that uses the **linear regression** (or "least squares fit") method to determine the primary trend direction. - -- The **Middle Line** is the actual linear regression trendline. -- The **Upper and Lower Channel Lines** are plotted based on the **maximum price deviation** from the middle line over the calculation period. - -The indicator provides an objective, mathematical measure of a trend and its trading channel. - -## 2. Mathematical Foundations and Calculation Logic - -The indicator's core is the linear regression trendline, which is the straight line that best fits a series of `Close` prices over a specified period. - -### Calculation Steps (Algorithm) - -For the last `N` bars at any given point in time: - -1. **Calculate the Linear Regression Line:** Using the method of least squares, find the straight line that best fits the `N` closing prices. -2. **Calculate Maximum Deviation:** Find the largest vertical distance between any of the `N` closing prices and the calculated regression line. -3. **Calculate the Upper and Lower Channel Lines:** Shift the regression line up and down by the maximum deviation found in the previous step. - -**Important Note on "Repainting":** The Linear Regression Channel is a "repainting" indicator by nature. Because the entire line is recalculated for the most recent `N` bars every time a new bar forms, its position in the recent past can change. - -## 3. MQL5 Implementation Details - -Our MQL5 implementation is designed to be highly efficient and visually clean by leveraging MetaTrader 5's built-in **`OBJ_REGRESSION`** graphical object. - -- **Object-Based Plotting:** The indicator uses a single, built-in `OBJ_REGRESSION` object. This object is managed by the MetaTrader terminal, which handles the complex regression and maximum deviation calculations internally using highly optimized code. -- **Clean, Non-Continuous Display:** By default, the indicator only displays the single, most current regression channel calculated on the last `N` bars. -- **Efficient "On New Bar" Updates:** The indicator is extremely light on terminal resources. The channel object is only updated **once per bar** when a new candle forms, preventing unnecessary recalculations on every tick. -- **Automatic Cleanup (RAII):** The graphical object is given a unique name and is always deleted from the chart when the indicator is removed. - -## 4. Parameters - -- **Regression Period (`InpRegressionPeriod`):** The number of bars to include in the regression calculation. Default is `100`. -- **Channel Color (`InpChannelColor`):** Allows the user to customize the color of the channel lines. Default is `clrRed`. -- **Channel Extensions:** - - **`InpRayRight`**: If `true`, the channel is extended indefinitely into the future. Default is `false`. - - **`InpRayLeft`**: If `true`, the channel is extended indefinitely into the past. Default is `false`. - -## 5. Usage and Interpretation - -- **Trend Identification:** The slope of the middle line indicates the direction of the trend. -- **Dynamic Support and Resistance:** The channel lines act as dynamic support and resistance levels. -- **Caution:** Due to its repainting nature, the indicator is best used for confirming the current market structure rather than for generating precise entry signals from past data. diff --git a/Indicators/MyIndicators/LinearRegressionChannel.mq5 b/Indicators/MyIndicators/LinearRegressionChannel.mq5 deleted file mode 100644 index 34b9b20..0000000 --- a/Indicators/MyIndicators/LinearRegressionChannel.mq5 +++ /dev/null @@ -1,124 +0,0 @@ -//+------------------------------------------------------------------+ -//| LinearRegressionChannel.mq5 | -//| Copyright 2025, xxxxxxxx | -//| | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property link "" -#property version "1.01" // Added color selection -#property description "Draws a Linear Regression Channel where width is based on max deviation." -#property indicator_chart_window -#property indicator_buffers 0 -#property indicator_plots 0 - -//--- Input Parameters --- -input int InpRegressionPeriod = 100; // Period for the regression calculation -input color InpChannelColor = clrRed; // Channel color -input group "Channel Extensions" -input bool InpRayRight = false; // Extend channel to the right -input bool InpRayLeft = false; // Extend channel to the left - -//--- Global Variables --- -int g_ExtPeriod; -string g_channel_name; -datetime g_last_update_time; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - g_ExtPeriod = (InpRegressionPeriod < 2) ? 2 : InpRegressionPeriod; - - g_channel_name = "LinRegChannel_" + IntegerToString(ChartID()) + "_" + IntegerToString(GetTickCount()); - g_last_update_time = 0; - - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("LinReg(%d)", g_ExtPeriod)); - - EventSetTimer(1); - - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { - EventKillTimer(); - ObjectDelete(0, g_channel_name); - ChartRedraw(); - } - -//+------------------------------------------------------------------+ -//| Timer event handler. | -//+------------------------------------------------------------------+ -void OnTimer() - { - UpdateChannel(); - } - -//+------------------------------------------------------------------+ -//| Main 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_ExtPeriod) - return(0); - - datetime last_bar_time = time[rates_total - 1]; - if(last_bar_time > g_last_update_time) - { - UpdateChannel(); - g_last_update_time = last_bar_time; - } - - return(rates_total); - } - -//+------------------------------------------------------------------+ -//| Updates the position and properties of the regression channel. | -//+------------------------------------------------------------------+ -void UpdateChannel() - { - if(Bars(_Symbol, _Period) < g_ExtPeriod) - return; - - datetime time1 = iTime(_Symbol, _Period, g_ExtPeriod - 1); - datetime time2 = iTime(_Symbol, _Period, 0); - - if(ObjectFind(0, g_channel_name) < 0) - { - if(!ObjectCreate(0, g_channel_name, OBJ_REGRESSION, 0, time1, 0, time2, 0)) - { - Print("Error creating regression channel object: ", GetLastError()); - return; - } - - // Set visual properties only once on creation - ObjectSetInteger(0, g_channel_name, OBJPROP_STYLE, STYLE_SOLID); - ObjectSetInteger(0, g_channel_name, OBJPROP_FILL, false); - ObjectSetInteger(0, g_channel_name, OBJPROP_SELECTABLE, false); - } - -// Update properties on every call to allow for dynamic changes - ObjectSetInteger(0, g_channel_name, OBJPROP_TIME, 0, time1); - ObjectSetInteger(0, g_channel_name, OBJPROP_TIME, 1, time2); - ObjectSetInteger(0, g_channel_name, OBJPROP_RAY_RIGHT, InpRayRight); - ObjectSetInteger(0, g_channel_name, OBJPROP_RAY_LEFT, InpRayLeft); -// --- FIX: Set color based on input --- - ObjectSetInteger(0, g_channel_name, OBJPROP_COLOR, InpChannelColor); - - ChartRedraw(); - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/LinearRegression_Pro_HeikinAshi.mq5 b/Indicators/MyIndicators/LinearRegression_Pro_HeikinAshi.mq5 deleted file mode 100644 index 77bc95c..0000000 --- a/Indicators/MyIndicators/LinearRegression_Pro_HeikinAshi.mq5 +++ /dev/null @@ -1,246 +0,0 @@ -//+------------------------------------------------------------------+ -//| LinearRegression_Pro_HeikinAshi.mq5| -//| Copyright 2025, xxxxxxxx | -//| | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property link "" -#property version "1.00" -#property description "A flexible, manually calculated Linear Regression Channel on Heikin Ashi data." -#property description "Updates only on new bars for efficiency." - -#include - -//--- Indicator Window and Plot Properties --- -#property indicator_chart_window -#property indicator_buffers 3 // Upper, Lower, Middle -#property indicator_plots 3 - -//--- Plot 1: Upper Channel -#property indicator_label1 "HA_Upper" -#property indicator_type1 DRAW_LINE -#property indicator_color1 clrDodgerBlue -#property indicator_style1 STYLE_DOT - -//--- Plot 2: Lower Channel -#property indicator_label2 "HA_Lower" -#property indicator_type2 DRAW_LINE -#property indicator_color2 clrDodgerBlue -#property indicator_style2 STYLE_DOT - -//--- Plot 3: Regression Line (Middle) -#property indicator_label3 "HA_Regression" -#property indicator_type3 DRAW_LINE -#property indicator_color3 clrRed -#property indicator_style3 STYLE_SOLID - -//--- Enum for Channel Calculation Mode --- -enum ENUM_CHANNEL_MODE - { - DEVIATION_STANDARD, // Channel width based on Standard Deviation - DEVIATION_MAXIMUM // Channel width based on Maximum Deviation - }; - -//--- Enum for selecting Heikin Ashi price source --- -enum ENUM_HA_APPLIED_PRICE - { - HA_PRICE_CLOSE, HA_PRICE_OPEN, HA_PRICE_HIGH, HA_PRICE_LOW, HA_PRICE_TYPICAL, HA_PRICE_MEDIAN - }; - -//--- Input Parameters --- -input int InpRegressionPeriod = 100; -input ENUM_HA_APPLIED_PRICE InpAppliedPrice = HA_PRICE_CLOSE; -input ENUM_CHANNEL_MODE InpChannelMode = DEVIATION_STANDARD; -input double InpDeviations = 2.0; - -//--- Indicator Buffers --- -double BufferUpper[]; -double BufferLower[]; -double BufferMiddle[]; - -//--- Global Objects and Variables --- -int g_ExtPeriod; -double g_ExtDeviations; -datetime g_last_update_time; -CHeikinAshi_Calculator *g_ha_calculator; - -//--- Forward declarations --- -void CalculateChannel(int rates_total, const double &ha_open[], const double &ha_high[], const double &ha_low[], const double &ha_close[]); -double GetHAPrice(int index, ENUM_HA_APPLIED_PRICE type, const double &ha_open[], const double &ha_high[], const double &ha_low[], const double &ha_close[]); - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - g_ExtPeriod = (InpRegressionPeriod < 2) ? 2 : InpRegressionPeriod; - g_ExtDeviations = (InpDeviations <= 0) ? 2.0 : InpDeviations; - g_last_update_time = 0; - - SetIndexBuffer(0, BufferUpper, INDICATOR_DATA); - SetIndexBuffer(1, BufferLower, INDICATOR_DATA); - SetIndexBuffer(2, BufferMiddle, INDICATOR_DATA); - - ArraySetAsSeries(BufferUpper, false); - ArraySetAsSeries(BufferLower, false); - ArraySetAsSeries(BufferMiddle, false); - - IndicatorSetInteger(INDICATOR_DIGITS, _Digits); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA LinReg Pro(%d)", g_ExtPeriod)); - - g_ha_calculator = new CHeikinAshi_Calculator(); - if(CheckPointer(g_ha_calculator) == POINTER_INVALID) - { - Print("Error creating CHeikinAshi_Calculator object"); - return(INIT_FAILED); - } - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { - if(CheckPointer(g_ha_calculator) != POINTER_INVALID) - { - delete g_ha_calculator; - g_ha_calculator = NULL; - } - } - -//+------------------------------------------------------------------+ -//| Linear Regression Channel on Heikin 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 < g_ExtPeriod) - return(0); - - if(time[rates_total - 1] > g_last_update_time) - { - ArrayInitialize(BufferUpper, EMPTY_VALUE); - ArrayInitialize(BufferLower, EMPTY_VALUE); - ArrayInitialize(BufferMiddle, EMPTY_VALUE); - - //--- Intermediate Heikin Ashi Buffers - double ha_open[], ha_high[], ha_low[], ha_close[]; - ArrayResize(ha_open, rates_total); - ArrayResize(ha_high, rates_total); - ArrayResize(ha_low, rates_total); - ArrayResize(ha_close, rates_total); - - //--- Calculate Heikin Ashi bars - g_ha_calculator.Calculate(rates_total, open, high, low, close, ha_open, ha_high, ha_low, ha_close); - - //--- Calculate the channel using HA data - CalculateChannel(rates_total, ha_open, ha_high, ha_low, ha_close); - - g_last_update_time = time[rates_total - 1]; - } - - return(rates_total); - } - -//+------------------------------------------------------------------+ -//| Main calculation logic moved to a helper function | -//+------------------------------------------------------------------+ -void CalculateChannel(int rates_total, const double &ha_open[], const double &ha_high[], const double &ha_low[], const double &ha_close[]) - { - int start_index = rates_total - g_ExtPeriod; - -//--- STEP 1: Calculate sums for the regression formula - double sum_x = 0, sum_y = 0, sum_xy = 0, sum_x2 = 0; - for(int i = 0; i < g_ExtPeriod; i++) - { - double y = GetHAPrice(start_index + i, InpAppliedPrice, ha_open, ha_high, ha_low, ha_close); - double x = i; - sum_x += x; - sum_y += y; - sum_xy += x * y; - sum_x2 += x * x; - } - -//--- STEP 2: Calculate slope (b) and intercept (a) - double b = (g_ExtPeriod * sum_xy - sum_x * sum_y) / (g_ExtPeriod * sum_x2 - sum_x * sum_x); - double a = (sum_y - b * sum_x) / g_ExtPeriod; - -//--- STEP 3: Calculate regression values and deviation - double deviation_offset = 0; - double regression_values[]; - ArrayResize(regression_values, g_ExtPeriod); - - if(InpChannelMode == DEVIATION_STANDARD) - { - double deviation_sum_sq = 0; - for(int i = 0; i < g_ExtPeriod; i++) - { - regression_values[i] = a + b * i; - double price = GetHAPrice(start_index + i, InpAppliedPrice, ha_open, ha_high, ha_low, ha_close); - double diff = price - regression_values[i]; - deviation_sum_sq += diff * diff; - } - double std_dev = MathSqrt(deviation_sum_sq / g_ExtPeriod); - deviation_offset = g_ExtDeviations * std_dev; - } - else // DEVIATION_MAXIMUM - { - double max_dev = 0; - for(int i = 0; i < g_ExtPeriod; i++) - { - regression_values[i] = a + b * i; - double price = GetHAPrice(start_index + i, InpAppliedPrice, ha_open, ha_high, ha_low, ha_close); - double dev = MathAbs(price - regression_values[i]); - if(dev > max_dev) - max_dev = dev; - } - deviation_offset = max_dev; - } - -//--- STEP 4: Fill the indicator buffers for the last N bars - for(int i = 0; i < g_ExtPeriod; i++) - { - int buffer_index = start_index + i; - BufferMiddle[buffer_index] = regression_values[i]; - BufferUpper[buffer_index] = regression_values[i] + deviation_offset; - BufferLower[buffer_index] = regression_values[i] - deviation_offset; - } - -//--- Dynamically set the draw begin to only show the last channel - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, start_index); - PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, start_index); - PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, start_index); - } - -//+------------------------------------------------------------------+ -//| Helper function to get the correct Heikin Ashi price type | -//+------------------------------------------------------------------+ -double GetHAPrice(int index, ENUM_HA_APPLIED_PRICE type, const double &ha_open[], const double &ha_high[], const double &ha_low[], const double &ha_close[]) - { - switch(type) - { - case HA_PRICE_OPEN: - return ha_open[index]; - case HA_PRICE_HIGH: - return ha_high[index]; - case HA_PRICE_LOW: - return ha_low[index]; - case HA_PRICE_MEDIAN: - return (ha_high[index] + ha_low[index]) / 2.0; - case HA_PRICE_TYPICAL: - return (ha_high[index] + ha_low[index] + ha_close[index]) / 3.0; - default: - return ha_close[index]; - } - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/LinearRegression_Pro_Sample.mq5 b/Indicators/MyIndicators/LinearRegression_Pro_Sample.mq5 deleted file mode 100644 index f876955..0000000 --- a/Indicators/MyIndicators/LinearRegression_Pro_Sample.mq5 +++ /dev/null @@ -1,215 +0,0 @@ -//+------------------------------------------------------------------+ -//| LinearRegression_Pro_Sample.mq5| -//| Copyright 2025, xxxxxxxx | -//| | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property link "" -#property version "1.00" -#property description "Linear Regression Channel using SAMPLE standard deviation (n-1)." -#property description "Updates only on new bars for efficiency." - -//--- Indicator Window and Plot Properties --- -#property indicator_chart_window -#property indicator_buffers 3 // Upper, Lower, Middle -#property indicator_plots 3 - -//--- Plot 1: Upper Channel -#property indicator_label1 "Upper" -#property indicator_type1 DRAW_LINE -#property indicator_color1 clrDodgerBlue -#property indicator_style1 STYLE_DOT - -//--- Plot 2: Lower Channel -#property indicator_label2 "Lower" -#property indicator_type2 DRAW_LINE -#property indicator_color2 clrDodgerBlue -#property indicator_style2 STYLE_DOT - -//--- Plot 3: Regression Line (Middle) -#property indicator_label3 "Regression" -#property indicator_type3 DRAW_LINE -#property indicator_color3 clrRed -#property indicator_style3 STYLE_SOLID - -//--- Enum for Channel Calculation Mode --- -enum ENUM_CHANNEL_MODE - { - DEVIATION_STANDARD, // Channel width based on Standard Deviation - DEVIATION_MAXIMUM // Channel width based on Maximum Deviation - }; - -//--- Input Parameters --- -input int InpRegressionPeriod = 100; -input ENUM_APPLIED_PRICE InpAppliedPrice = PRICE_CLOSE; -input ENUM_CHANNEL_MODE InpChannelMode = DEVIATION_STANDARD; -input double InpDeviations = 2.0; - -//--- Indicator Buffers --- -double BufferUpper[]; -double BufferLower[]; -double BufferMiddle[]; - -//--- Global Variables --- -int g_ExtPeriod; -double g_ExtDeviations; -datetime g_last_update_time; - -//--- Forward declarations --- -double GetPrice(int index, ENUM_APPLIED_PRICE type, const double &open[], const double &high[], const double &low[], const double &close[]); -void CalculateChannel(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[]); - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - g_ExtPeriod = (InpRegressionPeriod < 2) ? 2 : InpRegressionPeriod; - g_ExtDeviations = (InpDeviations <= 0) ? 2.0 : InpDeviations; - g_last_update_time = 0; - - SetIndexBuffer(0, BufferUpper, INDICATOR_DATA); - SetIndexBuffer(1, BufferLower, INDICATOR_DATA); - SetIndexBuffer(2, BufferMiddle, INDICATOR_DATA); - - ArraySetAsSeries(BufferUpper, false); - ArraySetAsSeries(BufferLower, false); - ArraySetAsSeries(BufferMiddle, false); - - IndicatorSetInteger(INDICATOR_DIGITS, _Digits); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("LinReg Pro Sample(%d)", g_ExtPeriod)); - - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Linear Regression Channel 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_ExtPeriod) - return(0); - - if(time[rates_total - 1] > g_last_update_time) - { - ArrayInitialize(BufferUpper, EMPTY_VALUE); - ArrayInitialize(BufferLower, EMPTY_VALUE); - ArrayInitialize(BufferMiddle, EMPTY_VALUE); - - CalculateChannel(rates_total, open, high, low, close); - - g_last_update_time = time[rates_total - 1]; - } - - return(rates_total); - } - -//+------------------------------------------------------------------+ -//| Main calculation logic moved to a helper function | -//+------------------------------------------------------------------+ -void CalculateChannel(int rates_total, const double &open[], const double &high[], const double &low[], const double &close[]) - { - int start_index = rates_total - g_ExtPeriod; - -//--- STEP 1: Calculate sums for the regression formula - double sum_x = 0, sum_y = 0, sum_xy = 0, sum_x2 = 0; - for(int i = 0; i < g_ExtPeriod; i++) - { - double y = GetPrice(start_index + i, InpAppliedPrice, open, high, low, close); - double x = i; - sum_x += x; - sum_y += y; - sum_xy += x * y; - sum_x2 += x * x; - } - -//--- STEP 2: Calculate slope (b) and intercept (a) - double b = (g_ExtPeriod * sum_xy - sum_x * sum_y) / (g_ExtPeriod * sum_x2 - sum_x * sum_x); - double a = (sum_y - b * sum_x) / g_ExtPeriod; - -//--- STEP 3: Calculate regression values and deviation - double deviation_offset = 0; - double regression_values[]; - ArrayResize(regression_values, g_ExtPeriod); - - if(InpChannelMode == DEVIATION_STANDARD) - { - double deviation_sum_sq = 0; - for(int i = 0; i < g_ExtPeriod; i++) - { - regression_values[i] = a + b * i; - double price = GetPrice(start_index + i, InpAppliedPrice, open, high, low, close); - double diff = price - regression_values[i]; - deviation_sum_sq += diff * diff; - } - - // Use Sample Standard Deviation (n-1) - if(g_ExtPeriod > 1) - { - double std_dev = MathSqrt(deviation_sum_sq / (g_ExtPeriod - 1)); - deviation_offset = g_ExtDeviations * std_dev; - } - } - else // DEVIATION_MAXIMUM - { - double max_dev = 0; - for(int i = 0; i < g_ExtPeriod; i++) - { - regression_values[i] = a + b * i; - double price = GetPrice(start_index + i, InpAppliedPrice, open, high, low, close); - double dev = MathAbs(price - regression_values[i]); - if(dev > max_dev) - max_dev = dev; - } - deviation_offset = max_dev; - } - -//--- STEP 4: Fill the indicator buffers for the last N bars - for(int i = 0; i < g_ExtPeriod; i++) - { - int buffer_index = start_index + i; - BufferMiddle[buffer_index] = regression_values[i]; - BufferUpper[buffer_index] = regression_values[i] + deviation_offset; - BufferLower[buffer_index] = regression_values[i] - deviation_offset; - } - -//--- Dynamically set the draw begin to only show the last channel - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, start_index); - PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, start_index); - PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, start_index); - } - -//+------------------------------------------------------------------+ -//| Helper function to get the correct price type | -//+------------------------------------------------------------------+ -double GetPrice(int index, ENUM_APPLIED_PRICE type, const double &open[], const double &high[], const double &low[], const double &close[]) - { - switch(type) - { - case PRICE_OPEN: - return open[index]; - case PRICE_HIGH: - return high[index]; - case PRICE_LOW: - return low[index]; - case PRICE_MEDIAN: - return (high[index] + low[index]) / 2.0; - case PRICE_TYPICAL: - return (high[index] + low[index] + close[index]) / 3.0; - case PRICE_WEIGHTED: - return (high[index] + low[index] + 2*close[index]) / 4.0; - default: - return close[index]; - } - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/MACD.md b/Indicators/MyIndicators/MACD.md deleted file mode 100644 index fa93fb6..0000000 --- a/Indicators/MyIndicators/MACD.md +++ /dev/null @@ -1,82 +0,0 @@ -# Moving Average Convergence/Divergence (MACD) - -## 1. Summary (Introduction) - -The Moving Average Convergence/Divergence (MACD), developed by Gerald Appel in the late 1970s, is one of the most popular and versatile technical indicators. It is a trend-following momentum indicator that shows the relationship between two exponential moving averages (EMAs) of a security’s price. - -The MACD is composed of three main components, which together provide a comprehensive view of trend direction, momentum, and potential reversal points: - -- **The MACD Line:** The core of the indicator. -- **The Signal Line:** A moving average of the MACD Line, used to generate trade signals. -- **The Histogram:** Represents the difference between the MACD Line and the Signal Line. - -## 2. Mathematical Foundations and Calculation Logic - -The MACD is calculated through a series of subtractions and exponential smoothing steps. - -### Required Components - -- **Fast EMA Period:** The period for the shorter-term EMA (standard is 12). -- **Slow EMA Period:** The period for the longer-term EMA (standard is 26). -- **Signal EMA Period:** The period for the EMA that smooths the MACD Line (standard is 9). -- **Source Price (P):** The price series used for the calculation (e.g., Close). - -### Calculation Steps (Algorithm) - -1. **Calculate the Fast EMA:** Compute an EMA of the source price using the fast period. - $\text{FastEMA} = \text{EMA}(P, \text{FastPeriod})$ - -2. **Calculate the Slow EMA:** Compute an EMA of the source price using the slow period. - $\text{SlowEMA} = \text{EMA}(P, \text{SlowPeriod})$ - -3. **Calculate the MACD Line:** Subtract the Slow EMA from the Fast EMA. This is the main momentum line. - $\text{MACD Line} = \text{FastEMA} - \text{SlowEMA}$ - -4. **Calculate the Signal Line:** Compute an EMA of the MACD Line using the signal period. - $\text{Signal Line} = \text{EMA}(\text{MACD Line}, \text{SignalPeriod})$ - -5. **Calculate the Histogram:** Subtract the Signal Line from the MACD Line. - $\text{Histogram} = \text{MACD Line} - \text{Signal Line}$ - -## 3. MQL5 Implementation Details - -Our MQL5 implementation was refactored to be a completely self-contained, robust, and accurate representation of the classic, TradingView-style MACD. - -- **Stability via Full Recalculation:** We employ a "brute-force" full recalculation within the `OnCalculate` function. This is our standard practice for indicators with multiple recursive calculations to ensure maximum stability. - -- **Fully Manual EMA Calculations:** To guarantee 100% accuracy and consistency, all three Exponential Moving Averages (Fast, Slow, and Signal) are calculated **manually**. The indicator is completely independent of external handles or libraries. - - - **Robust Initialization:** Each recursive EMA calculation is carefully initialized with a **manual Simple Moving Average (SMA)**. This provides a stable starting point for the recursive calculations and completely eliminates the risk of floating-point overflows. - -- **Clear, Staged Calculation:** The `OnCalculate` function is structured into clear, sequential steps, each handled by a dedicated `for` loop. This improves code readability and makes the complex logic easy to follow: - - 1. **Step 1:** The source price array is prepared. - 2. **Step 2 & 3:** The Fast and Slow EMAs are calculated and stored in calculation buffers. - 3. **Step 4:** The MACD Line is calculated from the two EMAs. - 4. **Step 5:** The Signal Line (EMA of the MACD Line) and the final Histogram value are calculated. - -- **TradingView-Style Visualization:** Our implementation plots all three standard components: the MACD Line (blue), the Signal Line (orange/red), and the true Histogram (the difference between the two lines), providing a more informative visual than the default MetaTrader MACD. - -- **Heikin Ashi Variant (`MACD_HeikinAshi.mq5`):** - - Our toolkit also includes a "pure" Heikin Ashi version. The calculation logic is identical, but it uses the smoothed Heikin Ashi price data as its input for the initial Fast and Slow EMAs. - - This results in a "doubly smoothed" MACD, which is excellent for filtering out market noise and identifying the most significant, underlying momentum shifts. - -## 4. Parameters - -- **Fast EMA Period (`InpFastEMA`):** The period for the shorter-term EMA. Default is `12`. -- **Slow EMA Period (`InpSlowEMA`):** The period for the longer-term EMA. Default is `26`. -- **Signal EMA Period (`InpSignalEMA`):** The period for the signal line's EMA. Default is `9`. -- **Applied Price (`InpAppliedPrice`):** The source price used for the calculation. Default is `PRICE_CLOSE`. - -## 5. Usage and Interpretation - -- **Signal Line Crossovers:** This is the most common MACD signal. - - **Bullish Crossover:** When the MACD Line (blue) crosses above the Signal Line (red). - - **Bearish Crossover:** When the MACD Line crosses below the Signal Line. -- **Zero Line Crossovers:** These indicate a potential change in the overall trend direction. - - **Bullish Crossover:** When the MACD Line crosses above the zero line. - - **Bearish Crossover:** When the MACD Line crosses below the zero line. -- **Divergence:** This is one of the most powerful MACD signals. - - **Bullish Divergence:** Price makes a lower low, but the MACD makes a higher low, suggesting weakening bearish momentum. - - **Bearish Divergence:** Price makes a higher high, but the MACD makes a lower high, suggesting weakening bullish momentum. -- **Histogram:** The histogram visually represents the distance between the MACD and Signal lines. When the bars grow taller, momentum is increasing. When they shrink, momentum is decreasing, which can be an early warning of a potential crossover. diff --git a/Indicators/MyIndicators/MACD.mq5 b/Indicators/MyIndicators/MACD.mq5 deleted file mode 100644 index f4cd01b..0000000 --- a/Indicators/MyIndicators/MACD.mq5 +++ /dev/null @@ -1,197 +0,0 @@ -//+------------------------------------------------------------------+ -//| MACD.mq5 | -//| Copyright 2025, xxxxxxxx | -//| | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property link "" -#property version "6.00" // TradingView style: MACD Line, Signal Line, and Histogram -#property description "Moving Average Convergence/Divergence (TradingView Style)" - -//--- Indicator Window and Plot Properties --- -#property indicator_separate_window -#property indicator_buffers 5 // Histogram, Signal, MACD Line, FastEMA, SlowEMA -#property indicator_plots 3 // Histogram, MACD Line, Signal Line - -//--- Plot 1: MACD Histogram -#property indicator_label1 "Histogram" -#property indicator_type1 DRAW_HISTOGRAM -#property indicator_color1 clrSilver -#property indicator_width1 1 - -//--- Plot 2: MACD Line -#property indicator_label2 "MACD" -#property indicator_type2 DRAW_LINE -// --- FIX: Replaced hex code with a standard MQL5 color constant --- -#property indicator_color2 clrDodgerBlue -#property indicator_style2 STYLE_SOLID -#property indicator_width2 1 - -//--- Plot 3: Signal Line -#property indicator_label3 "Signal" -#property indicator_type3 DRAW_LINE -// --- FIX: Replaced hex code with a standard MQL5 color constant --- -#property indicator_color3 clrOrangeRed -#property indicator_style3 STYLE_SOLID -#property indicator_width3 1 - -//--- Input Parameters --- -input int InpFastEMA = 12; -input int InpSlowEMA = 26; -input int InpSignalEMA = 9; -input ENUM_APPLIED_PRICE InpAppliedPrice = PRICE_CLOSE; - -//--- Indicator Buffers --- -double BufferMACD_Histogram[]; // Plot 1 -double BufferMACDLine[]; // Plot 2 -double BufferSignalLine[]; // Plot 3 -double BufferFastEMA[]; // Calculation -double BufferSlowEMA[]; // Calculation - -//--- Global Variables --- -int g_ExtFastEMA, g_ExtSlowEMA, g_ExtSignalEMA; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - g_ExtFastEMA = (InpFastEMA < 1) ? 1 : InpFastEMA; - g_ExtSlowEMA = (InpSlowEMA < 1) ? 1 : InpSlowEMA; - g_ExtSignalEMA = (InpSignalEMA < 1) ? 1 : InpSignalEMA; - - if(g_ExtFastEMA > g_ExtSlowEMA) - { - int temp = g_ExtFastEMA; - g_ExtFastEMA = g_ExtSlowEMA; - g_ExtSlowEMA = temp; - } - - SetIndexBuffer(0, BufferMACD_Histogram, INDICATOR_DATA); - SetIndexBuffer(1, BufferMACDLine, INDICATOR_DATA); - SetIndexBuffer(2, BufferSignalLine, INDICATOR_DATA); - SetIndexBuffer(3, BufferFastEMA, INDICATOR_CALCULATIONS); - SetIndexBuffer(4, BufferSlowEMA, INDICATOR_CALCULATIONS); - - ArraySetAsSeries(BufferMACD_Histogram, false); - ArraySetAsSeries(BufferMACDLine, false); - ArraySetAsSeries(BufferSignalLine, false); - ArraySetAsSeries(BufferFastEMA, false); - ArraySetAsSeries(BufferSlowEMA, false); - - int macd_line_draw_begin = g_ExtSlowEMA - 1; - int signal_draw_begin = g_ExtSlowEMA + g_ExtSignalEMA - 2; - - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, signal_draw_begin); // Histogram - PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, macd_line_draw_begin); // MACD Line - PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, signal_draw_begin); // Signal Line - - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("MACD(%d,%d,%d)", g_ExtFastEMA, g_ExtSlowEMA, g_ExtSignalEMA)); - IndicatorSetInteger(INDICATOR_DIGITS, _Digits); - - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Moving Average Convergence/Divergence 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[]) - { - int start_pos = g_ExtSlowEMA + g_ExtSignalEMA - 2; - if(rates_total <= start_pos) - return(0); - -//--- STEP 1: Prepare the source price array - double price_source[]; - ArrayResize(price_source, rates_total); - for(int i=0; i - -//--- Indicator Window and Plot Properties --- -#property indicator_separate_window -#property indicator_buffers 5 // Histogram, MACD Line, Signal Line, FastEMA, SlowEMA -#property indicator_plots 3 // Histogram, MACD Line, Signal Line - -//--- Plot 1: MACD Histogram -#property indicator_label1 "HA_Hist" -#property indicator_type1 DRAW_HISTOGRAM -#property indicator_color1 clrSilver -#property indicator_width1 1 - -//--- Plot 2: MACD Line -#property indicator_label2 "HA_MACD" -#property indicator_type2 DRAW_LINE -#property indicator_color2 clrDodgerBlue -#property indicator_style2 STYLE_SOLID -#property indicator_width2 1 - -//--- Plot 3: Signal Line -#property indicator_label3 "HA_Signal" -#property indicator_type3 DRAW_LINE -#property indicator_color3 clrOrangeRed -#property indicator_style3 STYLE_SOLID -#property indicator_width3 1 - -//--- Enum for selecting Heikin Ashi price source --- -enum ENUM_HA_APPLIED_PRICE - { - HA_PRICE_CLOSE, HA_PRICE_OPEN, HA_PRICE_HIGH, HA_PRICE_LOW - }; - -//--- Input Parameters --- -input int InpFastEMA = 12; -input int InpSlowEMA = 26; -input int InpSignalEMA = 9; -input ENUM_HA_APPLIED_PRICE InpAppliedPrice = HA_PRICE_CLOSE; - -//--- Indicator Buffers --- -double BufferMACD_Histogram[]; -double BufferMACDLine[]; -double BufferSignalLine[]; -double BufferFastEMA[]; -double BufferSlowEMA[]; - -//--- Global Objects and Variables --- -int g_ExtFastEMA, g_ExtSlowEMA, g_ExtSignalEMA; -CHeikinAshi_Calculator *g_ha_calculator; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - g_ExtFastEMA = (InpFastEMA < 1) ? 1 : InpFastEMA; - g_ExtSlowEMA = (InpSlowEMA < 1) ? 1 : InpSlowEMA; - g_ExtSignalEMA = (InpSignalEMA < 1) ? 1 : InpSignalEMA; - - if(g_ExtFastEMA > g_ExtSlowEMA) - { - int temp = g_ExtFastEMA; - g_ExtFastEMA = g_ExtSlowEMA; - g_ExtSlowEMA = temp; - } - - SetIndexBuffer(0, BufferMACD_Histogram, INDICATOR_DATA); - SetIndexBuffer(1, BufferMACDLine, INDICATOR_DATA); - SetIndexBuffer(2, BufferSignalLine, INDICATOR_DATA); - SetIndexBuffer(3, BufferFastEMA, INDICATOR_CALCULATIONS); - SetIndexBuffer(4, BufferSlowEMA, INDICATOR_CALCULATIONS); - - ArraySetAsSeries(BufferMACD_Histogram, false); - ArraySetAsSeries(BufferMACDLine, false); - ArraySetAsSeries(BufferSignalLine, false); - ArraySetAsSeries(BufferFastEMA, false); - ArraySetAsSeries(BufferSlowEMA, false); - - int macd_line_draw_begin = g_ExtSlowEMA - 1; - int signal_draw_begin = g_ExtSlowEMA + g_ExtSignalEMA - 2; - - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, signal_draw_begin); - PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, macd_line_draw_begin); - PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, signal_draw_begin); - - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA_MACD(%d,%d,%d)", g_ExtFastEMA, g_ExtSlowEMA, g_ExtSignalEMA)); - IndicatorSetInteger(INDICATOR_DIGITS, _Digits); - - g_ha_calculator = new CHeikinAshi_Calculator(); - if(CheckPointer(g_ha_calculator) == POINTER_INVALID) - { - Print("Error creating CHeikinAshi_Calculator object"); - return(INIT_FAILED); - } - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { - if(CheckPointer(g_ha_calculator) != POINTER_INVALID) - { - delete g_ha_calculator; - g_ha_calculator = NULL; - } - } - -//+------------------------------------------------------------------+ -//| MACD on Heikin 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[]) - { - int start_pos = g_ExtSlowEMA + g_ExtSignalEMA - 2; - if(rates_total <= start_pos) - return(0); - -//--- Intermediate Heikin Ashi Buffers - double ha_open[], ha_high[], ha_low[], ha_close[]; - ArrayResize(ha_open, rates_total); - ArrayResize(ha_high, rates_total); - ArrayResize(ha_low, rates_total); - ArrayResize(ha_close, rates_total); - -//--- STEP 1: Calculate Heikin Ashi bars - g_ha_calculator.Calculate(rates_total, open, high, low, close, ha_open, ha_high, ha_low, ha_close); - -//--- STEP 2: Prepare the Heikin Ashi source price array - double ha_price_source[]; - ArrayResize(ha_price_source, rates_total); - switch(InpAppliedPrice) - { - case HA_PRICE_OPEN: - ArrayCopy(ha_price_source, ha_open); - break; - case HA_PRICE_HIGH: - ArrayCopy(ha_price_source, ha_high); - break; - case HA_PRICE_LOW: - ArrayCopy(ha_price_source, ha_low); - break; - default: - ArrayCopy(ha_price_source, ha_close); - break; - } - -//--- STEP 3: Calculate Fast EMA on HA data - double pr_fast = 2.0 / (g_ExtFastEMA + 1.0); - for(int i = g_ExtFastEMA - 1; i < rates_total; i++) - { - if(i == g_ExtFastEMA - 1) - { - double sum = 0; - for(int j=0; j - -//--- Indicator Window and Plot Properties --- -#property indicator_separate_window -#property indicator_buffers 5 // Histogram, MACD Line, Signal Line, FastMA, SlowMA -#property indicator_plots 3 // Histogram, MACD Line, Signal Line - -//--- Plot 1: MACD Histogram -#property indicator_label1 "HA_Hist" -#property indicator_type1 DRAW_HISTOGRAM -#property indicator_color1 clrSilver -#property indicator_width1 1 - -//--- Plot 2: MACD Line -#property indicator_label2 "HA_MACD" -#property indicator_type2 DRAW_LINE -#property indicator_color2 clrDodgerBlue -#property indicator_style2 STYLE_SOLID -#property indicator_width2 1 - -//--- Plot 3: Signal Line -#property indicator_label3 "HA_Signal" -#property indicator_type3 DRAW_LINE -#property indicator_color3 clrOrangeRed -#property indicator_style3 STYLE_SOLID -#property indicator_width3 1 - -//--- Enum for selecting Heikin Ashi price source --- -enum ENUM_HA_APPLIED_PRICE - { - HA_PRICE_CLOSE, HA_PRICE_OPEN, HA_PRICE_HIGH, HA_PRICE_LOW - }; - -//--- Input Parameters --- -input int InpFastPeriod = 12; -input int InpSlowPeriod = 26; -input int InpSignalPeriod = 9; -input ENUM_HA_APPLIED_PRICE InpAppliedPrice = HA_PRICE_CLOSE; -input ENUM_MA_METHOD InpSourceMAType = MODE_EMA; // MA Type for Fast and Slow lines -input ENUM_MA_METHOD InpSignalMAType = MODE_EMA; // MA Type for Signal line - -//--- Indicator Buffers --- -double BufferMACD_Histogram[]; -double BufferMACDLine[]; -double BufferSignalLine[]; -double BufferFastMA[]; -double BufferSlowMA[]; - -//--- Global Objects and Variables --- -int g_ExtFastPeriod, g_ExtSlowPeriod, g_ExtSignalPeriod; -CHeikinAshi_Calculator *g_ha_calculator; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - g_ExtFastPeriod = (InpFastPeriod < 1) ? 1 : InpFastPeriod; - g_ExtSlowPeriod = (InpSlowPeriod < 1) ? 1 : InpSlowPeriod; - g_ExtSignalPeriod = (InpSignalPeriod < 1) ? 1 : InpSignalPeriod; - - if(g_ExtFastPeriod > g_ExtSlowPeriod) - { - int temp = g_ExtFastPeriod; - g_ExtFastPeriod = g_ExtSlowPeriod; - g_ExtSlowPeriod = temp; - } - - SetIndexBuffer(0, BufferMACD_Histogram, INDICATOR_DATA); - SetIndexBuffer(1, BufferMACDLine, INDICATOR_DATA); - SetIndexBuffer(2, BufferSignalLine, INDICATOR_DATA); - SetIndexBuffer(3, BufferFastMA, INDICATOR_CALCULATIONS); - SetIndexBuffer(4, BufferSlowMA, INDICATOR_CALCULATIONS); - - ArraySetAsSeries(BufferMACD_Histogram, false); - ArraySetAsSeries(BufferMACDLine, false); - ArraySetAsSeries(BufferSignalLine, false); - ArraySetAsSeries(BufferFastMA, false); - ArraySetAsSeries(BufferSlowMA, false); - - int macd_line_draw_begin = g_ExtSlowPeriod - 1; - int signal_draw_begin = g_ExtSlowPeriod + g_ExtSignalPeriod - 2; - - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, signal_draw_begin); - PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, macd_line_draw_begin); - PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, signal_draw_begin); - - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA_MACD_Pro(%d,%d,%d)", g_ExtFastPeriod, g_ExtSlowPeriod, g_ExtSignalPeriod)); - IndicatorSetInteger(INDICATOR_DIGITS, _Digits); - - g_ha_calculator = new CHeikinAshi_Calculator(); - if(CheckPointer(g_ha_calculator) == POINTER_INVALID) - { - Print("Error creating CHeikinAshi_Calculator object"); - return(INIT_FAILED); - } - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { - if(CheckPointer(g_ha_calculator) != POINTER_INVALID) - { - delete g_ha_calculator; - g_ha_calculator = NULL; - } - } - -//+------------------------------------------------------------------+ -//| MACD Pro on Heikin 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[]) - { - int start_pos = g_ExtSlowPeriod + g_ExtSignalPeriod - 2; - if(rates_total <= start_pos) - return(0); - -//--- Intermediate Heikin Ashi Buffers - double ha_open[], ha_high[], ha_low[], ha_close[]; - ArrayResize(ha_open, rates_total); - ArrayResize(ha_high, rates_total); - ArrayResize(ha_low, rates_total); - ArrayResize(ha_close, rates_total); - -//--- STEP 1: Calculate Heikin Ashi bars - g_ha_calculator.Calculate(rates_total, open, high, low, close, ha_open, ha_high, ha_low, ha_close); - -//--- STEP 2: Prepare the Heikin Ashi source price array - double ha_price_source[]; - ArrayResize(ha_price_source, rates_total); - switch(InpAppliedPrice) - { - case HA_PRICE_OPEN: - ArrayCopy(ha_price_source, ha_open); - break; - case HA_PRICE_HIGH: - ArrayCopy(ha_price_source, ha_high); - break; - case HA_PRICE_LOW: - ArrayCopy(ha_price_source, ha_low); - break; - default: - ArrayCopy(ha_price_source, ha_close); - break; - } - -//--- STEP 3: Calculate Fast MA on HA data - for(int i = g_ExtFastPeriod - 1; i < rates_total; i++) - { - switch(InpSourceMAType) - { - case MODE_EMA: - case MODE_SMMA: - if(i == g_ExtFastPeriod - 1) - { - double sum=0; - for(int j=0; j0) - BufferFastMA[i]=lwma_sum/weight_sum; - } - break; - default: // MODE_SMA - { - double sum=0; - for(int j=0; j0) - BufferSlowMA[i]=lwma_sum/weight_sum; - } - break; - default: // MODE_SMA - { - double sum=0; - for(int j=0; j0) - BufferSignalLine[i]=lwma_sum/weight_sum; - } - break; - default: // MODE_SMA - { - double sum=0; - for(int j=0; j - -//--- Plot 1: MAMA Line -#property indicator_label1 "MAMA" -#property indicator_type1 DRAW_LINE -#property indicator_color1 clrRed -#property indicator_style1 STYLE_SOLID -#property indicator_width1 2 - -//--- Plot 2: FAMA Line -#property indicator_label2 "FAMA" -#property indicator_type2 DRAW_LINE -#property indicator_color2 clrGreen -#property indicator_style2 STYLE_SOLID -#property indicator_width2 1 - -//--- Input Parameters --- -input ENUM_APPLIED_PRICE InpSourcePrice = PRICE_CLOSE; // Source Price -input double InpFastLimit = 0.5; // Fast Limit -input double InpSlowLimit = 0.05; // Slow Limit - -//--- Indicator Buffers --- -double BufferMAMA[]; -double BufferFAMA[]; - -//--- Global calculator object --- -CMESACalculator *g_calculator; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - SetIndexBuffer(0, BufferMAMA, INDICATOR_DATA); - SetIndexBuffer(1, BufferFAMA, INDICATOR_DATA); - ArraySetAsSeries(BufferMAMA, false); - ArraySetAsSeries(BufferFAMA, false); - - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, 10); - PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, 10); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("MAMA/FAMA(%.2f, %.2f)", InpFastLimit, InpSlowLimit)); - - g_calculator = new CMESACalculator(); - if(CheckPointer(g_calculator) == POINTER_INVALID || !g_calculator.Init(InpFastLimit, InpSlowLimit)) - { - Print("Failed to initialize MESA Calculator."); - return(INIT_FAILED); - } - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { - if(CheckPointer(g_calculator) != POINTER_INVALID) - delete g_calculator; - } - -//+------------------------------------------------------------------+ -//| Custom indicator iteration 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(CheckPointer(g_calculator) != POINTER_INVALID) - { - //--- Corrected: Pass all required parameters to the Calculate method - g_calculator.Calculate(rates_total, InpSourcePrice, open, high, low, close, BufferMAMA, BufferFAMA); - } - return(rates_total); - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/MAMA_FAMA_HeikinAshi.mq5 b/Indicators/MyIndicators/MAMA_FAMA_HeikinAshi.mq5 deleted file mode 100644 index 1366bda..0000000 --- a/Indicators/MyIndicators/MAMA_FAMA_HeikinAshi.mq5 +++ /dev/null @@ -1,95 +0,0 @@ -//+------------------------------------------------------------------+ -//| MAMA_FAMA_HeikinAshi.mq5 | -//| Copyright 2025, xxxxxxxx| -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property version "1.01" -#property description "MESA Adaptive Moving Average (MAMA) and FAMA on Heikin Ashi data." - -#property indicator_chart_window -#property indicator_buffers 2 -#property indicator_plots 2 - -#include - -//--- Plot 1: MAMA Line -#property indicator_label1 "MAMA (HA)" -#property indicator_type1 DRAW_LINE -#property indicator_color1 clrRed -#property indicator_style1 STYLE_SOLID -#property indicator_width1 2 - -//--- Plot 2: FAMA Line -#property indicator_label2 "FAMA (HA)" -#property indicator_type2 DRAW_LINE -#property indicator_color2 clrGreen -#property indicator_style2 STYLE_SOLID -#property indicator_width2 1 - -//--- Input Parameters --- -input double InpFastLimit = 0.5; -input double InpSlowLimit = 0.05; - -//--- Indicator Buffers --- -double BufferMAMA[]; -double BufferFAMA[]; - -//--- Global calculator object --- -CMESACalculator_HA *g_calculator; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - SetIndexBuffer(0, BufferMAMA, INDICATOR_DATA); - SetIndexBuffer(1, BufferFAMA, INDICATOR_DATA); - ArraySetAsSeries(BufferMAMA, false); - ArraySetAsSeries(BufferFAMA, false); - - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, 10); - PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, 10); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("MAMA/FAMA HA(%.2f, %.2f)", InpFastLimit, InpSlowLimit)); - - g_calculator = new CMESACalculator_HA(); - if(CheckPointer(g_calculator) == POINTER_INVALID || !g_calculator.Init(InpFastLimit, InpSlowLimit)) - { - Print("Failed to initialize MESA HA Calculator."); - return(INIT_FAILED); - } - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { - if(CheckPointer(g_calculator) != POINTER_INVALID) - delete g_calculator; - } - -//+------------------------------------------------------------------+ -//| Custom indicator iteration 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(CheckPointer(g_calculator) != POINTER_INVALID) - { - //--- The HA calculator needs the original OHLC for conversion. - //--- The price_type parameter is ignored by the HA calculator. - g_calculator.Calculate(rates_total, PRICE_CLOSE, open, high, low, close, BufferMAMA, BufferFAMA); - } - return(rates_total); - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/MFI.md b/Indicators/MyIndicators/MFI.md deleted file mode 100644 index 459243b..0000000 --- a/Indicators/MyIndicators/MFI.md +++ /dev/null @@ -1,71 +0,0 @@ -# Money Flow Index (MFI) - -## 1. Summary (Introduction) - -The Money Flow Index (MFI) is a momentum oscillator that measures the strength of money flowing into and out of a security. Developed as a "volume-weighted RSI," it combines both price and volume data to identify overbought or oversold conditions. - -Unlike the standard RSI which only considers price, the MFI incorporates volume to provide a clearer picture of the conviction behind price moves. A strong price trend accompanied by high volume is considered more significant than one with low volume. This makes the MFI a powerful tool for gauging trend strength and spotting potential reversals, particularly through divergence signals. - -## 2. Mathematical Foundations and Calculation Logic - -The MFI calculation is similar to the RSI, but instead of using simple price changes, it uses "Money Flow," which is derived from the Typical Price and Volume. - -### Required Components - -- **Period (N):** The lookback period for the calculation (e.g., 14). -- **Price and Volume Data:** The `High`, `Low`, `Close`, and `Volume` of each bar. - -### Calculation Steps (Algorithm) - -1. **Calculate the Typical Price (TP):** For each bar, calculate the average of the high, low, and close. - $\text{TP}_i = \frac{\text{High}_i + \text{Low}_i + \text{Close}_i}{3}$ - -2. **Calculate the Raw Money Flow (RMF):** Multiply the Typical Price by the volume for that period. - $\text{Raw Money Flow}_i = \text{TP}_i \times \text{Volume}_i$ - -3. **Determine Positive and Negative Money Flow:** Compare the current bar's Typical Price to the previous bar's. - - - If $\text{TP}_i > \text{TP}_{i-1}$, it is considered **Positive Money Flow** ($\text{PMF}_i = \text{RMF}_i$). - - If $\text{TP}_i < \text{TP}_{i-1}$, it is considered **Negative Money Flow** ($\text{NMF}_i = \text{RMF}_i$). - - If they are equal, the money flow is zero for that period. - -4. **Calculate the Money Flow Ratio:** Sum the Positive and Negative Money Flows over the period `N` and calculate their ratio. - $\text{Money Flow Ratio} = \frac{\sum_{k=i-N+1}^{i} \text{PMF}_k}{\sum_{k=i-N+1}^{i} \text{NMF}_k}$ - -5. **Calculate the Money Flow Index (MFI):** Use the ratio to scale the value between 0 and 100. - $\text{MFI}_i = 100 - \frac{100}{1 + \text{Money Flow Ratio}}$ - -## 3. MQL5 Implementation Details - -Our MQL5 implementation is a self-contained, robust, and mathematically correct representation of the classic MFI. - -- **Stability via Full Recalculation:** We employ a "brute-force" full recalculation within the `OnCalculate` function to ensure maximum stability and prevent calculation errors. - -- **Correct Algorithm:** Unlike the flawed example code provided with MetaTrader, our implementation strictly follows the correct, textbook definition of the MFI, ensuring its results are consistent with other professional charting platforms like TradingView. - -- **Efficient Calculation:** The summation of Positive and Negative Money Flow over the lookback period is handled by an efficient **sliding window sum** technique. This avoids nested loops and provides excellent performance. - -- **Optional Signal Line:** Our version is enhanced with an optional, user-configurable moving average signal line. The signal line calculation uses our standard, robust, and fully manual `switch` block, which correctly handles all MA types (SMA, EMA, SMMA, LWMA) and their initialization. - -- **Heikin Ashi Variant (`MFI_HeikinAshi.mq5`):** - - Our toolkit also includes a "pure" Heikin Ashi version. The calculation logic is identical, but it uses the smoothed Heikin Ashi `ha_high`, `ha_low`, and `ha_close` to calculate the Typical Price. - - This results in a smoother MFI that filters out price noise. It is particularly effective at producing **clearer and more pronounced divergence signals**, as the Heikin Ashi smoothing helps to identify the true underlying momentum faster than standard price data. - -## 4. Parameters - -- **MFI Period (`InpMFIPeriod`):** The lookback period for summing the money flows. The standard is `14`. -- **Volume Type (`InpVolumeType`):** Allows the user to select between Tick Volume (`VOLUME_TICK`) and Real Volume (`VOLUME_REAL`). -- **Signal Line Settings:** - - `InpMAPeriod`: The lookback period for the optional signal line. - - `InpMAMethod`: The type of moving average for the signal line. - -## 5. Usage and Interpretation - -- **Overbought/Oversold Levels:** The primary use of the MFI is to identify extreme conditions. - - **Overbought:** Readings above **80** are considered overbought. - - **Oversold:** Readings below **20** are considered oversold. -- **Divergence:** This is the MFI's most powerful signal. - - **Bullish Divergence:** Price makes a lower low, but the MFI makes a higher low. This indicates that despite the lower price, selling pressure (volume) is weakening, which can foreshadow a bullish reversal. - - **Bearish Divergence:** Price makes a higher high, but the MFI makes a lower high. This indicates that the new high is not supported by strong money flow, and buying pressure is weakening, which can foreshadow a bearish reversal. -- **Signal Line Crossovers:** If the optional signal line is used, crossovers can provide entry and exit signals, similar to other oscillators like RSI or CCI. -- **Caution:** In a very strong trend, the MFI can remain in overbought or oversold territory for extended periods. Divergence signals are generally considered more reliable than simple overbought/oversold readings. diff --git a/Indicators/MyIndicators/MFI.mq5 b/Indicators/MyIndicators/MFI.mq5 deleted file mode 100644 index 06d429b..0000000 --- a/Indicators/MyIndicators/MFI.mq5 +++ /dev/null @@ -1,198 +0,0 @@ -//+------------------------------------------------------------------+ -//| MFI.mq5 | -//| Copyright 2025, xxxxxxxx | -//| | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property link "" -#property version "2.00" // Added signal line and refactored for stability -#property description "Money Flow Index with a signal line." - -//--- Indicator Window and Plot Properties --- -#property indicator_separate_window -#property indicator_buffers 2 // MFI and Signal Line -#property indicator_plots 2 -#property indicator_maximum 100.0 -#property indicator_minimum 0.0 -#property indicator_level1 20.0 -#property indicator_level2 80.0 -#property indicator_level3 50.0 -#property indicator_levelstyle STYLE_DOT - -//--- Plot 1: MFI line -#property indicator_label1 "MFI" -#property indicator_type1 DRAW_LINE -#property indicator_color1 clrDodgerBlue -#property indicator_style1 STYLE_SOLID -#property indicator_width1 1 - -//--- Plot 2: Signal line -#property indicator_label2 "Signal" -#property indicator_type2 DRAW_LINE -#property indicator_color2 clrOrangeRed -#property indicator_style2 STYLE_DOT -#property indicator_width2 1 - -//--- Input Parameters --- -input int InpMFIPeriod = 14; -input ENUM_APPLIED_VOLUME InpVolumeType = VOLUME_TICK; -input group "Signal Line Settings" -input int InpMAPeriod = 9; -input ENUM_MA_METHOD InpMAMethod = MODE_SMA; - -//--- Indicator Buffers --- -double BufferMFI[]; -double BufferSignal[]; - -//--- Global Variables --- -int g_ExtMFIPeriod, g_ExtMAPeriod; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - g_ExtMFIPeriod = (InpMFIPeriod < 1) ? 1 : InpMFIPeriod; - g_ExtMAPeriod = (InpMAPeriod < 1) ? 1 : InpMAPeriod; - - SetIndexBuffer(0, BufferMFI, INDICATOR_DATA); - SetIndexBuffer(1, BufferSignal, INDICATOR_DATA); - - ArraySetAsSeries(BufferMFI, false); - ArraySetAsSeries(BufferSignal, false); - - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, g_ExtMFIPeriod); - PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, g_ExtMFIPeriod + g_ExtMAPeriod - 1); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("MFI(%d, %d)", g_ExtMFIPeriod, g_ExtMAPeriod)); - IndicatorSetInteger(INDICATOR_DIGITS, 2); - - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Money Flow 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[]) - { - int start_pos = g_ExtMFIPeriod + g_ExtMAPeriod; - if(rates_total <= start_pos) - return(0); - -//--- STEP 1: Calculate Typical Price - double typical_price[]; - ArrayResize(typical_price, rates_total); - for(int i=0; i typical_price[i-1]) - { - positive_mf[i] = raw_money_flow; - } - else - if(typical_price[i] < typical_price[i-1]) - { - negative_mf[i] = raw_money_flow; - } - } - -//--- STEP 3: Calculate Money Flow Ratio and MFI using a sliding window sum - double sum_pos = 0; - double sum_neg = 0; - for(int i = 1; i < rates_total; i++) - { - sum_pos += positive_mf[i]; - sum_neg += negative_mf[i]; - - if(i > g_ExtMFIPeriod) - { - sum_pos -= positive_mf[i - g_ExtMFIPeriod]; - sum_neg -= negative_mf[i - g_ExtMFIPeriod]; - } - - if(i >= g_ExtMFIPeriod) - { - if(sum_neg > 0) - { - double money_ratio = sum_pos / sum_neg; - BufferMFI[i] = 100.0 - (100.0 / (1.0 + money_ratio)); - } - else - { - BufferMFI[i] = 100.0; - } - } - } - -//--- STEP 4: Calculate the Signal Line (MA of MFI) - int ma_start_pos = g_ExtMFIPeriod + g_ExtMAPeriod - 1; - for(int i = ma_start_pos; i < rates_total; i++) - { - switch(InpMAMethod) - { - case MODE_EMA: - case MODE_SMMA: - if(i == ma_start_pos) - { - double sum=0; - for(int j=0; j0) - BufferSignal[i]=lwma_sum/weight_sum; - } - break; - default: // MODE_SMA - { - double sum=0; - for(int j=0; j - -//--- Indicator Window and Plot Properties --- -#property indicator_separate_window -#property indicator_buffers 2 // MFI and Signal Line -#property indicator_plots 2 -#property indicator_maximum 100.0 -#property indicator_minimum 0.0 -#property indicator_level1 20.0 -#property indicator_level2 80.0 -#property indicator_level3 50.0 -#property indicator_levelstyle STYLE_DOT - -//--- Plot 1: MFI line -#property indicator_label1 "HA_MFI" -#property indicator_type1 DRAW_LINE -#property indicator_color1 clrDodgerBlue -#property indicator_style1 STYLE_SOLID -#property indicator_width1 1 - -//--- Plot 2: Signal line -#property indicator_label2 "HA_Signal" -#property indicator_type2 DRAW_LINE -#property indicator_color2 clrOrangeRed -#property indicator_style2 STYLE_DOT -#property indicator_width2 1 - -//--- Input Parameters --- -input int InpMFIPeriod = 14; -input ENUM_APPLIED_VOLUME InpVolumeType = VOLUME_TICK; -input group "Signal Line Settings" -input int InpMAPeriod = 9; -input ENUM_MA_METHOD InpMAMethod = MODE_SMA; - -//--- Indicator Buffers --- -double BufferMFI[]; -double BufferSignal[]; - -//--- Global Objects and Variables --- -int g_ExtMFIPeriod, g_ExtMAPeriod; -CHeikinAshi_Calculator *g_ha_calculator; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - g_ExtMFIPeriod = (InpMFIPeriod < 1) ? 1 : InpMFIPeriod; - g_ExtMAPeriod = (InpMAPeriod < 1) ? 1 : InpMAPeriod; - - SetIndexBuffer(0, BufferMFI, INDICATOR_DATA); - SetIndexBuffer(1, BufferSignal, INDICATOR_DATA); - - ArraySetAsSeries(BufferMFI, false); - ArraySetAsSeries(BufferSignal, false); - - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, g_ExtMFIPeriod); - PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, g_ExtMFIPeriod + g_ExtMAPeriod - 1); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA_MFI(%d, %d)", g_ExtMFIPeriod, g_ExtMAPeriod)); - IndicatorSetInteger(INDICATOR_DIGITS, 2); - - g_ha_calculator = new CHeikinAshi_Calculator(); - if(CheckPointer(g_ha_calculator) == POINTER_INVALID) - { - Print("Error creating CHeikinAshi_Calculator object"); - return(INIT_FAILED); - } - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { - if(CheckPointer(g_ha_calculator) != POINTER_INVALID) - { - delete g_ha_calculator; - g_ha_calculator = NULL; - } - } - -//+------------------------------------------------------------------+ -//| MFI on Heikin 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[]) - { - int start_pos = g_ExtMFIPeriod + g_ExtMAPeriod; - if(rates_total <= start_pos) - return(0); - -//--- Intermediate Heikin Ashi Buffers - double ha_open[], ha_high[], ha_low[], ha_close[]; - ArrayResize(ha_open, rates_total); - ArrayResize(ha_high, rates_total); - ArrayResize(ha_low, rates_total); - ArrayResize(ha_close, rates_total); - -//--- STEP 1: Calculate Heikin Ashi bars - g_ha_calculator.Calculate(rates_total, open, high, low, close, ha_open, ha_high, ha_low, ha_close); - -//--- STEP 2: Calculate HA Typical Price and Raw Money Flow - double ha_typical_price[], raw_money_flow[]; - ArrayResize(ha_typical_price, rates_total); - ArrayResize(raw_money_flow, rates_total); - for(int i=0; i ha_typical_price[i-1]) - { - positive_mf[i] = raw_money_flow[i]; - } - else - if(ha_typical_price[i] < ha_typical_price[i-1]) - { - negative_mf[i] = raw_money_flow[i]; - } - } - -//--- STEP 4: Calculate Money Flow Ratio and MFI using a sliding window sum - double sum_pos = 0; - double sum_neg = 0; - for(int i = 1; i < rates_total; i++) - { - sum_pos += positive_mf[i]; - sum_neg += negative_mf[i]; - - if(i > g_ExtMFIPeriod) - { - sum_pos -= positive_mf[i - g_ExtMFIPeriod]; - sum_neg -= negative_mf[i - g_ExtMFIPeriod]; - } - - if(i >= g_ExtMFIPeriod) - { - if(sum_neg > 0) - { - double money_ratio = sum_pos / sum_neg; - BufferMFI[i] = 100.0 - (100.0 / (1.0 + money_ratio)); - } - else - { - BufferMFI[i] = 100.0; - } - } - } - -//--- STEP 5: Calculate the Signal Line (MA of MFI) - int ma_start_pos = g_ExtMFIPeriod + g_ExtMAPeriod - 1; - for(int i = ma_start_pos; i < rates_total; i++) - { - switch(InpMAMethod) - { - case MODE_EMA: - case MODE_SMMA: - if(i == ma_start_pos) - { - double sum=0; - for(int j=0; j0) - BufferSignal[i]=lwma_sum/weight_sum; - } - break; - default: // MODE_SMA - { - double sum=0; - for(int j=0; j - -//--- 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 Heikin Ashi price source --- -enum ENUM_HA_APPLIED_PRICE - { - HA_PRICE_CLOSE, // Heikin Ashi Close - HA_PRICE_OPEN, // Heikin Ashi Open - HA_PRICE_HIGH, // Heikin Ashi High - HA_PRICE_LOW, // Heikin Ashi Low - }; - -//--- Input Parameters --- -input int InpLength = 14; -input ENUM_HA_APPLIED_PRICE InpAppliedPrice = HA_PRICE_CLOSE; - -//--- Indicator Buffers --- -double BufferHA_McGinley[]; - -//--- Intermediate Heikin Ashi Buffers --- -double ExtHaOpenBuffer[]; -double ExtHaHighBuffer[]; -double ExtHaLowBuffer[]; -double ExtHaCloseBuffer[]; - -//--- Global Objects and Variables --- -int g_ExtLength; -CHeikinAshi_Calculator *g_ha_calculator; // Pointer to our Heikin Ashi calculator - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - g_ExtLength = (InpLength < 1) ? 1 : InpLength; - - SetIndexBuffer(0, BufferHA_McGinley, INDICATOR_DATA); - ArraySetAsSeries(BufferHA_McGinley, false); - - IndicatorSetInteger(INDICATOR_DIGITS, _Digits); - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, 1); // McGinley can be drawn from the 2nd bar - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA_McGinley(%d)", g_ExtLength)); - -//--- Create the calculator instance - g_ha_calculator = new CHeikinAshi_Calculator(); - if(CheckPointer(g_ha_calculator) == POINTER_INVALID) - { - Print("Error creating CHeikinAshi_Calculator object"); - return(INIT_FAILED); - } - - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { -//--- Free the calculator object - if(CheckPointer(g_ha_calculator) != POINTER_INVALID) - { - delete g_ha_calculator; - g_ha_calculator = NULL; - } - } - -//+------------------------------------------------------------------+ -//| McGinley Dynamic on Heikin 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 < 2) - return(0); - -//--- Resize intermediate buffers - ArrayResize(ExtHaOpenBuffer, rates_total); - ArrayResize(ExtHaHighBuffer, rates_total); - ArrayResize(ExtHaLowBuffer, rates_total); - ArrayResize(ExtHaCloseBuffer, rates_total); - -//--- STEP 1: Calculate Heikin Ashi bars - g_ha_calculator.Calculate(rates_total, open, high, low, close, - ExtHaOpenBuffer, ExtHaHighBuffer, ExtHaLowBuffer, ExtHaCloseBuffer); - -//--- STEP 2: Select the source Heikin Ashi price array - double ha_price_source[]; - switch(InpAppliedPrice) - { - case HA_PRICE_OPEN: - ArrayCopy(ha_price_source, ExtHaOpenBuffer); - break; - case HA_PRICE_HIGH: - ArrayCopy(ha_price_source, ExtHaHighBuffer); - break; - case HA_PRICE_LOW: - ArrayCopy(ha_price_source, ExtHaLowBuffer); - break; - default: - ArrayCopy(ha_price_source, ExtHaCloseBuffer); - break; - } - -//--- STEP 3: Main calculation loop for McGinley Dynamic - for(int i = 0; i < rates_total; i++) - { - // --- Initialization Step --- - if(i == 0) - { - // The first McGinley value is simply the first source price - BufferHA_McGinley[i] = ha_price_source[i]; - continue; - } - - // --- Recursive Calculation Step --- - double prev_mg = BufferHA_McGinley[i-1]; - - // Prevent division by zero if the previous value was somehow zero - if(prev_mg == 0) - { - BufferHA_McGinley[i] = ha_price_source[i]; - continue; - } - - double denominator = g_ExtLength * MathPow(ha_price_source[i] / prev_mg, 4); - - // Prevent division by zero if the denominator becomes zero - if(denominator == 0) - { - BufferHA_McGinley[i] = prev_mg; - continue; - } - - BufferHA_McGinley[i] = prev_mg + (ha_price_source[i] - prev_mg) / denominator; - } - - return(rates_total); - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+ diff --git a/Indicators/MyIndicators/Pascal_WMA.md b/Indicators/MyIndicators/Pascal_WMA.md deleted file mode 100644 index 8d12f05..0000000 --- a/Indicators/MyIndicators/Pascal_WMA.md +++ /dev/null @@ -1,62 +0,0 @@ -# Pascal Weighted Moving Average (Pascal WMA) - -## 1. Summary (Introduction) - -The Pascal Weighted Moving Average (Pascal WMA) is a unique type of weighted moving average that derives its weights from the coefficients of Pascal's triangle. This mathematical structure, known from combinatorics, produces a set of weights that are perfectly symmetrical and follow a smooth, bell-shaped (Gaussian-like) curve. - -Similar to the Sine WMA, the Pascal WMA is a **symmetrical, zero-lag smoothing filter**. Its primary purpose is not to follow trends with minimal lag, but to provide an exceptionally smooth and stable representation of the market's central tendency or "fair value". By assigning the heaviest weights to the price data in the middle of the lookback period, it effectively filters out market noise and reduces the impact of short-term, insignificant price spikes. - -The result is a clean, aesthetically pleasing line that glides through the price action, making it a powerful tool for identifying the underlying smoothed trend and for mean-reversion analysis. - -## 2. Mathematical Foundations and Calculation Logic - -The Pascal WMA calculates a weighted average where the weights are the binomial coefficients found in a row of Pascal's triangle. - -### Required Components - -- **Period (N):** The lookback period for the moving average. This determines which row of Pascal's triangle is used. -- **Source Price:** The price series used for calculation (e.g., `PRICE_CLOSE`). - -### Calculation Steps (Algorithm) - -1. **Generate Pascal Weights:** For a given period `N`, the weights are the coefficients of the binomial expansion of $(x+y)^{N-1}$. These coefficients correspond to the `N`-th row of Pascal's triangle (starting the count from row 0). The `k`-th weight in the sequence (where `k` is from 0 to N-1) is calculated using the combination formula: - - $Weight_k = C(N-1, k) = \frac{(N-1)!}{k! \cdot (N-1-k)!}$ - -2. **Calculate the Weighted Sum:** For each bar `t`, multiply the last `N` prices by the corresponding Pascal coefficients. - - $\text{Weighted Sum}_t = \sum_{i=0}^{N-1} (\text{Price}_{t-i} \cdot Weight_i)$ - -3. **Calculate the Sum of Weights:** Sum all the generated Pascal weights. A known property of Pascal's triangle is that the sum of the `n`-th row is $2^n$. Therefore, the sum of weights is $2^{N-1}$. - - $\text{Sum of Weights} = \sum_{i=0}^{N-1} Weight_i = 2^{N-1}$ - -4. **Calculate the Final WMA Value:** Divide the weighted sum of prices by the sum of the weights. - - $\text{Pascal WMA}_t = \frac{\text{Weighted Sum}_t}{\text{Sum of Weights}}$ - -This process results in a symmetrically weighted average that is centered on the data, providing a very smooth output with a Gaussian-like response. - -## 3. MQL5 Implementation Details - -Our MQL5 implementation is a clean and robust indicator that accurately calculates the Pascal WMA using an efficient algorithm. - -- **Self-Contained, Object-Oriented Design:** The entire logic is encapsulated within a single `.mq5` file but is internally structured into a dedicated `CPascalWMACalculator` class. This separates the calculation logic from the indicator's buffer management, ensuring the code is clean and maintainable. - -- **Efficient Weight Generation:** The Pascal's triangle coefficients are calculated only once during the indicator's initialization in the `Init()` method of the calculator class. The algorithm for calculating combinations (`n C k`) is optimized to handle large numbers by using the multiplicative formula and symmetry (`C(n, k) = C(n, n-k)`), preventing unnecessary computations and potential overflows. The weights and their sum are stored in internal class members for efficient reuse. - -- **Stability via Full Recalculation:** In line with our core principles, the indicator employs a "brute-force" full recalculation within the `OnCalculate` function. This is the most reliable method to ensure stability and prevent any potential glitches, while keeping the code simple and robust. - -- **Correct Symmetrical Application:** The `Calculate` method applies the pre-calculated symmetrical weights directly to the price data. The weights are **not reversed**. The most recent price is multiplied by the first (and smallest) coefficient, and the price in the middle of the period is multiplied by the largest coefficient. This correctly implements the smoothing, centered nature of the filter. The inherent lag of `(Period-1)/2` bars is a mathematical property of the filter. - -## 4. Parameters - -- **Period (`InpPeriod`):** The lookback period for the moving average. A longer period results in a smoother, more heavily filtered line that is less sensitive to short-term price fluctuations. Default is `21`. -- **Source Price (`InpSourcePrice`):** The price data used for the calculation (Close, Open, High, Low, Median, etc.). Default is `PRICE_CLOSE`. - -## 5. Usage and Interpretation - -The Pascal WMA should be interpreted as a **high-quality smoothing filter and a "mean" or "center of gravity" line**, not as a traditional trend-following moving average. - -- **Noise Reduction and Trend Clarity:** The primary use of the Pascal WMA is to filter out market noise and provide a much clearer picture of the underlying price movement. Its extremely smooth, bell-shaped response makes it highly effective at ignoring insignificant price spikes. -- **Mean Reversion Signals:** The line acts as a "magnet" for the price. - - When the price moves significantly **above** the Pascal WMA, it can be considered over-extended, increasing the probability of a reversion (downward correction) back towards the line. - - When the price moves significantly **below** the Pascal WMA, it can be considered oversold, increasing the probability of a reversion back up towards the line. -- **Confirmation of Trend Direction:** The slope of the Pascal WMA provides a very stable, albeit lagging, confirmation of the main trend direction. Because it is very slow to turn, a change in the slope's direction is a significant event, suggesting a potential major shift in the market. -- **Caution:** Due to its inherent nature as a centered, smoothing filter, the Pascal WMA will always lag the price. It should **not** be used for fast crossover signals in the same way as an EMA. Its strength lies in its exceptional smoothness and its ability to define the market's equilibrium point, making it an excellent tool for mean-reversion strategies or as a baseline in more complex systems. diff --git a/Indicators/MyIndicators/Pascal_WMA.mq5 b/Indicators/MyIndicators/Pascal_WMA.mq5 deleted file mode 100644 index 406c5ce..0000000 --- a/Indicators/MyIndicators/Pascal_WMA.mq5 +++ /dev/null @@ -1,199 +0,0 @@ -//+------------------------------------------------------------------+ -//| Pascal_WMA.mq5 | -//| Copyright 2025, xxxxxxxx| -//| | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property version "1.00" -#property description "Pascal's Triangle Weighted Moving Average. A zero-lag smoothing filter." - -#property indicator_chart_window -#property indicator_buffers 1 -#property indicator_plots 1 - -//--- Plot 1: Pascal WMA Line -#property indicator_label1 "Pascal WMA" -#property indicator_type1 DRAW_LINE -#property indicator_color1 clrMediumPurple -#property indicator_style1 STYLE_SOLID -#property indicator_width1 2 - -//--- Input Parameters --- -input int InpPeriod = 21; -input ENUM_APPLIED_PRICE InpSourcePrice = PRICE_CLOSE; - -//--- Indicator Buffers --- -double BufferWMA[]; -double BufferPrice[]; - -//+------------------------------------------------------------------+ -//| CLASS: CPascalWMACalculator | -//| Encapsulates the logic for Pascal's Triangle weighting. | -//+------------------------------------------------------------------+ -class CPascalWMACalculator - { -private: - int m_period; - double m_weights[]; - double m_weight_sum; - -public: - CPascalWMACalculator(void); - ~CPascalWMACalculator(void) {}; - - bool Init(int period); - void Calculate(int rates_total, const double &price_src[], double &wma_out[]); - }; - -//+------------------------------------------------------------------+ -//| CPascalWMACalculator: Constructor | -//+------------------------------------------------------------------+ -CPascalWMACalculator::CPascalWMACalculator(void) : m_period(0), m_weight_sum(0) - { - } - -//+------------------------------------------------------------------+ -//| CPascalWMACalculator: Initialization and Weight Generation | -//+------------------------------------------------------------------+ -bool CPascalWMACalculator::Init(int period) - { - m_period = (period < 2) ? 2 : period; - ArrayResize(m_weights, m_period); - m_weight_sum = 0; - -//--- Generate weights from Pascal's triangle row (n C k) -//--- n = period - 1 - for(int i = 0; i < m_period; i++) - { - long n = m_period - 1; - long k = i; - - // Optimization for combinations: C(n, k) = C(n, n-k) - if(k > n / 2) - k = n - k; - - long res = 1; - for(long j = 1; j <= k; j++) - { - // Defensive check to prevent division by zero, though j starts at 1 - if(j == 0) - continue; - res = res * (n - j + 1) / j; - } - m_weights[i] = (double)res; - m_weight_sum += m_weights[i]; - } - - return (m_weight_sum != 0); - } - -//+------------------------------------------------------------------+ -//| CPascalWMACalculator: Main Calculation Method | -//+------------------------------------------------------------------+ -void CPascalWMACalculator::Calculate(int rates_total, const double &price_src[], double &wma_out[]) - { - if(rates_total < m_period) - return; - - for(int i = m_period - 1; i < rates_total; i++) - { - double weighted_sum = 0; - for(int j = 0; j < m_period; j++) - { - // Symmetrical weighting, use weights as generated - weighted_sum += price_src[i - j] * m_weights[j]; - } - wma_out[i] = weighted_sum / m_weight_sum; - } - } - -//--- Global calculator object --- -CPascalWMACalculator *g_calculator; - -//--- Forward declaration -int PriceSeries(ENUM_APPLIED_PRICE,int,const double&[],const double&[],const double&[],const double&[],double&[]); - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - SetIndexBuffer(0, BufferWMA, INDICATOR_DATA); - ArraySetAsSeries(BufferWMA, false); - - g_calculator = new CPascalWMACalculator(); - if(CheckPointer(g_calculator) == POINTER_INVALID || !g_calculator.Init(InpPeriod)) - { - Print("Failed to initialize Pascal WMA Calculator."); - return(INIT_FAILED); - } - - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, InpPeriod - 1); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("PascalWMA(%d)", InpPeriod)); - - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { - if(CheckPointer(g_calculator) != POINTER_INVALID) - delete g_calculator; - } - -//+------------------------------------------------------------------+ -//| Custom indicator iteration function. | -//+------------------------------------------------------------------+ -int OnCalculate(const int rates_total, const int, const datetime&[], const double &open[], const double &high[], const double &low[], const double &close[], const long&[], const long&[], const int&[]) - { - ArrayResize(BufferPrice, rates_total); - if(PriceSeries(InpSourcePrice, rates_total, open, high, low, close, BufferPrice) <= 0) - return 0; - - if(CheckPointer(g_calculator) != POINTER_INVALID) - { - g_calculator.Calculate(rates_total, BufferPrice, BufferWMA); - } - return(rates_total); - } - -//+------------------------------------------------------------------+ -//| Helper function to get the selected price series. | -//+------------------------------------------------------------------+ -int PriceSeries(ENUM_APPLIED_PRICE type, int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], double &dest_buffer[]) - { - switch(type) - { - case PRICE_CLOSE: - ArrayCopy(dest_buffer, close, 0, 0, rates_total); - break; - case PRICE_OPEN: - ArrayCopy(dest_buffer, open, 0, 0, rates_total); - break; - case PRICE_HIGH: - ArrayCopy(dest_buffer, high, 0, 0, rates_total); - break; - case PRICE_LOW: - ArrayCopy(dest_buffer, low, 0, 0, rates_total); - break; - case PRICE_MEDIAN: - for(int i=0; i` library and ensures robust behavior on `non-timeseries` arrays. - -- **Indicator Family:** - - - **Line Versions:** `RSIMA.mq5` and `RSI_HeikinAshi.mq5` plot the RSI line and its signal line. - - **Oscillator Versions:** `RSI_Oscillator.mq5` and `RSI_Oscillator_HeikinAshi.mq5` plot the difference between the two lines as a histogram. - -- **Heikin Ashi Variant (`RSI_HeikinAshi.mq5`):** - - Our toolkit also includes a Heikin Ashi version. The calculation logic is identical, but it uses the smoothed Heikin Ashi `ha_close` values as the input for the initial RSI calculation. This results in a doubly-smoothed oscillator. - -## 4. Parameters - -- **RSI Period (`InpPeriodRSI`):** The lookback period for the underlying RSI calculation. Default is `14`. -- **Applied Price (`InpAppliedPrice`):** The source price used for the RSI calculation (standard version only). -- **Signal Line Settings:** - - `InpPeriodMA`: The lookback period for the moving average that smooths the RSI line. - - `InpMethodMA`: The type of moving average to use for smoothing (SMA, EMA, SMMA, LWMA). - -## 5. Usage and Interpretation - -- **Trend and Momentum Confirmation:** The primary use is to provide a clearer view of momentum. When the signal line is rising, it confirms bullish momentum; when it's falling, it confirms bearish momentum. -- **Signal Generation via Crossovers:** - - **RSI / Signal Line Crossover:** When the raw RSI line crosses above its moving average, it can be seen as a bullish signal. A cross below is a bearish signal. - - **Centerline Crossover:** A crossover of the signal line above the 50 level indicates that bulls are in control. A crossover below 50 indicates bears are in control. -- **Oscillator (Histogram):** The histogram provides a clear visual of the relationship between the RSI and its signal line, highlighting the acceleration and deceleration of momentum. -- **Caution:** The smoothing process introduces lag. The signal line will always react slower than the raw RSI. This filtering is its main advantage, but traders should be aware of the delay. diff --git a/Indicators/MyIndicators/RSIMa.mq5 b/Indicators/MyIndicators/RSIMa.mq5 deleted file mode 100644 index 8e21e27..0000000 --- a/Indicators/MyIndicators/RSIMa.mq5 +++ /dev/null @@ -1,177 +0,0 @@ -//+------------------------------------------------------------------+ -//| RSIMA.mq5 | -//| Copyright 2025, xxxxxxxx | -//| | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property link "" -#property version "2.00" // Refactored for full recalculation and stability -#property description "Oscillator based on the Moving Average of a standard RSI." - -// --- Standard Includes --- -#include - -//--- Indicator Window and Level Properties --- -#property indicator_separate_window -#property indicator_level1 30.0 -#property indicator_level2 50.0 -#property indicator_level3 70.0 - -//--- Buffers and Plots --- -#property indicator_buffers 2 -#property indicator_plots 2 - -//--- Plot 1: RSIMA (Smoothed RSI) -#property indicator_label1 "RSIMA" -#property indicator_type1 DRAW_LINE -#property indicator_color1 clrDodgerBlue -#property indicator_style1 STYLE_SOLID -#property indicator_width1 1 - -//--- Plot 2: RSI (Raw RSI) -#property indicator_label2 "RSI" -#property indicator_type2 DRAW_LINE -#property indicator_color2 clrGreen -#property indicator_style2 STYLE_SOLID -#property indicator_width2 1 - -//--- Input Parameters --- -input int InpPeriodRSI = 14; // Period for RSI -input ENUM_APPLIED_PRICE InpAppliedPrice = PRICE_CLOSE; // Applied price for RSI -input int InpPeriodMA = 14; // Period for Moving Average -input ENUM_MA_METHOD InpMethod = MODE_SMA; // Method for Moving Average - -//--- Indicator Buffers --- -double BufferRSIMA[]; // Buffer for the smoothed RSI line (Plot 1) -double BufferRawRSI[]; // Buffer for the raw RSI values (Plot 2) - -//--- Global Variables --- -int g_ExtPeriodRSI; -int g_ExtPeriodMA; -int g_handle_rsi; // Handle for the standard RSI indicator - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { -//--- Validate and store input periods - g_ExtPeriodRSI = (InpPeriodRSI < 1) ? 1 : InpPeriodRSI; - g_ExtPeriodMA = (InpPeriodMA < 1) ? 1 : InpPeriodMA; - -//--- Map the buffers - SetIndexBuffer(0, BufferRSIMA, INDICATOR_DATA); - SetIndexBuffer(1, BufferRawRSI, INDICATOR_DATA); - -//--- Set buffers as non-timeseries for stable calculation - ArraySetAsSeries(BufferRSIMA, false); - ArraySetAsSeries(BufferRawRSI, false); - -//--- Set indicator display properties - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("RSIMA(%d, %d)", g_ExtPeriodRSI, g_ExtPeriodMA)); - IndicatorSetInteger(INDICATOR_DIGITS, 2); - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, g_ExtPeriodRSI + g_ExtPeriodMA - 1); - PlotIndexSetString(0, PLOT_LABEL, "RSIMA"); - PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, g_ExtPeriodRSI - 1); - PlotIndexSetString(1, PLOT_LABEL, "RSI"); - -//--- Create a handle to the standard iRSI indicator - g_handle_rsi = iRSI(_Symbol, _Period, g_ExtPeriodRSI, InpAppliedPrice); - if(g_handle_rsi == INVALID_HANDLE) - { - PrintFormat("Failed to create iRSI handle. Error %d", GetLastError()); - return(INIT_FAILED); - } - - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { -//--- Release the indicator handle - IndicatorRelease(g_handle_rsi); - } - -//+------------------------------------------------------------------+ -//| 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[]) - { -//--- Check if there is enough data for the calculation - int start_pos = g_ExtPeriodRSI + g_ExtPeriodMA - 1; - if(rates_total <= start_pos) - return(0); - -//--- STEP 1: Get all available RSI values into our buffer - if(CopyBuffer(g_handle_rsi, 0, 0, rates_total, BufferRawRSI) < rates_total) - { - Print("Error copying RSI buffer data."); - } - -//--- STEP 2: Calculate the Moving Average on the RSI buffer - int ma_start_pos = g_ExtPeriodRSI + g_ExtPeriodMA - 1; // Correct start pos - for(int i = ma_start_pos; i < rates_total; i++) - { - // --- FIX: Full, robust switch block for all MA types --- - switch(InpMethod) - { - case MODE_EMA: - case MODE_SMMA: - if(i == ma_start_pos) - { - double sum=0; - for(int j=0; j0) - BufferRSIMA[i]=lwma_sum/weight_sum; - } - break; - default: // MODE_SMA - { - double sum=0; - for(int j=0; j - -//--- 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 2 // RSI and its MA -#property indicator_plots 2 - -//--- Plot 1: RSI MA line (smoothed) -#property indicator_label1 "HA_RSIMA" -#property indicator_type1 DRAW_LINE -#property indicator_color1 clrRed -#property indicator_style1 STYLE_DOT -#property indicator_width1 1 - -//--- Plot 2: RSI line (raw) -#property indicator_label2 "HA_RSI" -#property indicator_type2 DRAW_LINE -#property indicator_color2 clrDodgerBlue -#property indicator_style2 STYLE_SOLID -#property indicator_width2 1 - -//--- Input Parameters --- -input int InpPeriodRSI = 14; -input group "Signal Line Settings" -input int InpPeriodMA = 14; -input ENUM_MA_METHOD InpMethodMA = MODE_SMA; - -//--- Indicator Buffers --- -double BufferHARSI_MA[]; -double BufferHARSI[]; - -//--- Global Objects and Variables --- -int g_ExtPeriodRSI, g_ExtPeriodMA; -CHeikinAshi_RSI_Calculator *g_ha_rsi_calculator; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - g_ExtPeriodRSI = (InpPeriodRSI < 1) ? 1 : InpPeriodRSI; - g_ExtPeriodMA = (InpPeriodMA < 1) ? 1 : InpPeriodMA; - - SetIndexBuffer(0, BufferHARSI_MA, INDICATOR_DATA); - SetIndexBuffer(1, BufferHARSI, INDICATOR_DATA); - - ArraySetAsSeries(BufferHARSI_MA, false); - ArraySetAsSeries(BufferHARSI, false); - - IndicatorSetInteger(INDICATOR_DIGITS, 2); - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, g_ExtPeriodRSI + g_ExtPeriodMA - 1); - PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, g_ExtPeriodRSI); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA_RSI(%d, %d)", g_ExtPeriodRSI, g_ExtPeriodMA)); - - g_ha_rsi_calculator = new CHeikinAshi_RSI_Calculator(); - if(CheckPointer(g_ha_rsi_calculator) == POINTER_INVALID) - { - Print("Error creating CHeikinAshi_RSI_Calculator object"); - return(INIT_FAILED); - } - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { - if(CheckPointer(g_ha_rsi_calculator) != POINTER_INVALID) - { - delete g_ha_rsi_calculator; - g_ha_rsi_calculator = NULL; - } - } - -//+------------------------------------------------------------------+ -//| RSI on Heikin 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[]) - { - int start_pos = g_ExtPeriodRSI + g_ExtPeriodMA; - if(rates_total <= start_pos) - return(0); - -//--- STEP 1: Calculate Heikin Ashi RSI values using our toolkit - if(!g_ha_rsi_calculator.Calculate(rates_total, g_ExtPeriodRSI, open, high, low, close, BufferHARSI)) - { - Print("Heikin Ashi RSI calculation failed."); - return(0); - } - -//--- STEP 2: Calculate the Signal Line (MA of HA RSI) - int ma_start_pos = g_ExtPeriodRSI + g_ExtPeriodMA - 1; - for(int i = ma_start_pos; i < rates_total; i++) - { - switch(InpMethodMA) - { - case MODE_EMA: - case MODE_SMMA: - if(i == ma_start_pos) - { - double sum=0; - for(int j=0; j0) - BufferHARSI_MA[i]=lwma_sum/weight_sum; - } - break; - default: // MODE_SMA - { - double sum=0; - for(int j=0; j - -//--- Indicator Window and Plot Properties --- -#property indicator_separate_window -#property indicator_buffers 1 -#property indicator_plots 1 -#property indicator_type1 DRAW_HISTOGRAM -#property indicator_color1 clrSilver -#property indicator_width1 1 -#property indicator_label1 "HA_RSI_Osc" -#property indicator_level1 0.0 -#property indicator_levelstyle STYLE_DOT - -//--- Input Parameters --- -input int InpPeriodRSI = 14; -input group "Signal Line Settings" -input int InpPeriodMA = 14; -input ENUM_MA_METHOD InpMethodMA = MODE_SMA; - -//--- Indicator Buffers --- -double BufferOscillator[]; - -//--- Global Objects and Variables --- -int g_ExtPeriodRSI, g_ExtPeriodMA; -CHeikinAshi_RSI_Calculator *g_ha_rsi_calculator; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - g_ExtPeriodRSI = (InpPeriodRSI < 1) ? 1 : InpPeriodRSI; - g_ExtPeriodMA = (InpPeriodMA < 1) ? 1 : InpPeriodMA; - - SetIndexBuffer(0, BufferOscillator, INDICATOR_DATA); - ArraySetAsSeries(BufferOscillator, false); - - int draw_begin = g_ExtPeriodRSI + g_ExtPeriodMA - 1; - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, draw_begin); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA_RSI_Osc(%d,%d)", g_ExtPeriodRSI, g_ExtPeriodMA)); - IndicatorSetInteger(INDICATOR_DIGITS, 2); - - g_ha_rsi_calculator = new CHeikinAshi_RSI_Calculator(); - if(CheckPointer(g_ha_rsi_calculator) == POINTER_INVALID) - { - Print("Error creating CHeikinAshi_RSI_Calculator object"); - return(INIT_FAILED); - } - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { - if(CheckPointer(g_ha_rsi_calculator) != POINTER_INVALID) - { - delete g_ha_rsi_calculator; - g_ha_rsi_calculator = NULL; - } - } - -//+------------------------------------------------------------------+ -//| RSI Oscillator on Heikin 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[]) - { - int start_pos = g_ExtPeriodRSI + g_ExtPeriodMA - 1; - if(rates_total <= start_pos) - return(0); - -//--- Internal Buffers for calculation --- - double buffer_rsi[], buffer_signal[]; - ArrayResize(buffer_rsi, rates_total); - ArrayResize(buffer_signal, rates_total); - -//--- STEP 1: Calculate Heikin Ashi RSI internally - if(!g_ha_rsi_calculator.Calculate(rates_total, g_ExtPeriodRSI, open, high, low, close, buffer_rsi)) - { - Print("Heikin Ashi RSI calculation failed."); - return(0); - } - -//--- STEP 2: Calculate the Signal Line (MA of HA RSI) - for(int i = start_pos; i < rates_total; i++) - { - switch(InpMethodMA) - { - case MODE_EMA: - case MODE_SMMA: - if(i == start_pos) - { - double sum=0; - for(int j=0; j0) - buffer_signal[i]=lwma_sum/weight_sum; - } - break; - default: // MODE_SMA - { - double sum=0; - for(int j=0; j ema2_start) // Recursive - { - BufferEmaEma_Relative[i] = BufferEma_Relative[i] * pr_d + BufferEmaEma_Relative[i-1] * (1.0 - pr_d); - BufferEmaEma_Range[i] = BufferEma_Range[i] * pr_d + BufferEmaEma_Range[i-1] * (1.0 - pr_d); - } - - // --- Final SMI Value --- - if(i >= ema2_start) - { - if(BufferEmaEma_Range[i] != 0) - BufferSMI[i] = 100 * (BufferEmaEma_Relative[i] / (BufferEmaEma_Range[i] / 2.0)); - else - BufferSMI[i] = 0; - } - - // --- Signal Line --- - if(i == signal_start) // Initialization with manual SMA - { - double sum_smi=0; - for(int j=0; j signal_start) // Recursive - { - BufferSignal[i] = BufferSMI[i] * pr_ema + BufferSignal[i-1] * (1.0 - pr_ema); - } - } - - 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/SMI_HeikinAshi.mq5 b/Indicators/MyIndicators/SMI_HeikinAshi.mq5 deleted file mode 100644 index f65684d..0000000 --- a/Indicators/MyIndicators/SMI_HeikinAshi.mq5 +++ /dev/null @@ -1,268 +0,0 @@ -//+------------------------------------------------------------------+ -//| SMI_HeikinAshi.mq5 | -//| Copyright 2025, xxxxxxxx | -//| | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property link "" -#property version "2.00" // Refactored for full recalculation and stability -#property description "Stochastic Momentum Index (SMI) on Heikin 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 BufferHighestLowestRange[]; -double BufferRelativeRange[]; -double BufferEma_Relative[]; -double BufferEma_Range[]; -double BufferEmaEma_Relative[]; -double BufferEmaEma_Range[]; - -//--- Intermediate Heikin Ashi Buffers --- -double ExtHaOpenBuffer[]; -double ExtHaHighBuffer[]; -double ExtHaLowBuffer[]; -double ExtHaCloseBuffer[]; - -//--- Global Objects and Variables --- -int g_ExtLengthK, g_ExtLengthD, g_ExtLengthEMA; -CHeikinAshi_Calculator *g_ha_calculator; // Pointer to our Heikin 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. | -//+------------------------------------------------------------------+ -int OnInit() - { -//--- Validate and store inputs - g_ExtLengthK = (InpLengthK < 1) ? 1 : InpLengthK; - g_ExtLengthD = (InpLengthD < 1) ? 1 : InpLengthD; - g_ExtLengthEMA = (InpLengthEMA < 1) ? 1 : InpLengthEMA; - -//--- Map the buffers - SetIndexBuffer(0, BufferSMI, INDICATOR_DATA); - SetIndexBuffer(1, BufferSignal, INDICATOR_DATA); - SetIndexBuffer(2, BufferHighestLowestRange, INDICATOR_CALCULATIONS); - SetIndexBuffer(3, BufferRelativeRange, INDICATOR_CALCULATIONS); - SetIndexBuffer(4, BufferEma_Relative, INDICATOR_CALCULATIONS); - SetIndexBuffer(5, BufferEma_Range, INDICATOR_CALCULATIONS); - SetIndexBuffer(6, BufferEmaEma_Relative, INDICATOR_CALCULATIONS); - SetIndexBuffer(7, BufferEmaEma_Range, INDICATOR_CALCULATIONS); - -//--- Set all buffers to non-timeseries - ArraySetAsSeries(BufferSMI, false); - ArraySetAsSeries(BufferSignal, false); - ArraySetAsSeries(BufferHighestLowestRange, false); - ArraySetAsSeries(BufferRelativeRange, false); - ArraySetAsSeries(BufferEma_Relative, false); - ArraySetAsSeries(BufferEma_Range, false); - ArraySetAsSeries(BufferEmaEma_Relative, false); - ArraySetAsSeries(BufferEmaEma_Range, false); - -//--- Set indicator properties - IndicatorSetInteger(INDICATOR_DIGITS, 2); - int smi_draw_begin = g_ExtLengthK + g_ExtLengthD - 2; - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, smi_draw_begin); - PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, smi_draw_begin + g_ExtLengthEMA - 1); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("HA_SMI(%d,%d,%d)", g_ExtLengthK, g_ExtLengthD, g_ExtLengthEMA)); - -//--- Create the calculator instance - g_ha_calculator = new CHeikinAshi_Calculator(); - if(CheckPointer(g_ha_calculator) == POINTER_INVALID) - { - Print("Error creating CHeikinAshi_Calculator object"); - return(INIT_FAILED); - } - - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { -//--- Free the calculator object - if(CheckPointer(g_ha_calculator) != POINTER_INVALID) - { - delete g_ha_calculator; - g_ha_calculator = NULL; - } - } - -//+------------------------------------------------------------------+ -//| 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[]) - { - int start_pos = g_ExtLengthK + g_ExtLengthD + g_ExtLengthEMA - 2; - if(rates_total <= start_pos) - return(0); - -//--- Resize intermediate buffers - ArrayResize(ExtHaOpenBuffer, rates_total); - ArrayResize(ExtHaHighBuffer, rates_total); - ArrayResize(ExtHaLowBuffer, rates_total); - ArrayResize(ExtHaCloseBuffer, rates_total); - -//--- STEP 1: Calculate Heikin Ashi bars - g_ha_calculator.Calculate(rates_total, open, high, low, close, - ExtHaOpenBuffer, ExtHaHighBuffer, ExtHaLowBuffer, ExtHaCloseBuffer); - -//--- STEP 2: Calculate Highest, Lowest, and Ranges - for(int i = g_ExtLengthK - 1; i < rates_total; i++) - { - double highest_high = Highest(ExtHaHighBuffer, g_ExtLengthK, i); - double lowest_low = Lowest(ExtHaLowBuffer, g_ExtLengthK, i); - BufferHighestLowestRange[i] = highest_high - lowest_low; - BufferRelativeRange[i] = ExtHaCloseBuffer[i] - (highest_high + lowest_low) / 2.0; - } - -//--- STEP 3-7: Calculate all smoothed values and final SMI in a single loop - double pr_d = 2.0 / (g_ExtLengthD + 1.0); - double pr_ema = 2.0 / (g_ExtLengthEMA + 1.0); - - int ema1_start = g_ExtLengthK + g_ExtLengthD - 2; - int ema2_start = ema1_start + g_ExtLengthD - 1; - int signal_start = ema2_start + g_ExtLengthEMA - 1; - - for(int i = g_ExtLengthK - 1; i < rates_total; i++) - { - // --- 1st EMA Smoothing --- - if(i == g_ExtLengthK - 1) // Initialization - { - BufferEma_Relative[i] = BufferRelativeRange[i]; - BufferEma_Range[i] = BufferHighestLowestRange[i]; - } - else // Recursive - { - BufferEma_Relative[i] = BufferRelativeRange[i] * pr_d + BufferEma_Relative[i-1] * (1.0 - pr_d); - BufferEma_Range[i] = BufferHighestLowestRange[i] * pr_d + BufferEma_Range[i-1] * (1.0 - pr_d); - } - - // --- 2nd EMA Smoothing --- - if(i == ema1_start) // Initialization with manual SMA - { - double sum_rel=0, sum_ran=0; - for(int j=0; j ema1_start) // Recursive - { - BufferEmaEma_Relative[i] = BufferEma_Relative[i] * pr_d + BufferEmaEma_Relative[i-1] * (1.0 - pr_d); - BufferEmaEma_Range[i] = BufferEma_Range[i] * pr_d + BufferEmaEma_Range[i-1] * (1.0 - pr_d); - } - - // --- Final SMI Value --- - if(i >= ema1_start) - { - if(BufferEmaEma_Range[i] != 0) - BufferSMI[i] = 100 * (BufferEmaEma_Relative[i] / (BufferEmaEma_Range[i] / 2.0)); - else - BufferSMI[i] = 0; - } - - // --- Signal Line --- - if(i == signal_start) // Initialization with manual SMA - { - double sum_smi=0; - for(int j=0; j signal_start) // Recursive - { - BufferSignal[i] = BufferSMI[i] * pr_ema + BufferSignal[i-1] * (1.0 - pr_ema); - } - } - - 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/Sine_WMA.md b/Indicators/MyIndicators/Sine_WMA.md deleted file mode 100644 index feea971..0000000 --- a/Indicators/MyIndicators/Sine_WMA.md +++ /dev/null @@ -1,65 +0,0 @@ -# Sine Weighted Moving Average (Sine WMA) - -## 1. Summary (Introduction) - -The Sine Weighted Moving Average (Sine WMA) is a specialized type of weighted moving average that uses a sine wave function to assign weights to price data. It was developed as an advanced smoothing filter, designed to reduce lag and provide a cleaner representation of the market's underlying trend. - -Unlike traditional moving averages that are inherently lagging, the Sine WMA is a **symmetrical, zero-lag filter**. It achieves this by assigning the heaviest weights to the price data in the middle of the lookback period, with weights tapering off towards the beginning and end of the period, mirroring the shape of a sine wave. - -The result is an exceptionally smooth line that acts as the "center of gravity" for the price action. It is not a trend-following tool in the classic sense but rather a superior smoothing mechanism for identifying the true equilibrium price and filtering out market noise. - -## 2. Mathematical Foundations and Calculation Logic - -The Sine WMA calculates a weighted average where the weights are derived from a sine function, creating a smooth, bell-shaped weighting curve. - -### Required Components - -* **Period (N):** The lookback period for the moving average. -* **Source Price:** The price series used for calculation (e.g., `PRICE_CLOSE`). - -### Calculation Steps (Algorithm) - -1. **Generate Sine Weights:** For a given period `N`, the weight for each bar `i` (where `i` ranges from 0 to N-1) is calculated using the sine function. - * $Weight_i = \sin\left(\frac{\pi \cdot (i+1)}{N+1}\right)$ - -2. **Calculate the Weighted Sum:** For each bar `t`, multiply the last `N` prices by the corresponding sine-based weights. - * $\text{Weighted Sum}_t = \sum_{i=0}^{N-1} (\text{Price}_{t-i} \cdot Weight_i)$ - -3. **Calculate the Sum of Weights:** Sum all the generated sine weights. - * $\text{Sum of Weights} = \sum_{i=0}^{N-1} Weight_i$ - -4. **Calculate the Final WMA Value:** Divide the weighted sum of prices by the sum of the weights. - * $\text{Sine WMA}_t = \frac{\text{Weighted Sum}_t}{\text{Sum of Weights}}$ - -This process results in a symmetrically weighted average that is centered on the data. - -## 3. MQL5 Implementation Details - -Our MQL5 implementation is a clean and robust indicator that accurately reflects the mathematical definition of a symmetrical, centered filter. - -* **Modular, Reusable Calculation Engine (`Sine_WMA_Calculator.mqh`):** The entire calculation logic for both standard and Heikin Ashi versions is encapsulated within a single, powerful include file. This file contains a base `CSineWMACalculator` class and an inherited `CSineWMACalculator_HA` child class, eliminating code duplication and ensuring both versions are always in sync. - -* **Efficient Weight Generation:** The sine-based weights are calculated only once during the indicator's initialization in the `Init()` method of the calculator class. The weights and their sum are stored in internal class members for efficient reuse. - -* **Stability via Full Recalculation:** In line with our core principles, the indicator employs a "brute-force" full recalculation within the `OnCalculate` function. This is the most reliable method to ensure stability and prevent any potential glitches. - -* **Correct Symmetrical Application:** The `Calculate` method applies the pre-calculated symmetrical weights directly to the price data. The weights are **not reversed**. This correctly implements the smoothing, centered nature of the filter. The inherent lag of `(Period-1)/2` bars is a mathematical property of the filter, not an implementation error. - -* **Heikin Ashi Variant (`Sine_WMA_HeikinAshi.mq5`):** - * **As an experiment, a Heikin Ashi version of this indicator was also developed. However, testing revealed that the practical benefit is minimal.** - * **The "Double Smoothing" Effect:** The Heikin Ashi transformation is, in itself, a powerful smoothing algorithm. Applying a second, strong smoothing filter (the Sine WMA) to an already smoothed data series (HA Close) results in an extremely smooth line, but one that shows negligible difference from the standard version while potentially increasing lag. - * **Conclusion:** For symmetrical, smoothing-type filters like the Sine WMA, the standard version is recommended as it already provides excellent noise reduction. The Heikin Ashi variant remains in the toolkit as a technical demonstration of our modular calculation engine. - -## 4. Parameters - -* **Period (`InpPeriod`):** The lookback period for the moving average. A longer period results in a smoother line that is less sensitive to short-term price fluctuations. Default is `21`. -* **Source Price (`InpSourcePrice`):** The price data used for the calculation. **Note: This parameter is ignored by the Heikin Ashi version**, which always uses the HA Close price. Default is `PRICE_CLOSE`. - -## 5. Usage and Interpretation - -The Sine WMA should be interpreted as a **smoothing filter and a "mean" or "center of gravity" line**, not as a traditional trend-following moving average. - -* **Noise Reduction and Trend Clarity:** The primary use of the Sine WMA is to filter out market noise and provide a much clearer picture of the underlying price movement. -* **Mean Reversion Signals:** The line acts as a "magnet" for the price. When the price moves significantly away from the Sine WMA, it can be considered over-extended, increasing the probability of a reversion back towards the line. -* **Confirmation of Trend Direction:** The slope of the Sine WMA provides a very stable, albeit lagging, confirmation of the main trend direction. A change in the slope's direction is a significant event. -* **Caution:** Due to its inherent nature as a centered, smoothing filter, the Sine WMA will always lag the price. It should **not** be used for fast crossover signals. Its strength lies in its smoothness and its ability to define the market's equilibrium point. diff --git a/Indicators/MyIndicators/Sine_WMA.mq5 b/Indicators/MyIndicators/Sine_WMA.mq5 deleted file mode 100644 index 80a4513..0000000 --- a/Indicators/MyIndicators/Sine_WMA.mq5 +++ /dev/null @@ -1,185 +0,0 @@ -//+------------------------------------------------------------------+ -//| Sine_WMA.mq5 | -//| Copyright 2025, xxxxxxxx| -//| | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2025, xxxxxxxx" -#property version "1.01" -#property description "Sine Weighted Moving Average. A zero-lag smoothing filter." - -#property indicator_chart_window -#property indicator_buffers 1 -#property indicator_plots 1 - -//--- Plot 1: Sine WMA Line -#property indicator_label1 "Sine WMA" -#property indicator_type1 DRAW_LINE -#property indicator_color1 clrAqua -#property indicator_style1 STYLE_SOLID -#property indicator_width1 2 - -//--- Input Parameters --- -input int InpPeriod = 21; -input ENUM_APPLIED_PRICE InpSourcePrice = PRICE_CLOSE; - -//--- Indicator Buffers --- -double BufferWMA[]; -double BufferPrice[]; - -//+------------------------------------------------------------------+ -//| CLASS: CSineWMACalculator | -//| Encapsulates the logic for Sine weighting. | -//+------------------------------------------------------------------+ -class CSineWMACalculator - { -private: - int m_period; - double m_weights[]; - double m_weight_sum; - -public: - CSineWMACalculator(void); - ~CSineWMACalculator(void) {}; - - bool Init(int period); - void Calculate(int rates_total, const double &price_src[], double &wma_out[]); - }; - -//+------------------------------------------------------------------+ -//| CSineWMACalculator: Constructor | -//+------------------------------------------------------------------+ -CSineWMACalculator::CSineWMACalculator(void) : m_period(0), m_weight_sum(0) - { - } - -//+------------------------------------------------------------------+ -//| CSineWMACalculator: Initialization and Weight Generation | -//+------------------------------------------------------------------+ -bool CSineWMACalculator::Init(int period) - { - m_period = (period < 2) ? 2 : period; - - ArrayResize(m_weights, m_period); - m_weight_sum = 0; - - for(int i = 0; i < m_period; i++) - { - m_weights[i] = MathSin(M_PI * (i + 1.0) / (m_period + 1.0)); - m_weight_sum += m_weights[i]; - } - - return (m_weight_sum != 0); - } - -//+------------------------------------------------------------------+ -//| CSineWMACalculator: Main Calculation Method (No phase shift) | -//+------------------------------------------------------------------+ -void CSineWMACalculator::Calculate(int rates_total, const double &price_src[], double &wma_out[]) - { - if(rates_total < m_period) - return; - - for(int i = m_period - 1; i < rates_total; i++) - { - double weighted_sum = 0; - for(int j = 0; j < m_period; j++) - { - //--- Symmetrical weighting, use weights as generated - weighted_sum += price_src[i - j] * m_weights[j]; - } - - //--- No displacement, result is plotted at the current bar - wma_out[i] = weighted_sum / m_weight_sum; - } - } - -//--- Global calculator object --- -CSineWMACalculator *g_calculator; - -//--- Forward declaration -int PriceSeries(ENUM_APPLIED_PRICE,int,const double&[],const double&[],const double&[],const double&[],double&[]); - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - SetIndexBuffer(0, BufferWMA, INDICATOR_DATA); - ArraySetAsSeries(BufferWMA, false); - - g_calculator = new CSineWMACalculator(); - if(CheckPointer(g_calculator) == POINTER_INVALID || !g_calculator.Init(InpPeriod)) - { - Print("Failed to initialize Sine WMA Calculator."); - return(INIT_FAILED); - } - - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, InpPeriod - 1); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("SineWMA(%d)", InpPeriod)); - - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { - if(CheckPointer(g_calculator) != POINTER_INVALID) - delete g_calculator; - } - -//+------------------------------------------------------------------+ -//| Custom indicator iteration function. | -//+------------------------------------------------------------------+ -int OnCalculate(const int rates_total, const int, const datetime&[], const double &open[], const double &high[], const double &low[], const double &close[], const long&[], const long&[], const int&[]) - { - ArrayResize(BufferPrice, rates_total); - if(PriceSeries(InpSourcePrice, rates_total, open, high, low, close, BufferPrice) <= 0) - return 0; - - if(CheckPointer(g_calculator) != POINTER_INVALID) - { - g_calculator.Calculate(rates_total, BufferPrice, BufferWMA); - } - return(rates_total); - } - -//+------------------------------------------------------------------+ -//| Helper function to get the selected price series. | -//+------------------------------------------------------------------+ -int PriceSeries(ENUM_APPLIED_PRICE type, int rates_total, const double &open[], const double &high[], const double &low[], const double &close[], double &dest_buffer[]) - { - switch(type) - { - case PRICE_CLOSE: - ArrayCopy(dest_buffer, close, 0, 0, rates_total); - break; - case PRICE_OPEN: - ArrayCopy(dest_buffer, open, 0, 0, rates_total); - break; - case PRICE_HIGH: - ArrayCopy(dest_buffer, high, 0, 0, rates_total); - break; - case PRICE_LOW: - ArrayCopy(dest_buffer, low, 0, 0, rates_total); - break; - case PRICE_MEDIAN: - for(int i=0; i - -//--- Plot 1: Sine WMA Line -#property indicator_label1 "Sine WMA (HA)" -#property indicator_type1 DRAW_LINE -#property indicator_color1 clrAqua -#property indicator_style1 STYLE_SOLID -#property indicator_width1 2 - -//--- Input Parameters --- -input int InpPeriod = 21; - -//--- Indicator Buffers --- -double BufferWMA[]; - -//--- Global calculator object --- -CSineWMACalculator_HA *g_calculator; - -//+------------------------------------------------------------------+ -//| Custom indicator initialization function. | -//+------------------------------------------------------------------+ -int OnInit() - { - SetIndexBuffer(0, BufferWMA, INDICATOR_DATA); - ArraySetAsSeries(BufferWMA, false); - - g_calculator = new CSineWMACalculator_HA(); - if(CheckPointer(g_calculator) == POINTER_INVALID || !g_calculator.Init(InpPeriod)) - { - Print("Failed to initialize Sine WMA HA Calculator."); - return(INIT_FAILED); - } - - PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, InpPeriod - 1); - IndicatorSetString(INDICATOR_SHORTNAME, StringFormat("SineWMA_HA(%d)", InpPeriod)); - - return(INIT_SUCCEEDED); - } - -//+------------------------------------------------------------------+ -//| Custom indicator deinitialization function. | -//+------------------------------------------------------------------+ -void OnDeinit(const int reason) - { - if(CheckPointer(g_calculator) != POINTER_INVALID) - delete g_calculator; - } - -//+------------------------------------------------------------------+ -//| Custom indicator iteration function. | -//+------------------------------------------------------------------+ -int OnCalculate(const int rates_total, const int, const datetime&[], const double &open[], const double &high[], const double &low[], const double &close[], const long&[], const long&[], const int&[]) - { - if(CheckPointer(g_calculator) != POINTER_INVALID) - { - //--- The price_type parameter is ignored by the HA calculator, so we can pass a default - g_calculator.Calculate(rates_total, PRICE_CLOSE, open, high, low, close, BufferWMA); - } - return(rates_total); - } -//+------------------------------------------------------------------+ -//+------------------------------------------------------------------+