From 94bc679290a288530072d0160b43d11f29b801b4 Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Wed, 17 Sep 2025 15:23:00 +0330 Subject: [PATCH] last works ... --- Documents/Indicators/x-saherelm.x121.xzg.mq5 | 757 ++++++ Documents/Indicators/x-saherelm.xzg.mq5 | 1097 +++++++++ Experts/x-saherelm.xfima.backtester.ea.mq5 | 27 +- Indicators/x-saherelm.xfima.mq5 | 2074 +++++++++++++++++ .../x-saherelm.common.extensions.lib.mq5 | 69 + Libraries/x-saherelm.x-enums.lib.mq5 | 4 + 6 files changed, 4026 insertions(+), 2 deletions(-) create mode 100644 Documents/Indicators/x-saherelm.x121.xzg.mq5 create mode 100644 Documents/Indicators/x-saherelm.xzg.mq5 create mode 100644 Indicators/x-saherelm.xfima.mq5 diff --git a/Documents/Indicators/x-saherelm.x121.xzg.mq5 b/Documents/Indicators/x-saherelm.x121.xzg.mq5 new file mode 100644 index 00000000..d7cde079 --- /dev/null +++ b/Documents/Indicators/x-saherelm.x121.xzg.mq5 @@ -0,0 +1,757 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// --------------------------------------------- +// Name: X121_XZG +// Description: Zogzag Implementation ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm X121_XZG Indicator" +#property strict + +// +#define ShortName "X121_XZG" + +// +// DEFINITIONS ... +enum ENUM_X_ZG_SEARCH_MODE +{ + X_ZG_SEARCH_EXTREMUM = 0, // searching for the first extremum + X_ZG_SEARCH_PEAK = 1, // searching for the next ZigZag peak + X_ZG_SEARCH_VALE = -1 // searching for the next ZigZag vale +}; + +// +// How to Calculate Up and Down Price ... +enum ENUM_X_ZG_PRICE_MODE +{ + // + X_ZG_PRICE_HIGH_LOW_MODE = 1, + X_ZG_PRICE_OPEN_CLOSE_MODE = 2, +}; + +// +// INPUT ... + +// +input int depth = 12; // Depth +input int deviation = 5; // Deviation +input int backStep = 3; // Back Step +input ENUM_X_ZG_PRICE_MODE mode = X_ZG_PRICE_HIGH_LOW_MODE; // Mode + +// +// BUFFERS ... + +// +#property indicator_chart_window + +// +#property indicator_buffers 5 +#property indicator_plots 3 + +// +// ZigZag ... + +// +#define mainBufferIndex 0 +#define mainBufferPlotIndex 0 +double mainBuffer[]; + +// +#property indicator_label1 "X121_XZG Main" +#property indicator_type1 DRAW_SECTION +#property indicator_color1 clrYellow +#property indicator_width1 2 + +// +// Highs ... + +// +// ZigZag Pointer or Line Indicator ... +#define arrowBufferIndex 1 +#define arrowBufferPlotIndex 1 +double arrowBuffer[]; + +// +#define arrowColorBufferIndex 2 +double arrowColorBuffer[]; + +// +#property indicator_label2 "X121_XZG PV" +#property indicator_type2 DRAW_COLOR_ARROW +#property indicator_color2 clrAqua, clrMagenta +#property indicator_width2 1 + +// +#define highsBufferIndex 3 +double highsBuffer[]; + +// +// Lows ... + +// +#define lowsBufferIndex 4 +double lowsBuffer[]; + +// +// VARIABLES ... + +// +int mRecalc = 3; // Number of last extremes for recalculation + +// +// EVENT Handlers ... + +// +// Initialization ... +int OnInit() +{ + // + // Validate Inputs ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // logTag = ShortName; + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +void OnDeinit(const int reason) +{ + // + // REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + // REASON_REMOVE 1 Program removed from a chart + // REASON_RECOMPILE 2 Program recompiled + // REASON_CHARTCHANGE 3 A symbol or a chart period is changed + // REASON_CHARTCLOSE 4 Chart closed + // REASON_PARAMETERS 5 Inputs changed by a user + // REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + // REASON_TEMPLATE 7 Another chart template applied + // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + // REASON_CLOSE 9 Terminal closed +} + +// +// Calculating what we want ... +int OnCalculate( + // + // total Candles on chart ... + const int rates_total, + // + // total calculated Candles on charts ... + const int prev_calculated, + // + // history of Candles Open Time ... + const datetime &time[], + // + // history of Candles Open Price ... + const double &open[], + // + // history of Candles High Price ... + const double &high[], + // + // history of Candles Low Price ... + const double &low[], + // + // history of Candles Close Price ... + const double &close[], + // + // history of Tick Volumes on Candle ... + const long &tick_volume[], + // + // history of Trade Volumes ... + const long &volume[], + // + // history of Candles Spread Price ... + const int &spread[] // +) +{ + // + double mZGHigh[]; + double mZGLow[]; + if (mode == X_ZG_PRICE_OPEN_CLOSE_MODE) + { + // + ArrayCopy( + mZGHigh, + open + // + ); + + // + ArrayCopy( + mZGLow, + close + // + ); + } + else + { + // + ArrayCopy( + mZGHigh, + high + // + ); + + // + ArrayCopy( + mZGLow, + low + // + ); + } + + // + int zigZagResult = CalcukateZigZag( + prev_calculated, + rates_total, + mZGHigh, + mZGLow + // + ); + + // + if (zigZagResult != rates_total) + { + return zigZagResult; + } + + // + return rates_total; +} + +// +// CUSTOM Functions ... + +// +// Validate Input Args for Initialization ... +bool ValidateInputs() +{ + // + bool result = false; + + // + result = + // + depth > 0 && + deviation > 0 && + backStep > 0 + // + ; + + // + return result; +} + +// +// Define Indexes and Styles ... +void DefineBuffers() +{ + // + // Main ... + + // + SetIndexBuffer(mainBufferIndex, mainBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(mainBufferPlotIndex, PLOT_SHOW_DATA, true); + PlotIndexSetInteger(mainBufferPlotIndex, PLOT_DRAW_BEGIN, 0); + PlotIndexSetDouble(mainBufferPlotIndex, PLOT_EMPTY_VALUE, 0); + + // + // Arrow ... + + // + SetIndexBuffer(arrowBufferIndex, arrowBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(arrowBufferPlotIndex, PLOT_SHOW_DATA, true); + PlotIndexSetInteger(arrowBufferPlotIndex, PLOT_DRAW_BEGIN, 0); + PlotIndexSetInteger(arrowBufferPlotIndex, PLOT_ARROW, 159); + PlotIndexSetInteger(arrowBufferPlotIndex, PLOT_ARROW_SHIFT, 0); + PlotIndexSetDouble(arrowBufferPlotIndex, PLOT_EMPTY_VALUE, 0); + + // + // Arrow Color ... + SetIndexBuffer(arrowColorBufferIndex, arrowColorBuffer, INDICATOR_COLOR_INDEX); + + // + // Highs ... + SetIndexBuffer(highsBufferIndex, highsBuffer, INDICATOR_CALCULATIONS); + + // + // Lows ... + SetIndexBuffer(lowsBufferIndex, lowsBuffer, INDICATOR_CALCULATIONS); +} + +// +// Set Indicator Short Name and also we can define Buffers Labels ... +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +// +// Calculating Zig Zag ... +int CalcukateZigZag( + const int prev_calculated, + const int rates_total, + double &high[], + double &low[] + // +) +{ + // + if (rates_total < 100) + { + return 0; + } + + // + // Define Variables ... + int i = 0; + + // + int start = 0; + int extreme_counter = 0; + int extreme_search = X_ZG_SEARCH_EXTREMUM; + int shift = 0; + int back = 0; + int last_high_pos = 0; + int last_low_pos = 0; + + // + double val = 0; + double res = 0; + double curlow = 0; + double curhigh = 0; + double last_high = 0; + double last_low = 0; + + // + double colorIDX = 0; + double lastZigZagValue = 0; + + // + // Initializing ... + if (prev_calculated == 0) + { + // + ArrayInitialize(mainBuffer, 0); + ArrayInitialize(highsBuffer, 0); + ArrayInitialize(lowsBuffer, 0); + + // + start = depth; + } + + // + // Already Calculated Before ... + if (prev_calculated > 0) + { + // + i = rates_total - 1; + + // + // Searching for the third X_ZG_SEARCH_EXTREMUM from the last UnComplete Bar ... + while (extreme_counter < mRecalc && i > rates_total - 100) + { + // + res = mainBuffer[i]; + if (res != 0) + { + extreme_counter++; + } + + // + i--; + } + + // + i++; + start = i; + + // + // What type of X_ZG_SEARCH_EXTREMUM we Search for ... + if (lowsBuffer[i] != 0) + { + // + curlow = lowsBuffer[i]; + extreme_search = X_ZG_SEARCH_PEAK; + } + else + { + // + curhigh = highsBuffer[i]; + extreme_search = X_ZG_SEARCH_VALE; + } + + // + // Clear Values ... + for (i = start + 1; i < rates_total && !IsStopped(); i++) + { + // + mainBuffer[i] = 0; + lowsBuffer[i] = 0; + highsBuffer[i] = 0; + } + } + + // + // Search for High and Low Extremes ... + for (shift = start; shift < rates_total && !IsStopped(); shift++) + { + // + // Low ... + val = low[Lowest(low, depth, shift)]; + if (val == last_low) + { + val = 0; + } + else + { + // + last_low = val; + + // + if ((low[shift] - val) > deviation * _Point) + { + val = 0; + } + else + { + // + for (back = 1; back <= backStep; back++) + { + // + res = lowsBuffer[shift - back]; + if ((res != 0) && (res > val)) + { + lowsBuffer[shift - back] = 0; + } + } + } + } + + // + if (low[shift] == val) + { + lowsBuffer[shift] = val; + } + else + { + lowsBuffer[shift] = 0; + } + + // + // High ... + val = high[Highest(high, depth, shift)]; + if (val == last_high) + { + val = 0; + } + else + { + // + last_high = val; + + // + if ((val - high[shift]) > deviation * _Point) + { + val = 0; + } + else + { + // + for (back = 1; back <= backStep; back++) + { + // + res = highsBuffer[shift - back]; + if ((res != 0) && (res < val)) + { + highsBuffer[shift - back] = 0; + } + } + } + } + + // + if (high[shift] == val) + { + highsBuffer[shift] = val; + } + else + { + highsBuffer[shift] = 0; + } + } + + // + // Set Last Value ... + if (extreme_search == 0) // Undefined Values ... + { + // + last_low = 0; + last_high = 0; + } + else + { + // + last_low = curlow; + last_high = curhigh; + } + + // + // Final Selection of Extreme Points for ZigZag ... + for (shift = start; shift < rates_total && !IsStopped(); shift++) + { + // + res = 0; + + // + switch (extreme_search) + { + // + case X_ZG_SEARCH_EXTREMUM: + // + if (last_low == 0 && last_high == 0) + { + // + if (highsBuffer[shift] != 0) + { + // + last_high_pos = shift; + last_high = high[shift]; + + // + extreme_search = X_ZG_SEARCH_VALE; + + // + mainBuffer[shift] = last_high; + + // + res = 1; + } + + // + if (lowsBuffer[shift] != 0) + { + // + last_low_pos = shift; + last_low = low[shift]; + + // + extreme_search = X_ZG_SEARCH_PEAK; + + // + mainBuffer[shift] = last_low; + + // + res = 1; + } + } + break; + + // + case X_ZG_SEARCH_PEAK: + // + if (lowsBuffer[shift] != 0 && lowsBuffer[shift] < last_low && highsBuffer[shift] == 0) + { + // + mainBuffer[last_low_pos] = 0; + + // + last_low_pos = shift; + last_low = lowsBuffer[shift]; + + // + mainBuffer[shift] = last_low; + + // + res = 1; + } + + // + if (highsBuffer[shift] != 0 && lowsBuffer[shift] == 0) + { + // + last_high_pos = shift; + last_high = highsBuffer[shift]; + + // + mainBuffer[shift] = last_high; + + // + extreme_search = X_ZG_SEARCH_VALE; + + // + res = 1; + } + break; + + // + case X_ZG_SEARCH_VALE: + // + if (highsBuffer[shift] != 0 && highsBuffer[shift] > last_high && lowsBuffer[shift] == 0) + { + // + mainBuffer[last_high_pos] = 0; + + // + last_high_pos = shift; + last_high = highsBuffer[shift]; + + // + mainBuffer[shift] = last_high; + } + + // + if (lowsBuffer[shift] != 0 && highsBuffer[shift] == 0) + { + // + last_low_pos = shift; + last_low = lowsBuffer[shift]; + + // + mainBuffer[shift] = last_low; + + // + extreme_search = X_ZG_SEARCH_PEAK; + } + break; + } + + // + double iZigZagForColor = lastZigZagValue; + double iZigZag = mainBuffer[shift]; + if (iZigZag == 0 && lastZigZagValue != 0) + { + arrowBuffer[shift] = lastZigZagValue; + } + else if (iZigZag != 0) + { + // + lastZigZagValue = iZigZag; + arrowBuffer[shift] = lastZigZagValue; + } + + // + colorIDX = + lastZigZagValue > iZigZagForColor + ? 0 + : lastZigZagValue < iZigZagForColor + ? 1 + : colorIDX; + arrowColorBuffer[shift] = colorIDX; + } + + // + return rates_total; +} + +// +// TOOLS ... + +// +// Search for the index of the highest bar ... +int Highest( + const double &mArray[], + const int mDepth, + const int mStart // +) +{ + // + int result = 0; + + // + if (mStart < 0) + { + return result; + } + + // + double max = mArray[mStart]; + result = mStart; + + // + // Start searching ... + for (int i = mStart - 1; i > mStart - mDepth && i >= 0; i--) + { + // + if (mArray[i] > max) + { + // + result = i; + max = mArray[i]; + } + } + + // + // Return index of the highest bar + return result; +} + +// +// Search for the index of the lowest bar ... +int Lowest( + const double &mArray[], + const int mDepth, + const int mStart // +) +{ + // + int result = 0; + + // + if (mStart < 0) + { + return result; + } + + // + double min = mArray[mStart]; + result = mStart; + + // + // Start searching ... + for (int i = mStart - 1; i > mStart - mDepth && i >= 0; i--) + { + // + if (mArray[i] < min) + { + // + result = i; + min = mArray[i]; + } + } + + // + // Return index of the lowest bar + return result; +} diff --git a/Documents/Indicators/x-saherelm.xzg.mq5 b/Documents/Indicators/x-saherelm.xzg.mq5 new file mode 100644 index 00000000..4d44b62c --- /dev/null +++ b/Documents/Indicators/x-saherelm.xzg.mq5 @@ -0,0 +1,1097 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// --------------------------------------------- +// Name: XZG +// Description: ZigZag Implementation ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm XZG Indicator" +#property strict + +// +#define ShortName "XZG" + +// +// Imports ... +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// Definitions ... +enum ENUM_X_ZG_SEARCH_MODE +{ + X_ZG_SEARCH_EXTREMUM = 0, // searching for the first extremum + X_ZG_SEARCH_PEAK = 1, // searching for the next ZigZag peak + X_ZG_SEARCH_VALE = -1 // searching for the next ZigZag vale +}; + +// +// Inputs ... + +// +input group "Calculation"; +input int depth = 12; // Depth +input int deviation = 5; // Deviation +input int backStep = 3; // Back Step +input ENUM_X_PRICE zigzagUppersMode = X_PRICE_HIGH; // High Detect Mode +input ENUM_X_PRICE zigzagLowersMode = X_PRICE_LOW; // Low Detect Mode + +// +// Presentation ... +input group "Presentation"; +input bool showPeaks = true; // Show Peaks +input bool showVales = true; // Show Vales +input bool showZigZag = true; // Show ZigZag +input int peakArrowCode = 159; // Peaks Arrow Code +input int valeArrowCode = 159; // Vales Arrow Code + +// +// Non Inputs ... + +// +#define hideColorIDX 0 +#define bullishColorIDX 1 +#define bearishColorIDX 2 +#define neuturalColorIDX 3 + +// +#define bullishState 1 +#define neuturalState 0 +#define bearishState -1 + +// +#define emptyValue 0.0 + +// +// Buffers ... + +// +#property indicator_chart_window + +// +#property indicator_buffers 7 +#property indicator_plots 3 + +// +// ZigZag ... + +// +#define zigzagBufferIndex 0 +#define zigzagBufferPlotIndex 0 +double zigzagBuffer[]; + +// +#property indicator_label1 "XZG" +#property indicator_type1 DRAW_SECTION +#property indicator_color1 clrYellow +#property indicator_width1 2 + +// +// Peaks ... + +// +#define peakBufferIndex 1 +#define peakBufferPlotIndex 1 +double peakBuffer[]; + +// +#property indicator_label2 "PEAK" +#property indicator_type2 DRAW_ARROW +#property indicator_color2 clrMagenta +#property indicator_width2 3 + +// +// Vales ... + +// +#define valeBufferIndex 2 +#define valeBufferPlotIndex 2 +double valeBuffer[]; + +// +#property indicator_label3 "VALE" +#property indicator_type3 DRAW_ARROW +#property indicator_color3 clrAqua +#property indicator_width3 3 + +// +// Data Buffers ... + +// +#define mLastBufferIndex 2 + +// +#define highsBufferIndex mLastBufferIndex + 1 +double highsBuffer[]; + +// +#define highsTimeBufferIndex mLastBufferIndex + 2 +double highsTimeBuffer[]; + +// +#define lowsBufferIndex mLastBufferIndex + 3 +double lowsBuffer[]; + +// +#define lowsTimeBufferIndex mLastBufferIndex + 4 +double lowsTimeBuffer[]; + +// +// Variables, Properties and etc ... + +// +int mRecalc = 3; // Number of last extremes for recalculation + +// +int limit; + +// +int maxLength; + +// +int firstBarIndex; + +// +double zigzagUppers[]; +double zigzagLowers[]; +int zigzagLowersCount = 0; +int zigzagUppersCount = 0; + +// +// Event Handlers ... + +/** + * Initialize Indicator ... + * + * @return ( int ) + */ +int OnInit() +{ + // + bool has = false; + + // + // Validate Inputs ... + has = ValidateInputs(); + if (!has) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // because in some cases we may have more than one input for + // calculation and we must prevent any calculation + // untill we pass the biggest input length, here we get max Input length + // and then wait until pass it ... + maxLength = ExtractMaxLengthOfInputs(); + + // + // Initial Requirements ... + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; + + // +} + +/** + * De Initialize Indicator ... + * + * @param reason: Integer, De Initialization Reason ... + */ +void OnDeinit(const int reason) +{ + // + // REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + // REASON_REMOVE 1 Program removed from a chart + // REASON_RECOMPILE 2 Program recompiled + // REASON_CHARTCHANGE 3 A symbol or a chart period is changed + // REASON_CHARTCLOSE 4 Chart closed + // REASON_PARAMETERS 5 Inputs changed by a user + // REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + // REASON_TEMPLATE 7 Another chart template applied + // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + // REASON_CLOSE 9 Terminal closed +} + +/** + * Calculate Bars ... + * + * @param rates_total: Integer, Total Bars on Chart ... + * @param prev_calculated: Integer, Total Calculated Bars on Charts ... + * @param time: DateTime Array, History of Open Time ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param low: Double Array, History of Low Prices ... + * @param close: Double Array, History of Close Prices ... + * @param tick_volume: Long, History of Tick Volumes on Bar ... + * @param volume: Long, History of Trade Volumes ... + * @param spread: Double, History of Spread Price ... + * + * @return ( int ) + */ +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[] // +) +{ + // + // Do ZigZag Calculations Before ArraySet As Series ... + int calculatedZigZags = CalculateZigZag( + 0, + prev_calculated, + rates_total, + open, + high, + close, + low, + tick_volume // + ); + if (calculatedZigZags != rates_total) + { + return prev_calculated; + } + + // + // Prepare Buffers ... + ArraySetAsSeries(time, true); + ArraySetAsSeries(open, true); + ArraySetAsSeries(high, true); + ArraySetAsSeries(low, true); + ArraySetAsSeries(close, true); + ArraySetAsSeries(tick_volume, true); + ArraySetAsSeries(volume, true); + ArraySetAsSeries(spread, true); + + // + // Validate Calculated Bars ... + + // + limit = (prev_calculated > rates_total || prev_calculated <= 0) + ? rates_total + : (rates_total - prev_calculated) + 1; + + // + // Main Loop ... + for (int i = 0; i <= limit - 1 && !IsStopped(); i++) + { + // + // Calculate Peaks and Vales ... + CalculatePeaksAndVales( + i, + prev_calculated, + rates_total, + // + open, + high, + close, + low, + tick_volume // + ); + } + + // for (int i = limit - 1; i >= 0 && !IsStopped(); i--) + // { + // // + // // Calculate Peaks and Vales ... + // CalculatePeaksAndVales( + // i, + // prev_calculated, + // rates_total, + // // + // open, + // high, + // close, + // low, + // tick_volume // + // ); + // } + + // + return rates_total; +} + +// +// Custom Functions ... + +/** + * Set Indicator Short Name and also we can define Buffers Labels ... + */ +void SetIndicatorName() +{ + // + IndicatorSetInteger(INDICATOR_DIGITS, _Digits); + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +/** + * Validate Input Args for Initialization ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = false; + + // + result = + // + // Inputs ... + depth > 0 && + deviation > 0 && + backStep > 0 && + // + // Validate Upper Mode Detection ... + IsXValid(zigzagUppersMode) && + // + // Validate Lower Mode Detection ... + IsXValid(zigzagLowersMode) + // + ; + + // + return result; +} + +/** + * Extract Max Length of Inputs ... + * + * @return ( int ) + */ +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + return result; +} + +/** + * Define Required Buffers ... + */ +void DefineBuffers() +{ + // + // Plot Buffers ... + + // + // ZigZag ... + + // + ENUM_DRAW_TYPE zigzagDrawType = showZigZag ? DRAW_SECTION : DRAW_NONE; + + // + SetIndexBuffer(zigzagBufferIndex, zigzagBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(zigzagBufferPlotIndex, PLOT_SHOW_DATA, showZigZag); + PlotIndexSetInteger(zigzagBufferPlotIndex, PLOT_DRAW_TYPE, zigzagDrawType); + + PlotIndexSetInteger(zigzagBufferPlotIndex, PLOT_DRAW_BEGIN, 0); + PlotIndexSetDouble(zigzagBufferPlotIndex, PLOT_EMPTY_VALUE, 0); + + // + // PEAK ... + + // + ENUM_DRAW_TYPE peaksDrawType = showPeaks ? DRAW_ARROW : DRAW_NONE; + + // + SetIndexBuffer(peakBufferIndex, peakBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(peakBufferPlotIndex, PLOT_SHOW_DATA, showPeaks); + PlotIndexSetInteger(peakBufferPlotIndex, PLOT_DRAW_TYPE, peaksDrawType); + + // + PlotIndexSetDouble(peakBufferPlotIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(peakBufferPlotIndex, PLOT_ARROW, peakArrowCode); + + // + // VALE ... + + // + ENUM_DRAW_TYPE valesDrawType = showVales ? DRAW_ARROW : DRAW_NONE; + + // + SetIndexBuffer(valeBufferIndex, valeBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(valeBufferPlotIndex, PLOT_SHOW_DATA, showVales); + PlotIndexSetInteger(valeBufferPlotIndex, PLOT_DRAW_TYPE, valesDrawType); + + // + PlotIndexSetDouble(valeBufferPlotIndex, PLOT_EMPTY_VALUE, EMPTY_VALUE); + PlotIndexSetInteger(valeBufferPlotIndex, PLOT_ARROW, valeArrowCode); + + // + // Data Buffers ... + + // + // Highs ... + SetIndexBuffer(highsBufferIndex, highsBuffer, INDICATOR_CALCULATIONS); + SetIndexBuffer(highsTimeBufferIndex, highsTimeBuffer, INDICATOR_CALCULATIONS); + + // + // Lows ... + SetIndexBuffer(lowsBufferIndex, lowsBuffer, INDICATOR_CALCULATIONS); + SetIndexBuffer(lowsTimeBufferIndex, lowsTimeBuffer, INDICATOR_CALCULATIONS); + + // +} + +/** + * Calculate Values ... + * + * @param barIndex: int, Specified Bar Index ... + * @param prevCalculated: int, Provides Previous Calculated Bars ... + * @param ratesTotal: int, Provides All Availabled Bars ... + * @param open: double Collection, Provides Open Prices Time Series ... + * @param high: double Collection, Provides High Prices Time Series ... + * @param close: double Collection, Provides Close Prices Time Series ... + * @param low: double Collection, Provides Low Prices Time Series ... + * @param tickVolume: long Collection, Provides Ticks Volume Prices Time Series ... + * + * @return ( int ) + */ +int CalculateZigZag( + int barIndex, + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + int result = 0; + + // + // Define Variables ... + int i = 0; + + // + int start = 0; + int extreme_counter = 0; + int extreme_search = X_ZG_SEARCH_EXTREMUM; + int shift = 0; + int back = 0; + int last_high_pos = 0; + int last_low_pos = 0; + + // + double val = 0; + double res = 0; + double curlow = 0; + double curhigh = 0; + double last_high = 0; + double last_low = 0; + + // + // Initializing ... + if (prevCalculated == 0) + { + // + ArrayInitialize(lowsBuffer, 0); + ArrayInitialize(highsBuffer, 0); + ArrayInitialize(zigzagBuffer, 0); + ArrayInitialize(lowsTimeBuffer, 0); + ArrayInitialize(highsTimeBuffer, 0); + + // + start = depth; + } + + // + // Preparing ZigZag Calculation High and Lows ... + + // + if (zigzagLowersCount != zigzagUppersCount || zigzagLowersCount != ratesTotal) + { + // + // Filling Upper ... + zigzagUppersCount = FillPrice( + zigzagUppersMode, + zigzagUppers, + open, + high, + close, + low // + ); + + // + // Filling Lower ... + zigzagLowersCount = FillPrice( + zigzagLowersMode, + zigzagLowers, + open, + high, + close, + low // + ); + } + + // + // Already Calculated Before ... + if (prevCalculated > 0) + { + // + i = ratesTotal - 1; + + // + // Searching for the third X_ZG_SEARCH_EXTREMUM from the last UnComplete Bar ... + while (extreme_counter < mRecalc && i > ratesTotal - 100) + { + // + res = zigzagBuffer[i]; + if (res != 0) + { + extreme_counter++; + } + + // + i--; + } + + // + i++; + start = i; + + // + // What type of X_ZG_SEARCH_EXTREMUM we Search for ... + if (lowsBuffer[i] != 0) + { + // + curlow = lowsBuffer[i]; + extreme_search = X_ZG_SEARCH_PEAK; + } + else + { + // + curhigh = highsBuffer[i]; + extreme_search = X_ZG_SEARCH_VALE; + } + + // + // Clear Values ... + for (i = start + 1; i < ratesTotal && !IsStopped(); i++) + { + // + lowsBuffer[i] = 0; + highsBuffer[i] = 0; + zigzagBuffer[i] = 0; + lowsTimeBuffer[i] = 0; + highsTimeBuffer[i] = 0; + } + } + + // + // Search for High and Low Extremes ... + for (shift = start; shift < ratesTotal && !IsStopped(); shift++) + { + // + // Low ... + val = zigzagLowers[Lowest(zigzagLowers, depth, shift)]; + if (val == last_low) + { + val = 0; + } + else + { + // + last_low = val; + + // + if ((zigzagLowers[shift] - val) > deviation * _Point) + { + val = 0; + } + else + { + // + for (back = 1; back <= backStep; back++) + { + // + res = lowsBuffer[shift - back]; + if ((res != 0) && (res > val)) + { + // + lowsBuffer[shift - back] = 0; + lowsTimeBuffer[shift - back] = 0; + } + } + } + } + + // + if (zigzagLowers[shift] == val) + { + // + lowsBuffer[shift] = val; + lowsTimeBuffer[shift] = GetZigZagBarTime(shift); + } + else + { + // + lowsBuffer[shift] = 0; + lowsTimeBuffer[shift] = 0; + } + + // + // High ... + val = zigzagUppers[Highest(zigzagUppers, depth, shift)]; + if (val == last_high) + { + val = 0; + } + else + { + // + last_high = val; + + // + if ((val - zigzagUppers[shift]) > deviation * _Point) + { + val = 0; + } + else + { + // + for (back = 1; back <= backStep; back++) + { + // + res = highsBuffer[shift - back]; + if ((res != 0) && (res < val)) + { + // + highsBuffer[shift - back] = 0; + highsTimeBuffer[shift - back] = 0; + } + } + } + } + + // + if (zigzagUppers[shift] == val) + { + // + highsBuffer[shift] = val; + highsTimeBuffer[shift] = GetZigZagBarTime(shift); + } + else + { + highsBuffer[shift] = 0; + highsTimeBuffer[shift] = 0; + } + } + + // + // Set Last Value ... + if (extreme_search == 0) // Undefined Values ... + { + // + last_low = 0; + last_high = 0; + } + else + { + // + last_low = curlow; + last_high = curhigh; + } + + // + // Final Selection of Extreme Points for ZigZag ... + for (shift = start; shift < ratesTotal && !IsStopped(); shift++) + { + // + res = 0; + + // + switch (extreme_search) + { + // + case X_ZG_SEARCH_EXTREMUM: + // + if (last_low == 0 && last_high == 0) + { + // + if (highsBuffer[shift] != 0) + { + // + last_high_pos = shift; + last_high = zigzagUppers[shift]; + + // + extreme_search = X_ZG_SEARCH_VALE; + + // + zigzagBuffer[shift] = last_high; + + // + res = 1; + } + + // + if (lowsBuffer[shift] != 0) + { + // + last_low_pos = shift; + last_low = zigzagLowers[shift]; + + // + extreme_search = X_ZG_SEARCH_PEAK; + + // + zigzagBuffer[shift] = last_low; + + // + res = 1; + } + } + break; + + // + case X_ZG_SEARCH_PEAK: + // + if (lowsBuffer[shift] != 0 && lowsBuffer[shift] < last_low && highsBuffer[shift] == 0) + { + // + zigzagBuffer[last_low_pos] = 0; + + // + last_low_pos = shift; + last_low = lowsBuffer[shift]; + + // + zigzagBuffer[shift] = last_low; + + // + res = 1; + } + + // + if (highsBuffer[shift] != 0 && lowsBuffer[shift] == 0) + { + // + last_high_pos = shift; + last_high = highsBuffer[shift]; + + // + zigzagBuffer[shift] = last_high; + + // + extreme_search = X_ZG_SEARCH_VALE; + + // + res = 1; + } + break; + + // + case X_ZG_SEARCH_VALE: + // + if (highsBuffer[shift] != 0 && highsBuffer[shift] > last_high && lowsBuffer[shift] == 0) + { + // + zigzagBuffer[last_high_pos] = 0; + + // + last_high_pos = shift; + last_high = highsBuffer[shift]; + + // + zigzagBuffer[shift] = last_high; + } + + // + if (lowsBuffer[shift] != 0 && highsBuffer[shift] == 0) + { + // + last_low_pos = shift; + last_low = lowsBuffer[shift]; + + // + zigzagBuffer[shift] = last_low; + + // + extreme_search = X_ZG_SEARCH_PEAK; + } + break; + } + } + + // + result = ratesTotal; + + // + return result; +} + +/** + * Calculate Peaks and Vales ... + * + * @param barIndex: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculatePeaksAndVales( + int barIndex, + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + double iZigZagValue = zigzagBuffer[barIndex]; + + // + // Peak ... + double iHighValue = highsBuffer[barIndex]; + double iHighTimeDouble = highsTimeBuffer[barIndex]; + datetime iHighTime = (datetime)((int)iHighTimeDouble); + if (iHighValue != 0 && iHighValue != EMPTY_VALUE && iZigZagValue == iHighValue) + { + peakBuffer[barIndex] = iHighValue; + } + else + { + // + double iValue = emptyValue; + + // + peakBuffer[barIndex] = iValue; + } + + // + // Vale ... + double iLowValue = lowsBuffer[barIndex]; + double iLowTimeDouble = lowsTimeBuffer[barIndex]; + datetime iLowTime = (datetime)((int)iLowTimeDouble); + if (iLowValue != 0 && iLowValue != EMPTY_VALUE && iZigZagValue == iLowValue) + { + valeBuffer[barIndex] = iLowValue; + } + else + { + // + double iValue = emptyValue; + + // + valeBuffer[barIndex] = iValue; + } +} + +// +// Get Specified Bar Time as Double ... +double GetZigZagBarTime(int barIndex) +{ + // + if (barIndex <= 0) + { + barIndex = 0; + } + + // + datetime time = iTime(_Symbol, _Period, barIndex); + + // + double result = (double)((int)time); + + // + return result; +} + +// +// Filling Required Prices Based on MODE ... +int FillPrice( + ENUM_X_PRICE mode, + double &dest[], + const double &open[], + const double &high[], + const double &close[], + const double &low[] // +) +{ + // + int result = 0; + + // + SpecifiedClean(dest); + + // + if (!IsXValid(mode)) + { + return result; + } + + // + switch (mode) + { + // + case X_PRICE_HIGH: + // + result = ArrayCopy( + dest, + high // + ); + break; + + // + case X_PRICE_LOW: + // + result = ArrayCopy( + dest, + low // + ); + break; + + // + case X_PRICE_OPEN: + // + result = ArrayCopy( + dest, + open // + ); + break; + + // + case X_PRICE_CLOSE: + // + result = ArrayCopy( + dest, + close // + ); + break; + + // + default: + // + result = ArrayCopy( + dest, + close // + ); + break; + } + + // + return result; +} + +// +// Search for the index of the highest bar ... +int Highest( + const double &mArray[], + const int mDepth, + const int mStart // +) +{ + // + int result = 0; + + // + if (mStart < 0) + { + return result; + } + + // + double max = mArray[mStart]; + result = mStart; + + // + // Start searching ... + for (int i = mStart - 1; i > mStart - mDepth && i >= 0; i--) + { + // + if (mArray[i] > max) + { + // + result = i; + max = mArray[i]; + } + } + + // + // Return index of the highest bar + return result; +} + +// +// Search for the index of the lowest bar ... +int Lowest( + const double &mArray[], + const int mDepth, + const int mStart // +) +{ + // + int result = 0; + + // + if (mStart < 0) + { + return result; + } + + // + double min = mArray[mStart]; + result = mStart; + + // + // Start searching ... + for (int i = mStart - 1; i > mStart - mDepth && i >= 0; i--) + { + // + if (mArray[i] < min) + { + // + result = i; + min = mArray[i]; + } + } + + // + // Return index of the lowest bar + return result; +} diff --git a/Experts/x-saherelm.xfima.backtester.ea.mq5 b/Experts/x-saherelm.xfima.backtester.ea.mq5 index 46b4355a..84214a65 100644 --- a/Experts/x-saherelm.xfima.backtester.ea.mq5 +++ b/Experts/x-saherelm.xfima.backtester.ea.mq5 @@ -92,6 +92,11 @@ input ENUM_MA_METHOD maMethod = MODE_EMA; // MA Method input ENUM_APPLIED_PRICE maAppliedTo = PRICE_CLOSE; // MA Applied To input int maFastLength = 7; // Fast MA Length input int maSlowLength = 20; // Slow MA Length +input int zigzagDepth = 12; // ZigZag Depth +input int zigzagDeviation = 5; // ZigZag Deviation +input int zigzagBackStep = 3; // ZigZag Back Step +input ENUM_X_PRICE zigzagUppersMode = X_PRICE_HIGH; // ZigZag High Detect Mode +input ENUM_X_PRICE zigzagLowersMode = X_PRICE_LOW; // ZigZag Low Detect Mode // input group "Bar Timer"; @@ -108,6 +113,7 @@ input bool showSAR = true; // Show Sar input bool showMAFast = true; // Show MA Fast input bool showMASlow = true; // Show MA Slow input bool showBarTime = true; // Show Bar Time +input bool showZigZag = true; // Show ZigZag input bool showFiboZone = false; // Show Fibo Zone // @@ -231,7 +237,7 @@ int OnInit() eaHandler = iCustom( _Symbol, _Period, - "x-saherelm.xom1", + "x-saherelm.xfima", "", // Calculation ... scMethod, scPeriod, @@ -251,11 +257,17 @@ int OnInit() maAppliedTo, maFastLength, maSlowLength, + zigzagDepth, + zigzagDeviation, + zigzagBackStep, + zigzagUppersMode, + zigzagLowersMode, "", // Presentation ... showPV, showSAR, showMAFast, showMASlow, + showZigZag, showFiboZone, startCalculationForLastBars, sarArrowCode, @@ -438,7 +450,18 @@ bool ValidateInputs() (IsValid(scMethod, scPeriod) && IsValid(mcMethod, mcPeriod) && IsValid(lcMethod, lcPeriod) && - IsValid(hcMethod, hcPeriod)) + IsValid(hcMethod, hcPeriod)) && + // + // ZIGZAG ... + zigzagDepth > 0 && + zigzagDeviation > 0 && + zigzagBackStep > 0 && + // + // Validate Upper Mode Detection ... + IsXValid(zigzagUppersMode) && + // + // Validate Lower Mode Detection ... + IsXValid(zigzagLowersMode) // ); if (!isCommonValid) diff --git a/Indicators/x-saherelm.xfima.mq5 b/Indicators/x-saherelm.xfima.mq5 new file mode 100644 index 00000000..e0f16f04 --- /dev/null +++ b/Indicators/x-saherelm.xfima.mq5 @@ -0,0 +1,2074 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// ------------------------------------------------- +// Name: XFIMA +// Description: Integrates All Requirements inside +// this indicator for analyse Markets Based on OM1 ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm XFIMA Indicator" +#property strict + +// +// Definitions ... + +// +// Definitions ... +enum ENUM_X_ZG_SEARCH_MODE +{ + X_ZG_SEARCH_EXTREMUM = 0, // searching for the first extremum + X_ZG_SEARCH_PEAK = 1, // searching for the next ZigZag peak + X_ZG_SEARCH_VALE = -1 // searching for the next ZigZag vale +}; + +// +#define ShortName "XFIMA" + +// +// Imports ... +#include "../Classes/x-saherelm.x-poi.drawer.class.mq5" +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// Inputs ... + +// +input group "Calculation"; + +// +// Short ... +input ENUM_X_PERIOD_METHOD scMethod = X_PERIOD_AUTO; // How to Find Short Period +input ENUM_TIMEFRAMES scPeriod = NULL; // Short Period + +// +// Medium ... +input ENUM_X_PERIOD_METHOD mcMethod = X_PERIOD_AUTO; // How to Find Medium Period +input ENUM_TIMEFRAMES mcPeriod = NULL; // Medium Period + +// +// Long ... +input ENUM_X_PERIOD_METHOD lcMethod = X_PERIOD_AUTO; // How to Find Long Period +input ENUM_TIMEFRAMES lcPeriod = NULL; // Long Period + +// +// Hind ... +input ENUM_X_PERIOD_METHOD hcMethod = X_PERIOD_AUTO; // How to Find Hind Period +input ENUM_TIMEFRAMES hcPeriod = NULL; // Hind Period + +// +// PV ... +input ENUM_SERIESMODE upperMode = MODE_HIGH; // Peak Method +input ENUM_SERIESMODE lowerMode = MODE_LOW; // Vale Method + +// +// Others ... +input ENUM_X_FIBO_LEVELS upperZoneLevel = X_FIBO_LEVEL_618; // Upper Zone Level +input ENUM_X_FIBO_LEVELS lowerZoneLevel = X_FIBO_LEVEL_382; // Lower Zone Level +input double sarStep = 0.02; // SAR Step +input double sarMax = 0.2; // SAR Maximum +input ENUM_MA_METHOD maMethod = MODE_EMA; // MA Method +input ENUM_APPLIED_PRICE maAppliedTo = PRICE_CLOSE; // MA Applied To +input int maFastLength = 7; // Fast MA Length +input int maSlowLength = 20; // Slow MA Length +input int zigzagDepth = 12; // ZigZag Depth +input int zigzagDeviation = 5; // ZigZag Deviation +input int zigzagBackStep = 3; // ZigZag Back Step +input ENUM_X_PRICE zigzagUppersMode = X_PRICE_HIGH; // ZigZag High Detect Mode +input ENUM_X_PRICE zigzagLowersMode = X_PRICE_LOW; // ZigZag Low Detect Mode + +// +// Presentation ... +input group "Presentation"; +input bool showPV = true; // Show PV +input bool showSAR = true; // Show Sar +input bool showMAFast = true; // Show MA Fast +input bool showMASlow = true; // Show MA Slow +input bool showZigZag = true; // Show ZigZag +input bool showFiboZone = true; // Show Fibo Zone + +// +input int startCalculationForLastBars = 1500; // Calculate Last n Bars + +// +input int sarArrowCode = 159; // Parabolic Sar Arrow Code +input int peakArrowCode = 159; // Peaks Arrow Code +input int valeArrowCode = 159; // Vales Arrow Code + +// +// Non Inputs ... + +// +#define hideColorIDX 0 +#define bullishColorIDX 1 +#define bearishColorIDX 2 +#define neuturalColorIDX 3 + +// +#define bullishState 1 +#define neuturalState 0 +#define bearishState -1 + +// +#define emptyValue 0.0 + +// +// Buffers ... + +// +#property indicator_chart_window + +// +#property indicator_buffers 26 +#property indicator_plots 8 + +// +// Plot Buffers ... + +// +// Fast MA ... + +// +#define maFastBufferIndex 0 +#define maFastBufferPlotIndex 0 +double maFastBuffer[]; + +// +#define maFastColorBufferIndex 1 +double maFastColorBuffer[]; + +// +#property indicator_label1 "FastMA" +#property indicator_type1 DRAW_COLOR_LINE +#property indicator_color1 CLR_NONE, clrYellow, clrOrangeRed, clrGray +#property indicator_width1 2 + +// +// Slow MA ... + +// +#define maSlowBufferIndex 2 +#define maSlowBufferPlotIndex 1 +double maSlowBuffer[]; + +// +#define maSlowColorBufferIndex 3 +double maSlowColorBuffer[]; + +// +#property indicator_label2 "SlowMA" +#property indicator_type2 DRAW_COLOR_LINE +#property indicator_color2 CLR_NONE, clrLime, clrRed, clrGray +#property indicator_width2 2 + +// +// SAR ... + +// +#define sarBufferIndex 4 +#define sarBufferPlotIndex 2 +double sarBuffer[]; + +// +#define sarColorBufferIndex 5 +double sarColorBuffer[]; + +// +#property indicator_label3 "SAR" +#property indicator_type3 DRAW_COLOR_ARROW +#property indicator_color3 CLR_NONE, clrLime, clrRed, clrGray +#property indicator_width3 2 + +// +// PEAKS ... + +// +#define peakBufferIndex 6 +#define peakBufferPlotIndex 3 +double peakBuffer[]; + +// +#property indicator_label4 "PEAK" +#property indicator_type4 DRAW_ARROW +#property indicator_color4 clrMagenta +#property indicator_width4 3 + +// +// VALES ... + +// +#define valeBufferIndex 7 +#define valeBufferPlotIndex 4 +double valeBuffer[]; + +// +#property indicator_label5 "VALE" +#property indicator_type5 DRAW_ARROW +#property indicator_color5 clrAqua +#property indicator_width5 3 + +// +// FIBO Upper ... + +// +#define fiboUpperBufferIndex 8 +#define fiboUpperBufferPlotIndex 5 +double fiboUpperBuffer[]; + +// +#property indicator_label6 "FIBUP" +#property indicator_type6 DRAW_LINE +#property indicator_color6 clrAqua +#property indicator_width6 2 + +// +// FIBO Lower ... + +// +#define fiboLowerBufferIndex 9 +#define fiboLowerBufferPlotIndex 6 +double fiboLowerBuffer[]; + +// +#property indicator_label7 "FIBLO" +#property indicator_type7 DRAW_LINE +#property indicator_color7 clrMagenta +#property indicator_width7 2 + +// +// ZigZag ... + +// +#define zigzagBufferIndex 10 +#define zigzagBufferPlotIndex 7 +double zigzagBuffer[]; + +// +#property indicator_label8 "XZG" +#property indicator_type8 DRAW_SECTION +#property indicator_color8 clrYellow +#property indicator_width8 2 + +// +// Data Buffers ... + +// +#define mLastBufferIndex 10 + +// +// MA ... + +// +#define maFastStateBufferIndex mLastBufferIndex + 1 +double maFastStateBuffer[]; + +// +#define maSlowStateBufferIndex mLastBufferIndex + 2 +double maSlowStateBuffer[]; + +// +// SAR ... + +// +#define sarStateBufferIndex mLastBufferIndex + 3 +double sarStateBuffer[]; + +// +// CYCLES ... + +// +// SC ... + +// +#define sHHBufferIndex mLastBufferIndex + 4 +double sHHBuffer[]; + +// +#define sLLBufferIndex mLastBufferIndex + 5 +double sLLBuffer[]; + +// +// MC ... + +// +#define mHHBufferIndex mLastBufferIndex + 6 +double mHHBuffer[]; + +// +#define mLLBufferIndex mLastBufferIndex + 7 +double mLLBuffer[]; + +// +// LC ... + +// +#define lHHBufferIndex mLastBufferIndex + 8 +double lHHBuffer[]; + +// +#define lLLBufferIndex mLastBufferIndex + 9 +double lLLBuffer[]; + +// +// HC ... + +// +#define hHHBufferIndex mLastBufferIndex + 10 +double hHHBuffer[]; + +// +#define hLLBufferIndex mLastBufferIndex + 11 +double hLLBuffer[]; + +// +// ZigZag ... + +// +#define highsBufferIndex mLastBufferIndex + 12 +double highsBuffer[]; + +// +#define highsTimeBufferIndex mLastBufferIndex + 13 +double highsTimeBuffer[]; + +// +#define lowsBufferIndex mLastBufferIndex + 14 +double lowsBuffer[]; + +// +#define lowsTimeBufferIndex mLastBufferIndex + 15 +double lowsTimeBuffer[]; + +// +// Variables, Properties and etc ... + +// +// XMarketCycle sc; +int mSCLength = 0; +ENUM_TIMEFRAMES mSCPeriod = NULL; + +// +// XMarketCycle mc; +int mMCLength = 0; +ENUM_TIMEFRAMES mMCPeriod = NULL; + +// +// XMarketCycle lc; +int mLCLength = 0; +ENUM_TIMEFRAMES mLCPeriod = NULL; + +// +// XMarketCycle hc; +int mHCLength = 0; +ENUM_TIMEFRAMES mHCPeriod = NULL; + +// +int sarHandler = INVALID_HANDLE; +int maFastHandler = INVALID_HANDLE; +int maSlowHandler = INVALID_HANDLE; + +// +int limit; + +// +int maxLength; + +// +int firstBarIndex; + +// +// Requirements ... +CArrayObj mObjects; +XCPOIDrawer *mDrawer; + +// +double zigzagUppers[]; +double zigzagLowers[]; +int zigzagLowersCount = 0; +int zigzagUppersCount = 0; +int zigzagRecalc = 3; // Number of last extremes for recalculation + +// +// Event Handlers ... + +/** + * Initialize Indicator ... + * + * @return ( int ) + */ +int OnInit() +{ + // + bool has = false; + + // + // Validate Inputs ... + has = ValidateInputs(); + if (!has) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + has = InitCycles(); + if (!has) + { + return INIT_FAILED; + } + + // + // because in some cases we may have more than one input for + // calculation and we must prevent any calculation + // untill we pass the biggest input length, here we get max Input length + // and then wait until pass it ... + maxLength = ExtractMaxLengthOfInputs(); + + // + // Initial Requirements ... + has = InitRequirements(); + if (!has) + { + return INIT_FAILED; + } + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; + + // +} + +/** + * De Initialize Indicator ... + * + * @param reason: Integer, De Initialization Reason ... + */ +void OnDeinit(const int reason) +{ + // + // REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + // REASON_REMOVE 1 Program removed from a chart + // REASON_RECOMPILE 2 Program recompiled + // REASON_CHARTCHANGE 3 A symbol or a chart period is changed + // REASON_CHARTCLOSE 4 Chart closed + // REASON_PARAMETERS 5 Inputs changed by a user + // REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + // REASON_TEMPLATE 7 Another chart template applied + // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + // REASON_CLOSE 9 Terminal closed + + // + delete mDrawer; + ZeroMemory(mDrawer); + + // + mObjects.Clear(); + + // + // De Initialize all Handlers and etc ... + IndicatorRelease(sarHandler); + IndicatorRelease(maFastHandler); + IndicatorRelease(maSlowHandler); +} + +/** + * Calculate Bars ... + * + * @param rates_total: Integer, Total Bars on Chart ... + * @param prev_calculated: Integer, Total Calculated Bars on Charts ... + * @param time: DateTime Array, History of Open Time ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param low: Double Array, History of Low Prices ... + * @param close: Double Array, History of Close Prices ... + * @param tick_volume: Long, History of Tick Volumes on Bar ... + * @param volume: Long, History of Trade Volumes ... + * @param spread: Double, History of Spread Price ... + * + * @return ( int ) + */ +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[] // +) +{ + // + // Do ZigZag Calculations Before ArraySet As Series ... + int calculatedZigZags = CalculateZigZag( + 0, + prev_calculated, + rates_total, + open, + high, + close, + low, + tick_volume // + ); + if (calculatedZigZags != rates_total) + { + return prev_calculated; + } + + // + // Prepare Buffers ... + ArraySetAsSeries(time, true); + ArraySetAsSeries(open, true); + ArraySetAsSeries(high, true); + ArraySetAsSeries(low, true); + ArraySetAsSeries(close, true); + ArraySetAsSeries(tick_volume, true); + ArraySetAsSeries(volume, true); + ArraySetAsSeries(spread, true); + + // + // Validate Calculated Bars ... + + // + // MA ... + int maFastCalculatedBars = BarsCalculated(maFastHandler); + int maSlowCalculatedBars = BarsCalculated(maSlowHandler); + + // + // SAR ... + int sarCalculatedBars = BarsCalculated(sarHandler); + + // + bool isPassedRequiredCalculatedBars = + // + // MA ... + maFastCalculatedBars >= maxLength && + maSlowCalculatedBars >= maxLength && + // + // SAR ... + sarCalculatedBars >= maxLength + // + ; + if (!isPassedRequiredCalculatedBars) + { + return prev_calculated; + } + + // + limit = (prev_calculated > rates_total || prev_calculated <= 0) + ? rates_total + : (rates_total - prev_calculated) + 1; + + // + // Buffers Copy ... + + // + // MA ... + int copiedMAFasts = CopyBuffer(maFastHandler, MAIN_LINE, 0, limit, maFastBuffer); + int copiedMASlows = CopyBuffer(maSlowHandler, MAIN_LINE, 0, limit, maSlowBuffer); + + // + // SAR ... + int copiedSARs = CopyBuffer(sarHandler, MAIN_LINE, 0, limit, sarBuffer); + + // + // Validate Copied Items ... + bool isPassedRequiredCopiedItems = + // + // MA ... + copiedMAFasts >= limit && + copiedMASlows >= limit && + // + // SAR ... + copiedSARs >= limit + // + ; + if (!isPassedRequiredCopiedItems) + { + return prev_calculated; + } + + // + // Main Loop ... + for (int i = limit - 1; i >= 0 && !IsStopped(); i--) + { + // + CalculateBuffers( + i, + prev_calculated, + rates_total, + // + open, + high, + close, + low, + tick_volume // + ); + } + + // + return rates_total; +} + +// +// Custom Functions ... + +/** + * Set Indicator Short Name and also we can define Buffers Labels ... + */ +void SetIndicatorName() +{ + // + IndicatorSetInteger(INDICATOR_DIGITS, _Digits); + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +/** + * Validate Input Args for Initialization ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = false; + + // + result = + // + // MA ... + maFastLength >= 2 && + maSlowLength >= 2 && + maSlowLength > maFastLength && + // + // SAR ... + sarMax > 0 && + sarStep > 0 && + sarMax > sarStep && + // + // CYCLES ... + (IsValid(scMethod, scPeriod) && + IsValid(mcMethod, mcPeriod) && + IsValid(lcMethod, lcPeriod) && + IsValid(hcMethod, hcPeriod)) && + // + // ZIGZAG ... + zigzagDepth > 0 && + zigzagDeviation > 0 && + zigzagBackStep > 0 && + // + // Validate Upper Mode Detection ... + IsXValid(zigzagUppersMode) && + // + // Validate Lower Mode Detection ... + IsXValid(zigzagLowersMode) + // + ; + + // + return result; +} + +/** + * Extract Max Length of Inputs ... + * + * @return ( int ) + */ +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + result = MathMax(mSCLength, mMCLength); + result = MathMax(result, mLCLength); + result = MathMax(result, mHCLength); + result = MathMax(result, maFastLength); + result = MathMax(result, maSlowLength); + + // + return result; +} + +/** + * Define Required Buffers ... + */ +void DefineBuffers() +{ + // + // Fast MA ... + + // + ArraySetAsSeries(maFastBuffer, true); + SetIndexBuffer(maFastBufferIndex, maFastBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(maFastBufferPlotIndex, PLOT_SHOW_DATA, showMAFast); + PlotIndexSetDouble(maFastBufferPlotIndex, PLOT_EMPTY_VALUE, emptyValue); + + // + ArraySetAsSeries(maFastColorBuffer, true); + SetIndexBuffer(maFastColorBufferIndex, maFastColorBuffer, INDICATOR_COLOR_INDEX); + + // + ArraySetAsSeries(maFastStateBuffer, true); + SetIndexBuffer(maFastStateBufferIndex, maFastStateBuffer, INDICATOR_CALCULATIONS); + + // + // Slow MA ... + + // + ArraySetAsSeries(maSlowBuffer, true); + SetIndexBuffer(maSlowBufferIndex, maSlowBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(maSlowBufferPlotIndex, PLOT_SHOW_DATA, showMASlow); + PlotIndexSetDouble(maSlowBufferPlotIndex, PLOT_EMPTY_VALUE, emptyValue); + + // + ArraySetAsSeries(maSlowColorBuffer, true); + SetIndexBuffer(maSlowColorBufferIndex, maSlowColorBuffer, INDICATOR_COLOR_INDEX); + + // + ArraySetAsSeries(maSlowStateBuffer, true); + SetIndexBuffer(maSlowStateBufferIndex, maSlowStateBuffer, INDICATOR_CALCULATIONS); + + // + // SAR ... + + // + ArraySetAsSeries(sarBuffer, true); + SetIndexBuffer(sarBufferIndex, sarBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(sarBufferPlotIndex, PLOT_SHOW_DATA, showSAR); + PlotIndexSetDouble(sarBufferPlotIndex, PLOT_EMPTY_VALUE, emptyValue); + PlotIndexSetInteger(sarBufferPlotIndex, PLOT_ARROW, sarArrowCode); + + // + ArraySetAsSeries(sarColorBuffer, true); + SetIndexBuffer(sarColorBufferIndex, sarColorBuffer, INDICATOR_COLOR_INDEX); + + // + ArraySetAsSeries(sarStateBuffer, true); + SetIndexBuffer(sarStateBufferIndex, sarStateBuffer, INDICATOR_CALCULATIONS); + + // + // PEAK / VALE ... + + // + ENUM_DRAW_TYPE pvDrawType = showPV ? DRAW_ARROW : DRAW_NONE; + + // + // PEAK ... + + // + ArraySetAsSeries(peakBuffer, true); + SetIndexBuffer(peakBufferIndex, peakBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(peakBufferPlotIndex, PLOT_SHOW_DATA, showPV); + PlotIndexSetInteger(peakBufferPlotIndex, PLOT_DRAW_TYPE, pvDrawType); + + // + PlotIndexSetDouble(peakBufferPlotIndex, PLOT_EMPTY_VALUE, emptyValue); + PlotIndexSetInteger(peakBufferPlotIndex, PLOT_ARROW, peakArrowCode); + + // + // VALE ... + + // + ArraySetAsSeries(valeBuffer, true); + SetIndexBuffer(valeBufferIndex, valeBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(valeBufferPlotIndex, PLOT_SHOW_DATA, showPV); + PlotIndexSetInteger(valeBufferPlotIndex, PLOT_DRAW_TYPE, pvDrawType); + + // + PlotIndexSetDouble(valeBufferPlotIndex, PLOT_EMPTY_VALUE, emptyValue); + PlotIndexSetInteger(valeBufferPlotIndex, PLOT_ARROW, valeArrowCode); + + // + // FIBO Zone ... + + // + ENUM_DRAW_TYPE fiboZoneDrawType = showFiboZone ? DRAW_LINE : DRAW_NONE; + + // + // Upper ... + ArraySetAsSeries(fiboUpperBuffer, true); + SetIndexBuffer(fiboUpperBufferIndex, fiboUpperBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(fiboUpperBufferPlotIndex, PLOT_SHOW_DATA, showFiboZone); + PlotIndexSetInteger(fiboUpperBufferPlotIndex, PLOT_DRAW_TYPE, fiboZoneDrawType); + PlotIndexSetDouble(fiboUpperBufferPlotIndex, PLOT_EMPTY_VALUE, emptyValue); + + // + // Lower ... + ArraySetAsSeries(fiboLowerBuffer, true); + SetIndexBuffer(fiboLowerBufferIndex, fiboLowerBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(fiboLowerBufferPlotIndex, PLOT_SHOW_DATA, showFiboZone); + PlotIndexSetInteger(fiboLowerBufferPlotIndex, PLOT_DRAW_TYPE, fiboZoneDrawType); + PlotIndexSetDouble(fiboLowerBufferPlotIndex, PLOT_EMPTY_VALUE, emptyValue); + + // + // ZigZag ... + + // + ENUM_DRAW_TYPE zigzagDrawType = showZigZag ? DRAW_SECTION : DRAW_NONE; + + // + SetIndexBuffer(zigzagBufferIndex, zigzagBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(zigzagBufferPlotIndex, PLOT_SHOW_DATA, showZigZag); + PlotIndexSetInteger(zigzagBufferPlotIndex, PLOT_DRAW_TYPE, zigzagDrawType); + + PlotIndexSetInteger(zigzagBufferPlotIndex, PLOT_DRAW_BEGIN, 0); + PlotIndexSetDouble(zigzagBufferPlotIndex, PLOT_EMPTY_VALUE, 0); + + // + // Data Buffers ... + + // + // CYCLES ... + + // + // SC ... + + // + ArraySetAsSeries(sHHBuffer, true); + SetIndexBuffer(sHHBufferIndex, sHHBuffer, INDICATOR_DATA); + + // + ArraySetAsSeries(sLLBuffer, true); + SetIndexBuffer(sLLBufferIndex, sLLBuffer, INDICATOR_DATA); + + // + // MC ... + + // + ArraySetAsSeries(mHHBuffer, true); + SetIndexBuffer(mHHBufferIndex, mHHBuffer, INDICATOR_DATA); + + // + ArraySetAsSeries(mLLBuffer, true); + SetIndexBuffer(mLLBufferIndex, mLLBuffer, INDICATOR_DATA); + + // + // LC ... + + // + ArraySetAsSeries(lHHBuffer, true); + SetIndexBuffer(lHHBufferIndex, lHHBuffer, INDICATOR_DATA); + + // + ArraySetAsSeries(lLLBuffer, true); + SetIndexBuffer(lLLBufferIndex, lLLBuffer, INDICATOR_DATA); + + // + // HC ... + + // + ArraySetAsSeries(hHHBuffer, true); + SetIndexBuffer(hHHBufferIndex, hHHBuffer, INDICATOR_DATA); + + // + ArraySetAsSeries(hLLBuffer, true); + SetIndexBuffer(hLLBufferIndex, hLLBuffer, INDICATOR_DATA); + + // + // Highs ... + SetIndexBuffer(highsBufferIndex, highsBuffer, INDICATOR_CALCULATIONS); + SetIndexBuffer(highsTimeBufferIndex, highsTimeBuffer, INDICATOR_CALCULATIONS); + + // + // Lows ... + SetIndexBuffer(lowsBufferIndex, lowsBuffer, INDICATOR_CALCULATIONS); + SetIndexBuffer(lowsTimeBufferIndex, lowsTimeBuffer, INDICATOR_CALCULATIONS); + + // +} + +/** + * Initial Market Cycles ... + * + * @return ( bool ) + */ +bool InitCycles() +{ + // + bool result = false; + + // + int cPeriodSeconds = PeriodSeconds(_Period); + + // + // Find Cycle Period ... + if (scMethod == X_PERIOD_AUTO) + { + // + // Select Period ... + mSCPeriod = GetCyclePeriod( + X_MARKET_CYCLE_SHORT, + _Period // + ); + } + else + { + mSCPeriod = scPeriod; + } + + // + if (IsValid(mSCPeriod)) + { + mSCLength = PeriodSeconds(mSCPeriod) / cPeriodSeconds; + } + + // + // Find Cycle Period ... + if (mcMethod == X_PERIOD_AUTO) + { + // + // Select Period ... + mMCPeriod = GetCyclePeriod( + X_MARKET_CYCLE_MEDIUM, + _Period // + ); + } + else + { + mMCPeriod = mcPeriod; + } + + // + if (IsValid(mMCPeriod)) + { + mMCLength = PeriodSeconds(mMCPeriod) / cPeriodSeconds; + } + + // + // Find Cycle Period ... + if (lcMethod == X_PERIOD_AUTO) + { + // + // Select Period ... + mLCPeriod = GetCyclePeriod( + X_MARKET_CYCLE_LONG, + _Period // + ); + } + else + { + mLCPeriod = lcPeriod; + } + + // + if (IsValid(mLCPeriod)) + { + mLCLength = PeriodSeconds(mLCPeriod) / cPeriodSeconds; + } + + // + // Find Cycle Period ... + if (hcMethod == X_PERIOD_AUTO) + { + // + // Select Period ... + mHCPeriod = GetCyclePeriod( + X_MARKET_CYCLE_HIND, + _Period // + ); + } + else + { + mHCPeriod = hcPeriod; + } + + // + if (IsValid(mHCPeriod)) + { + mHCLength = PeriodSeconds(mHCPeriod) / cPeriodSeconds; + } + + // + result = mSCLength > 0 && + mMCLength > mSCLength && + mLCLength > mMCLength && + mHCLength > mLCLength; + + // + return result; +} + +/** + * Initial all Indicator Requirements ... + * + * @return ( false ) + * + */ +bool InitRequirements() +{ + // + bool result = false; + + // + // Handlers ... + + // + // Fast MA ... + maFastHandler = iMA( + _Symbol, + _Period, + maFastLength, + 0, + maMethod, + maAppliedTo // + ); + result = maFastHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + // Slow MA ... + maSlowHandler = iMA( + _Symbol, + _Period, + maSlowLength, + 0, + maMethod, + maAppliedTo // + ); + result = maSlowHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + // SAR ... + sarHandler = iSAR( + _Symbol, + _Period, + sarStep, + sarMax // + ); + result = sarHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + mDrawer = new XCPOIDrawer(); + + // + return result; +} + +/** + * Calculate Custom Buffers ... + * + * @param barIndex: Integer, Represent Current Bar ... + * @param prevCalculated: Integer, Represent Previous Calculated Bars ... + * @param ratesTotal: Integer, Represents All Available Bars ... + * @param open: Double Array, History of Open Prices ... + * @param high: Double Array, History of High Prices ... + * @param close: Double Array, History of Close Prices ... + * @param low: Double Array, History of Low Prices ... + * @param tickVolume: Long, History of Tick Volumes on Bar ... + */ +void CalculateBuffers( + int barIndex, + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + // Calculate Bars Limit and First Bar Index ... + int barsLimit = startCalculationForLastBars > 0 + ? startCalculationForLastBars + : 0; + if (barsLimit == 0) + { + // + barsLimit = ratesTotal; + firstBarIndex = barsLimit - 1; + } + else + { + firstBarIndex = startCalculationForLastBars; + } + + // + // bool canCalculate = true; + bool canCalculate = + barIndex <= barsLimit; + if (canCalculate) + { + // + // Calculate Values ... + CalculateValues( + barIndex, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume // + ); + } + else + { + FillBuffersZero(barIndex); + } +} + +/** + * Fill All Bufers to Zero Vlue for Specified Bar Index ... + * + * @param barIndex: Integer ... + */ +void FillBuffersZero(int barIndex) +{ + // + // TODO: Fill Buffers as Empty ... +} + +/** + * Calculate Values ... + * + * @param barIndex: int, Specified Bar Index ... + * @param prevCalculated: int, Provides Previous Calculated Bars ... + * @param ratesTotal: int, Provides All Availabled Bars ... + * @param open: double Collection, Provides Open Prices Time Series ... + * @param high: double Collection, Provides High Prices Time Series ... + * @param close: double Collection, Provides Close Prices Time Series ... + * @param low: double Collection, Provides Low Prices Time Series ... + * @param tickVolume: long Collection, Provides Ticks Volume Prices Time Series ... + */ +void CalculateValues( + int barIndex, + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + int lastBarIndex = barIndex + 1; + int maxBarIndex = startCalculationForLastBars > 0 + ? startCalculationForLastBars + : ratesTotal; + bool isFirstBar = + startCalculationForLastBars > 0 + ? barIndex == startCalculationForLastBars + : barIndex == firstBarIndex; + + // + // Common Requirements ... + + // + // CYCLES Ranges ... + CalculateCycleRanges( + barIndex, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume // + ); + + // + // PV ... + CalculatePV( + barIndex, + prevCalculated, + ratesTotal, + open, + high, + close, + low, + tickVolume // + ); + + // + // Fast MA ... + double iFastMa = maFastBuffer[barIndex]; + double maFastState = close[barIndex] > iFastMa + ? bullishState + : close[barIndex] < iFastMa + ? bearishState + : neuturalState; + double maFastColor = close[barIndex] > iFastMa + ? bullishColorIDX + : close[barIndex] < iFastMa + ? bearishColorIDX + : neuturalColorIDX; + maFastStateBuffer[barIndex] = maFastState; + maFastColorBuffer[barIndex] = showMAFast + ? maFastColor + : hideColorIDX; + + // + // Slow MA ... + double iSlowMa = maSlowBuffer[barIndex]; + double maSlowState = close[barIndex] > iSlowMa + ? bullishState + : close[barIndex] < iSlowMa + ? bearishState + : neuturalState; + double maSlowColor = close[barIndex] > iSlowMa + ? bullishColorIDX + : close[barIndex] < iSlowMa + ? bearishColorIDX + : neuturalColorIDX; + maSlowStateBuffer[barIndex] = maSlowState; + maSlowColorBuffer[barIndex] = showMASlow + ? maSlowColor + : hideColorIDX; + + // + // SAR ... + double iSar = sarBuffer[barIndex]; + double sarState = low[barIndex] > iSar + ? bullishState + : high[barIndex] < iSar + ? bearishState + : neuturalState; + double sarColor = low[barIndex] > iSar + ? bullishColorIDX + : high[barIndex] < iSar + ? bearishColorIDX + : neuturalColorIDX; + sarStateBuffer[barIndex] = sarState; + sarColorBuffer[barIndex] = showSAR + ? sarColor + : hideColorIDX; + + // + // FIBO Zone ... + + // + double iPeak = peakBuffer[barIndex]; + double iVale = valeBuffer[barIndex]; + + // + double iFiboUp = GetFibonacciLevel( + iPeak, + iVale, + upperZoneLevel, + X_DIRECTION_BULLISH); + + // + double iFiboLo = GetFibonacciLevel( + iPeak, + iVale, + lowerZoneLevel, + X_DIRECTION_BULLISH); + + // + fiboUpperBuffer[barIndex] = iFiboUp; + fiboLowerBuffer[barIndex] = iFiboLo; +} + +// +void CalculatePV( + int barIndex, + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + int lastBarIndex = barIndex + 1; + bool isFirstBar = + startCalculationForLastBars > 0 + ? barIndex == startCalculationForLastBars + : barIndex == firstBarIndex; + + // + double iSHH = sHHBuffer[barIndex]; + double iSLL = sLLBuffer[barIndex]; + + // + double iMHH = mHHBuffer[barIndex]; + double iMLL = mLLBuffer[barIndex]; + + // + double iLHH = lHHBuffer[barIndex]; + double iLLL = lLLBuffer[barIndex]; + + // + double iHHH = hHHBuffer[barIndex]; + double iHLL = hLLBuffer[barIndex]; + + // + // Calculate VALE ... + bool isVale = iSLL == iMLL && + iMLL == iLLL && + iLLL == iHLL; + double iPVale = + isFirstBar + ? emptyValue + : valeBuffer[lastBarIndex]; + double iVale = + isVale + ? iSLL + : iPVale; + valeBuffer[barIndex] = iVale; + + // + // Calculate PEAK ... + bool isPeak = iSHH == iMHH && + iMHH == iLHH && + iLHH == iHHH; + double iPPeak = + isFirstBar + ? emptyValue + : peakBuffer[lastBarIndex]; + double iPeak = + isPeak + ? iSHH + : iPPeak; + peakBuffer[barIndex] = iPeak; +} + +/** + * Calculate Values ... + * + * @param barIndex: int, Specified Bar Index ... + * @param prevCalculated: int, Provides Previous Calculated Bars ... + * @param ratesTotal: int, Provides All Availabled Bars ... + * @param open: double Collection, Provides Open Prices Time Series ... + * @param high: double Collection, Provides High Prices Time Series ... + * @param close: double Collection, Provides Close Prices Time Series ... + * @param low: double Collection, Provides Low Prices Time Series ... + * @param tickVolume: long Collection, Provides Ticks Volume Prices Time Series ... + * + * @return ( int ) + */ +int CalculateZigZag( + int barIndex, + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + int result = 0; + + // + // Define Variables ... + int i = 0; + + // + int start = 0; + int extreme_counter = 0; + int extreme_search = X_ZG_SEARCH_EXTREMUM; + int shift = 0; + int back = 0; + int last_high_pos = 0; + int last_low_pos = 0; + + // + double val = 0; + double res = 0; + double curlow = 0; + double curhigh = 0; + double last_high = 0; + double last_low = 0; + + // + // Initializing ... + if (prevCalculated == 0) + { + // + ArrayInitialize(lowsBuffer, 0); + ArrayInitialize(highsBuffer, 0); + ArrayInitialize(zigzagBuffer, 0); + ArrayInitialize(lowsTimeBuffer, 0); + ArrayInitialize(highsTimeBuffer, 0); + + // + start = zigzagDepth; + } + + // + // Preparing ZigZag Calculation High and Lows ... + + // + if (zigzagLowersCount != zigzagUppersCount || zigzagLowersCount != ratesTotal) + { + // + // Filling Upper ... + zigzagUppersCount = FillPrice( + zigzagUppersMode, + zigzagUppers, + open, + high, + close, + low // + ); + + // + // Filling Lower ... + zigzagLowersCount = FillPrice( + zigzagLowersMode, + zigzagLowers, + open, + high, + close, + low // + ); + } + + // + // Already Calculated Before ... + if (prevCalculated > 0) + { + // + i = ratesTotal - 1; + + // + // Searching for the third X_ZG_SEARCH_EXTREMUM from the last UnComplete Bar ... + while (extreme_counter < zigzagRecalc && i > ratesTotal - 100) + { + // + res = zigzagBuffer[i]; + if (res != 0) + { + extreme_counter++; + } + + // + i--; + } + + // + i++; + start = i; + + // + // What type of X_ZG_SEARCH_EXTREMUM we Search for ... + if (lowsBuffer[i] != 0) + { + // + curlow = lowsBuffer[i]; + extreme_search = X_ZG_SEARCH_PEAK; + } + else + { + // + curhigh = highsBuffer[i]; + extreme_search = X_ZG_SEARCH_VALE; + } + + // + // Clear Values ... + for (i = start + 1; i < ratesTotal && !IsStopped(); i++) + { + // + lowsBuffer[i] = 0; + highsBuffer[i] = 0; + zigzagBuffer[i] = 0; + lowsTimeBuffer[i] = 0; + highsTimeBuffer[i] = 0; + } + } + + // + // Search for High and Low Extremes ... + for (shift = start; shift < ratesTotal && !IsStopped(); shift++) + { + // + // Low ... + val = zigzagLowers[Lowest(zigzagLowers, zigzagDepth, shift)]; + if (val == last_low) + { + val = 0; + } + else + { + // + last_low = val; + + // + if ((zigzagLowers[shift] - val) > zigzagDeviation * _Point) + { + val = 0; + } + else + { + // + for (back = 1; back <= zigzagBackStep; back++) + { + // + res = lowsBuffer[shift - back]; + if ((res != 0) && (res > val)) + { + // + lowsBuffer[shift - back] = 0; + lowsTimeBuffer[shift - back] = 0; + } + } + } + } + + // + if (zigzagLowers[shift] == val) + { + // + lowsBuffer[shift] = val; + lowsTimeBuffer[shift] = GetZigZagBarTime(shift); + } + else + { + // + lowsBuffer[shift] = 0; + lowsTimeBuffer[shift] = 0; + } + + // + // High ... + val = zigzagUppers[Highest(zigzagUppers, zigzagDepth, shift)]; + if (val == last_high) + { + val = 0; + } + else + { + // + last_high = val; + + // + if ((val - zigzagUppers[shift]) > zigzagDeviation * _Point) + { + val = 0; + } + else + { + // + for (back = 1; back <= zigzagBackStep; back++) + { + // + res = highsBuffer[shift - back]; + if ((res != 0) && (res < val)) + { + // + highsBuffer[shift - back] = 0; + highsTimeBuffer[shift - back] = 0; + } + } + } + } + + // + if (zigzagUppers[shift] == val) + { + // + highsBuffer[shift] = val; + highsTimeBuffer[shift] = GetZigZagBarTime(shift); + } + else + { + highsBuffer[shift] = 0; + highsTimeBuffer[shift] = 0; + } + } + + // + // Set Last Value ... + if (extreme_search == 0) // Undefined Values ... + { + // + last_low = 0; + last_high = 0; + } + else + { + // + last_low = curlow; + last_high = curhigh; + } + + // + // Final Selection of Extreme Points for ZigZag ... + for (shift = start; shift < ratesTotal && !IsStopped(); shift++) + { + // + res = 0; + + // + switch (extreme_search) + { + // + case X_ZG_SEARCH_EXTREMUM: + // + if (last_low == 0 && last_high == 0) + { + // + if (highsBuffer[shift] != 0) + { + // + last_high_pos = shift; + last_high = zigzagUppers[shift]; + + // + extreme_search = X_ZG_SEARCH_VALE; + + // + zigzagBuffer[shift] = last_high; + + // + res = 1; + } + + // + if (lowsBuffer[shift] != 0) + { + // + last_low_pos = shift; + last_low = zigzagLowers[shift]; + + // + extreme_search = X_ZG_SEARCH_PEAK; + + // + zigzagBuffer[shift] = last_low; + + // + res = 1; + } + } + break; + + // + case X_ZG_SEARCH_PEAK: + // + if (lowsBuffer[shift] != 0 && lowsBuffer[shift] < last_low && highsBuffer[shift] == 0) + { + // + zigzagBuffer[last_low_pos] = 0; + + // + last_low_pos = shift; + last_low = lowsBuffer[shift]; + + // + zigzagBuffer[shift] = last_low; + + // + res = 1; + } + + // + if (highsBuffer[shift] != 0 && lowsBuffer[shift] == 0) + { + // + last_high_pos = shift; + last_high = highsBuffer[shift]; + + // + zigzagBuffer[shift] = last_high; + + // + extreme_search = X_ZG_SEARCH_VALE; + + // + res = 1; + } + break; + + // + case X_ZG_SEARCH_VALE: + // + if (highsBuffer[shift] != 0 && highsBuffer[shift] > last_high && lowsBuffer[shift] == 0) + { + // + zigzagBuffer[last_high_pos] = 0; + + // + last_high_pos = shift; + last_high = highsBuffer[shift]; + + // + zigzagBuffer[shift] = last_high; + } + + // + if (lowsBuffer[shift] != 0 && highsBuffer[shift] == 0) + { + // + last_low_pos = shift; + last_low = lowsBuffer[shift]; + + // + zigzagBuffer[shift] = last_low; + + // + extreme_search = X_ZG_SEARCH_PEAK; + } + break; + } + } + + // + result = ratesTotal; + + // + return result; +} + +// +void CalculateCycleRanges( + int barIndex, + const int prevCalculated, + const int ratesTotal, + const double &open[], + const double &high[], + const double &close[], + const double &low[], + const long &tickVolume[] // +) +{ + // + // SHORT ... + CalculateCycle( + barIndex, + X_MARKET_CYCLE_SHORT, + sHHBuffer, + sLLBuffer // + ); + + // + // MEDIUM ... + CalculateCycle( + barIndex, + X_MARKET_CYCLE_MEDIUM, + mHHBuffer, + mLLBuffer // + ); + + // + // LONG ... + CalculateCycle( + barIndex, + X_MARKET_CYCLE_LONG, + lHHBuffer, + lLLBuffer // + ); + + // + // HIND ... + CalculateCycle( + barIndex, + X_MARKET_CYCLE_HIND, + hHHBuffer, + hLLBuffer // + ); +} + +/** + * Calculate Specified Market Cycle Info ... + * + * @param barIndex: Integer, Bar Index ... + * @param cycle: ENUM_X_MARKET_CYCLES member, Specified Cycle ... + * @param hhBuffer: Highest High Buffer Reference ... + * @param llBuffer: Lowest Low Buffer Reference ... + */ +void CalculateCycle( + int barIndex, + ENUM_X_MARKET_CYCLES cycle, + double &hhBuffer[], + double &llBuffer[] // +) +{ + // + XOHCL bar; + bool isBarInited = bar.Init( + _Symbol, + _Period, + barIndex + // + ); + if (!isBarInited) + { + return; + } + + // + int mLength = 0; + switch (cycle) + { + // + case X_MARKET_CYCLE_SHORT: + mLength = mSCLength; + break; + + // + case X_MARKET_CYCLE_MEDIUM: + mLength = mMCLength; + break; + + // + case X_MARKET_CYCLE_LONG: + mLength = mLCLength; + break; + + // + case X_MARKET_CYCLE_HIND: + mLength = mHCLength; + break; + } + + // + if (mLength == 0) + { + return; + } + + // + // Find Highest High ... + double hhValue = bar.FindHighest( + mLength, + upperMode // + ); + hhBuffer[barIndex] = hhValue; + + // + // Find Lowest Low ... + double llValue = bar.FindLowest( + mLength, + lowerMode // + ); + llBuffer[barIndex] = llValue; + + // + bar.Clean(); +} + +// +// +// + +// +// Get Specified Bar Time as Double ... +double GetZigZagBarTime(int barIndex) +{ + // + if (barIndex <= 0) + { + barIndex = 0; + } + + // + datetime time = iTime(_Symbol, _Period, barIndex); + + // + double result = (double)((int)time); + + // + return result; +} + +// +// Filling Required Prices Based on MODE ... +int FillPrice( + ENUM_X_PRICE mode, + double &dest[], + const double &open[], + const double &high[], + const double &close[], + const double &low[] // +) +{ + // + int result = 0; + + // + SpecifiedClean(dest); + + // + if (!IsXValid(mode)) + { + return result; + } + + // + switch (mode) + { + // + case X_PRICE_HIGH: + // + result = ArrayCopy( + dest, + high // + ); + break; + + // + case X_PRICE_LOW: + // + result = ArrayCopy( + dest, + low // + ); + break; + + // + case X_PRICE_OPEN: + // + result = ArrayCopy( + dest, + open // + ); + break; + + // + case X_PRICE_CLOSE: + // + result = ArrayCopy( + dest, + close // + ); + break; + + // + default: + // + result = ArrayCopy( + dest, + close // + ); + break; + } + + // + return result; +} + +// +// Search for the index of the highest bar ... +int Highest( + const double &mArray[], + const int mDepth, + const int mStart // +) +{ + // + int result = 0; + + // + if (mStart < 0) + { + return result; + } + + // + double max = mArray[mStart]; + result = mStart; + + // + // Start searching ... + for (int i = mStart - 1; i > mStart - mDepth && i >= 0; i--) + { + // + if (mArray[i] > max) + { + // + result = i; + max = mArray[i]; + } + } + + // + // Return index of the highest bar + return result; +} + +// +// Search for the index of the lowest bar ... +int Lowest( + const double &mArray[], + const int mDepth, + const int mStart // +) +{ + // + int result = 0; + + // + if (mStart < 0) + { + return result; + } + + // + double min = mArray[mStart]; + result = mStart; + + // + // Start searching ... + for (int i = mStart - 1; i > mStart - mDepth && i >= 0; i--) + { + // + if (mArray[i] < min) + { + // + result = i; + min = mArray[i]; + } + } + + // + // Return index of the lowest bar + return result; +} + +// \ No newline at end of file diff --git a/Libraries/x-saherelm.common.extensions.lib.mq5 b/Libraries/x-saherelm.common.extensions.lib.mq5 index 1a4429be..232158c0 100644 --- a/Libraries/x-saherelm.common.extensions.lib.mq5 +++ b/Libraries/x-saherelm.common.extensions.lib.mq5 @@ -6639,6 +6639,75 @@ int GetPriceBoundary( return result; } +/** + * Get Applied Price Buffer ... + * + * @param mType: ENUM_X_PRICE, Specified Price Type ... + * @param dest: double, Holds Destination Prices ... + * @param mOpen: double collection, Open Prices ... + * @param mHigh: double collection, High Prices ... + * @param mLow: double collection, Low Prices ... + * @param mClose: double collection, Close Prices ... + * + * @return ( int ) + */ +int GetAppliedPrice( + ENUM_X_PRICE mType, + double &dest[], + const double &mOpen[], // Open Prices + const double &mHigh[], // High Preices + const double &mLow[], // Low Prices + const double &mClose[] // Close Prices +) +{ + // + int result = 0; + + // + // Prepare ... + SpecifiedClean(dest); + + // + // Check ArraySizes ... + int count = ArraySize(mOpen); + count = MathMin(count, ArraySize(mHigh)); + count = MathMin(count, ArraySize(mClose)); + count = MathMin(count, ArraySize(mLow)); + + // + // Validate ... + if (!IsValidSize(count)) + { + return result; + } + + // + // Loopback ... + for (int i = 0; i < count; i++) + { + // + double iPrice = GetAppliedPrice( + mType, + mOpen[i], + mHigh[i], + mLow[i], + mClose[i] // + ); + + // + Add( + iPrice, + dest // + ); + } + + // + result = ArraySize(dest); + + // + return result; +} + // // END Price ... // diff --git a/Libraries/x-saherelm.x-enums.lib.mq5 b/Libraries/x-saherelm.x-enums.lib.mq5 index 3997e94f..34803914 100644 --- a/Libraries/x-saherelm.x-enums.lib.mq5 +++ b/Libraries/x-saherelm.x-enums.lib.mq5 @@ -63,6 +63,10 @@ bool IsValid(ENUM_X_PRICE value) // return result; } +bool IsXValid(ENUM_X_PRICE value) +{ + return IsValid(value); +} /** * Converts Series Mode to ENUM_X_PRICE ...