From a185fb3c8ac3b66ea87db7e9559e4d3d2bfe278f Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Sat, 4 Oct 2025 16:12:32 +0330 Subject: [PATCH] last ... --- Classes/x-saherelm.x-market.pattern.class.mq5 | 155 +++- Helpers/x-saherelm.xfima.helper.mq5 | 527 ++++++++++++- Indicators/test-xpv.ind.mq5 | 690 ++++++++++++++++++ Indicators/x-saherelm.xfima.mq5 | 4 +- .../x-saherelm.xfima.signaller.class.mq5 | 75 +- 5 files changed, 1429 insertions(+), 22 deletions(-) create mode 100644 Indicators/test-xpv.ind.mq5 diff --git a/Classes/x-saherelm.x-market.pattern.class.mq5 b/Classes/x-saherelm.x-market.pattern.class.mq5 index b8060f56..596a4955 100644 --- a/Classes/x-saherelm.x-market.pattern.class.mq5 +++ b/Classes/x-saherelm.x-market.pattern.class.mq5 @@ -232,6 +232,159 @@ class XCMarketPatternDetector : public XCBase // // Detectors ... + bool IsPeak( + XOHCL &bar, + int validationLength = 7 // + ) { + // + bool result = false; + + // + // Normalize ... + validationLength = NormalizeInt(validationLength, 2); + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + // Define Requirements ... + result = bar.FindHighest(validationLength, MODE_HIGH) <= bar.high; + + // + return result; + } + + bool IsVale( + XOHCL &bar, + int validationLength = 7 // + ) { + // + bool result = false; + + // + // Normalize ... + validationLength = NormalizeInt(validationLength, 2); + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + // Define Requirements ... + result = bar.FindLowest(validationLength, MODE_LOW) >= bar.low; + + // + return result; + } + + /** + * Check Specified Bar is Peak or Vale ... + * + * @param bar: XOHCL, Specified Bar ... + * @param dir: ENUM_X_DIRECTION a reference for Direction ... + * @param validationLength: int, Validation Length ... + * + * @return ( bool ) + */ + bool IsPV( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + int validationLength = 7 // + ) + { + // + bool result = false; + + // + // Prepare ... + CleanDirection(dir); + + // + // Normalize ... + validationLength = NormalizeInt(validationLength, 2); + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + // Define Requirements ... + XOHCL iBar; + bool isPeak = true; + bool isVale = true; + int start = bar.Index(); + int end = start + validationLength; + for (int i = start; i < end; i++) + { + // + iBar.Clean(); + result = bar.BarAt(i, iBar); + if (!result) + { + // + isVale = false; + isPeak = false; + + // + break; + } + + // + isPeak = + isPeak && + iBar.high <= bar.high; + + // + isVale = + isVale && + iBar.low >= bar.low; + + // + if (!isPeak && !isVale) + { + break; + } + } + + // + result = + (isPeak && !isVale) || + (isVale && !isPeak); + if (!result) + { + return result; + } + + // + dir = isVale + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + // Get Result ... + result = HasDirection(dir); + + // + // Cleanup Resources ... + iBar.Clean(); + + // + return result; + } + /** * Check Specified Bar is Momentum Bar or not ... * @@ -1886,7 +2039,7 @@ class XCMarketPatternDetector : public XCBase /** * Check Zones and Manage them ... - * + * * @param forBar: XOHCL, reference to Specified Bar ... * @param zones: XBoxZone, reference to Specified Zone Collection ... * @param sortBy: X_SORT_BY_DATE, Sort Zones by ... diff --git a/Helpers/x-saherelm.xfima.helper.mq5 b/Helpers/x-saherelm.xfima.helper.mq5 index c40b73de..838810df 100644 --- a/Helpers/x-saherelm.xfima.helper.mq5 +++ b/Helpers/x-saherelm.xfima.helper.mq5 @@ -23,6 +23,7 @@ // // Imports ... #include "../Classes/x-saherelm.x-helper.class.mq5" +#include "../Classes/x-saherelm.x-market.pattern.class.mq5" #include "../Libraries/x-saherelm.x-poi.extensions.lib.mq5" #include "../Libraries/x-saherelm.x-poi.lib.mq5" @@ -488,18 +489,23 @@ class XCXFIMAHelper : public XCBaseHelper public: // // Props ... + XCMarketPatternDetector *patternDetector; // // Constructors ... XCXFIMAHelper() : XCBaseHelper(_Symbol, _Period) { + patternDetector = new XCMarketPatternDetector(); } // // Deconstructor ... ~XCXFIMAHelper() { + // + delete patternDetector; + ZeroMemory(patternDetector); } // @@ -1519,6 +1525,98 @@ class XCXFIMAHelper : public XCBaseHelper return result; } + bool GetBoundaryValues( + double &min, + double &max, + int barIndex = 0 // + ) + { + // + bool result = false; + + // + // Prepare ... + min = EMPTY_VALUE; + max = EMPTY_VALUE; + + // + // Normalize ... + barIndex = NormalizeBarIndex(barIndex); + + // + // Validate ... + result = IsValid(); + if (!result) + { + return result; + } + + // + double fast = GetMAFast(barIndex); + double slow = GetMASlow(barIndex); + + // + double maBondUpper = GetMABondUpper(barIndex); + double maBondLower = GetMABondLower(barIndex); + + // + double pbBondUpper = GetPBBondUpper(barIndex); + double pbBondLower = GetPBBondLower(barIndex); + + // + double hkBondUpper = GetHKBondUpper(barIndex); + double hkBondLower = GetHKBondLower(barIndex); + + // + double fiboUpper = GetFiboUpper(barIndex); + double fiboLower = GetFiboLower(barIndex); + double fiboMiddle = GetFiboMiddle(barIndex); + + // + result = + NotEmptyZero(fast) && + NotEmptyZero(slow) && + NotEmptyZero(fiboLower) && + NotEmptyZero(fiboUpper) && + NotEmptyZero(fiboMiddle) && + NotEmptyZero(maBondUpper) && + NotEmptyZero(maBondLower) && + NotEmptyZero(pbBondUpper) && + NotEmptyZero(pbBondLower) && + NotEmptyZero(hkBondUpper) && + NotEmptyZero(hkBondLower); + if (!result) + { + return result; + } + + // + double values[11] = { + fast, + slow, + fiboLower, + fiboUpper, + fiboMiddle, + maBondUpper, + maBondLower, + pbBondUpper, + pbBondLower, + hkBondUpper, + hkBondLower // + }; + min = GetMin(values); + max = GetMax(values); + + // + result = + NotEmptyZero(min) && + NotEmptyZero(max) && + min < max; + + // + return result; + } + // // Tools ... @@ -2956,8 +3054,11 @@ class XCXFIMAHelper : public XCBaseHelper * * @param zones: XBoxZone, reference to Collection for holding Detected Zones ... * @param barIndex: int, Specified Start Looking Bar Index ... + * @param onlyValidZones: bool, Only Validation Zones ... * @param requiredNumberOfZones: int, Specified how many zones looking for ... * @param shadowMultiplier: double, a valid zone's Shadow side multiplier ... + * @param validationStrength: double, Validation Strength ... + * @param validationLength: int, Validation Length ... * @param maxAllowedLoopbackLength: int, Specified Max Allowed Looping back trhough Bars for Detection ... * * @return ( int ) @@ -2968,6 +3069,7 @@ class XCXFIMAHelper : public XCBaseHelper bool onlyValidZones = false, int requiredNumberOfZones = 50, double shadowMultiplier = 4, + double validationStrength = 1, int validationLength = 7, int maxAllowedLoopbackLength = 1500 // ) @@ -2984,6 +3086,7 @@ class XCXFIMAHelper : public XCBaseHelper barIndex = NormalizeBarIndex(barIndex); validationLength = NormalizeInt(validationLength, 3); shadowMultiplier = NormalizeDouble(shadowMultiplier, 2); + validationStrength = NormalizeDouble(validationStrength, 1); requiredNumberOfZones = NormalizeInt(requiredNumberOfZones, 5); maxAllowedLoopbackLength = NormalizeInt(maxAllowedLoopbackLength, 50); @@ -3101,7 +3204,7 @@ class XCXFIMAHelper : public XCBaseHelper ? iBar.low : iBar.GetUp(); iBox.type = - (isBullish ? "XFIMSup" : "XFIMARes") + "_" + + (isBullish ? "XFIMA_Support" : "XFIMA_Resistance") + "_" + ToXString(NormalizePrice(iBox.upper, iBox.symbol)) + "_" + ToXString(NormalizePrice(iBox.lower, iBox.symbol)); @@ -3148,7 +3251,45 @@ class XCXFIMAHelper : public XCBaseHelper // // Validate Zone Length ... has = iBox.IsValid() && + (validationStrength >= 1 + ? iBox.GetRange() >= validationStrength * GetPoints(iBox.symbol) + : true) && (iBox.FromIndex() - iBox.AtIndex() >= validationLength); + + // + // Validate Zone State ... + if (has) + { + // + // Cleanup Bar ... + iBar.Clean(); + + // + // Loopingh through At Index ... + for (int i = iBox.ToIndex(); i < iBox.AtIndex(); i++) + { + // + // Initialized Indexed Bar ... + has = bar.BarAt(i, iBar); + if (!has) + { + break; + } + + // + // Validate Bar ... + has = + iBox.IsBullish() + ? iBar.low > iBox.lower + : iBar.high < iBox.upper; + if (!has) + { + break; + } + } + } + + // if (has) { // @@ -3174,6 +3315,7 @@ class XCXFIMAHelper : public XCBaseHelper { XClean(zones); } + bar.Clean(); iBar.Clean(); iBox.Clean(); @@ -3181,6 +3323,389 @@ class XCXFIMAHelper : public XCBaseHelper return result; } + int DetecteXFIMAPivots( + XPivot &pivots[], + int barIndex = 0, + int requiredNumberOfPivots = 50, + int validationLength = 7, + int maxAllowedLoopbackLength = 1500, // + // + // PV ... + int pvValidationLength = 7, + // + // Momentum ... + int momentumBarValidationLength = 3, + double momentumBarApprovedMultiplier = 3, + // + // TrueGap ... + double trueGapApprovedStrength = 2, + // + // Pin ... + double pinBarShadowApprovedMultiplier = 3, + double pinBarRangeMultiplier = 4, + bool pinBarForceDirection = false, + // + // Flag ... + int flagPatternPullbackLength = 3 // + ) + { + // + int result = 0; + + // + // Prepare ... + XClean(pivots); + + // + // Normalize ... + barIndex = NormalizeBarIndex(barIndex); + validationLength = NormalizeInt(validationLength, 1); + requiredNumberOfPivots = NormalizeInt(requiredNumberOfPivots, 5); + maxAllowedLoopbackLength = NormalizeInt(maxAllowedLoopbackLength, 50); + + // + pvValidationLength = NormalizeInt(pvValidationLength, 2); + + // + momentumBarValidationLength = NormalizeInt(momentumBarValidationLength, 2); + momentumBarApprovedMultiplier = NormalizeDouble(momentumBarApprovedMultiplier, 1); + + // + trueGapApprovedStrength = NormalizeDouble(trueGapApprovedStrength, 1); + + // + pinBarRangeMultiplier = NormalizeDouble(pinBarRangeMultiplier, 4); + pinBarShadowApprovedMultiplier = NormalizeDouble(pinBarShadowApprovedMultiplier, 3); + + // + flagPatternPullbackLength = NormalizeInt(flagPatternPullbackLength, 3); + + // + // Validate ... + bool has = IsValid(); + if (!has) + { + return result; + } + + // + XOHCL iBar; + XOHCL tmpBar; + XPivot iPivot; + string iPrefix = NULL; + ENUM_X_DIRECTION iDir; + int idx = barIndex - 1; + double iMin = EMPTY_VALUE; + double iMax = EMPTY_VALUE; + double iValue = EMPTY_VALUE; + ENUM_X_PIVOT_TYPE iType = X_PIVOT_TYPE_NONE; + int end = barIndex + maxAllowedLoopbackLength; + while ( + idx < end && + ArraySize(pivots) < requiredNumberOfPivots) + { + // + idx++; + + // + iBar.Clean(); + iPivot.Clean(); + tmpBar.Clean(); + iPrefix = NULL; + iDir = X_DIRECTION_NONE; + + // + has = iBar.Init( + mSymbol, + mPeriod, + idx // + ); + if (!has) + { + break; + } + + // + // Pivots List ... + + // + // PV ... + has = patternDetector.IsPV( + iBar, + iDir, + pvValidationLength // + ); + if (has) + { + // + iPrefix = + IsXBullish(iDir) + ? "XLow" + : "XHigh"; + } + + // + // Momentum Bar ... + if (!has) + { + // + has = patternDetector.IsMomentumBar( + iBar, + iDir, + momentumBarValidationLength, + momentumBarApprovedMultiplier // + ); + if (has) + { + iPrefix = "XMomentum"; + } + } + + // + // Engulf Bar ... + if (!has) + { + // + has = patternDetector.IsEngulfedBar( + iBar, + iDir // + ); + if (has) + { + iPrefix = "XEngulfed"; + } + } + + // + // True Gap ... + if (!has) + { + // + has = patternDetector.IsTrueGapedBar( + iBar, + iDir, + trueGapApprovedStrength // + ); + if (has) + { + iPrefix = "XTrueGap"; + } + } + + // + // Pin Bar ... + if (!has) + { + // + has = patternDetector.IsPinnedBar( + iBar, + iDir, + pinBarShadowApprovedMultiplier, + pinBarRangeMultiplier, + pinBarForceDirection // + ); + if (has) + { + iPrefix = "XPinned"; + } + } + + // + // Patterns ... + + // + // Star Pattern ... + if (!has) + { + // + has = patternDetector.IsStartPattern( + iBar, + iDir // + ); + if (has) + { + iPrefix = "XStar"; + } + } + + // + // Piercing Pattern ... + if (!has) + { + // + has = patternDetector.IsPiercingPattern( + iBar, + iDir // + ); + if (has) + { + iPrefix = "XPiercing"; + } + } + + // + // Rising Pattern ... + if (!has) + { + // + has = patternDetector.IsRisingPattern( + iBar, + iDir // + ); + if (has) + { + iPrefix = "XRising"; + } + } + + // + // Flag Pattern ... + if (!has) + { + // + has = patternDetector.IsFlagPattern( + iBar, + iDir, + tmpBar, + flagPatternPullbackLength // + ); + if (has) + { + iPrefix = "XFlag"; + } + } + + // + // Signal Key Pattern ... + if (!has) + { + // + has = patternDetector.IsSignalKeyBarPattern( + iBar, + iDir, + pinBarShadowApprovedMultiplier, + pinBarRangeMultiplier, + pinBarForceDirection // + ); + if (has) + { + iPrefix = "XSignalKey"; + } + } + + // + if (!has) + { + continue; + } + + // // + // // Validate Pivot Length ... + // // Validate Pivot vs XFIMA Values ... + // for (int i = iBar.Index(); i < iBar.Index() + validationLength; i++) + // { + // // + // tmpBar.Clean(); + // has = iBar.BarAt(i, tmpBar); + // if (!has) + // { + // break; + // } + + // // + // iMin = EMPTY_VALUE; + // iMax = EMPTY_VALUE; + // has = GetBoundaryValues( + // iMin, + // iMax, + // i // + // ); + + // // + // // Validate Bar vs TmpBar and Also Boundary Values ... + // has = + // has && + // (IsXBullish(iDir) + // ? + // // tmpBar.low < iMin && + // (tmpBar.low > iBar.low || + // tmpBar.GetDown() || iBar.GetDown()) + // : + // // tmpBar.high > iMax && + // (tmpBar.high < iBar.high || + // tmpBar.GetUp() < iBar.GetUp())); + // if (!has) + // { + // break; + // } + + // // + // iValue = IsXBullish(iDir) + // ? iBar.low + // : iBar.high; + + // // + // iType = IsXBullish(iDir) + // ? X_PIVOT_TYPE_VALE + // : X_PIVOT_TYPE_PEAK; + + // // + // tmpBar.Clean(); + // } + + // + has = IsXValid(iPrefix); + if (has) + { + // + iValue = IsXBullish(iDir) + ? iBar.low + : iBar.high; + + // + iType = IsXBullish(iDir) + ? X_PIVOT_TYPE_VALE + : X_PIVOT_TYPE_PEAK; + + // + // Preparing Pivot ... + has = iPivot.Init( + iValue, + iBar.time, + iBar.symbol, + iDir, + iBar.period, + iType // + ); + if (has) + { + // + iPivot.prefix = iPrefix; + + // + AddIfNotExists( + iPivot, + pivots // + ); + } + } + + // + } + + // + // Cleanup Resources ... + iBar.Clean(); + iPivot.Clean(); + tmpBar.Clean(); + + // + result = ArraySize(pivots); + + // + return result; + } + // // Values Retrievers ... diff --git a/Indicators/test-xpv.ind.mq5 b/Indicators/test-xpv.ind.mq5 new file mode 100644 index 00000000..8328ff85 --- /dev/null +++ b/Indicators/test-xpv.ind.mq5 @@ -0,0 +1,690 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// ------------------------------------------------- +// Name: XFIMAPV +// 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 icon "../Images/SaherElm_Logo_Color.ico" +#property strict + +// +// Definitions ... + +// +#define ShortName "XFIMA" + +// +// Imports ... +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// Inputs ... + +// +// Calculation ... +input group "Calculation"; +input int pvValidationLength = 7; // Peaks and Vales Validation Length +input int pvValidationCount = 2; // Recent Peak or Vale must under/over latests +input ENUM_X_PRICE peakPriceType = X_PRICE_HIGH; // Peak Calculated Price +input ENUM_X_PRICE valePriceType = X_PRICE_LOW; // Vale Calculated Price + +// +// Presentation ... +input group "Presentation"; +input bool showPV = true; // Show Peaks and Vales +input bool showHL = true; // Show Highs and Lows +input int startCalculationForLastBars = 1500; // Calculate Last n Bars +input int peakArrowCode = 159; // Peaks Arrow Code +input int highArrowCode = 159; // Highs Arrow Code +input int valeArrowCode = 159; // Vales Arrow Code +input int lowArrowCode = 159; // Lows 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 6 +#property indicator_plots 4 + +// +// Plot Buffers ... + +// +// PEAKS ... + +// +#define peakBufferIndex 0 +double peakBuffer[]; + +// +#define peakBufferPlotIndex 0 +#property indicator_label1 "PEAK" +#property indicator_type1 DRAW_ARROW +#property indicator_color1 clrMagenta +#property indicator_width1 3 + +// +// VALES ... + +// +#define valeBufferIndex 1 +double valeBuffer[]; + +// +#define valeBufferPlotIndex 1 +#property indicator_label2 "VALE" +#property indicator_type2 DRAW_ARROW +#property indicator_color2 clrAqua +#property indicator_width2 3 + +// +// HIGHS ... + +// +#define highBufferIndex 2 +double highBuffer[]; + +// +#define highBufferPlotIndex 2 +#property indicator_label3 "HIGH" +#property indicator_type3 DRAW_ARROW +#property indicator_color3 clrOrangeRed +#property indicator_width3 3 + +// +// LOWS ... + +// +#define lowBufferIndex 3 +double lowBuffer[]; + +// +#define lowBufferPlotIndex 3 +#property indicator_label4 "LOW" +#property indicator_type4 DRAW_ARROW +#property indicator_color4 clrYellow +#property indicator_width4 3 + +// +// Data Buffers ... + +// +#define mLastBufferIndex 3 + +// +#define highRawBufferIndex mLastBufferIndex + 1 +double highRawBuffer[]; + +// +#define lowRawBufferIndex mLastBufferIndex + 2 +double lowRawBuffer[]; + +// +// Variables ... + +// +int limit; + +// +int maxLength; + +// +int firstBarIndex; + +// +// 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 ... + 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 + + // + // De Initialize all Handlers and etc ... +} + +/** + * 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[] // +) +{ + // + // 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; + + // + // Buffers Copy ... + + // + // 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 = + // + IsXValid(peakPriceType) && + IsXValid(valePriceType) && + NotEmptyZero(pvValidationLength) + // + ; + + // + return result; +} + +/** + * Extract Max Length of Inputs ... + * + * @return ( int ) + */ +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + result = MathMax(result, pvValidationLength); + + // + return result; +} + +/** + * Define Required Buffers ... + */ +void DefineBuffers() +{ + // + // Plot Buffers ... + + // + // PV ... + + // + 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); + + // + // HL ... + + // + ENUM_DRAW_TYPE hlDrawType = showHL ? DRAW_ARROW : DRAW_NONE; + + // + // HIGH ... + + // + ArraySetAsSeries(highBuffer, true); + SetIndexBuffer(highBufferIndex, highBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(highBufferPlotIndex, PLOT_SHOW_DATA, showHL); + PlotIndexSetInteger(highBufferPlotIndex, PLOT_DRAW_TYPE, hlDrawType); + + // + PlotIndexSetDouble(highBufferPlotIndex, PLOT_EMPTY_VALUE, emptyValue); + PlotIndexSetInteger(highBufferPlotIndex, PLOT_ARROW, highArrowCode); + + // + // LOW ... + + // + ArraySetAsSeries(lowBuffer, true); + SetIndexBuffer(lowBufferIndex, lowBuffer, INDICATOR_DATA); + + // + PlotIndexSetInteger(lowBufferPlotIndex, PLOT_SHOW_DATA, showHL); + PlotIndexSetInteger(lowBufferPlotIndex, PLOT_DRAW_TYPE, hlDrawType); + + // + PlotIndexSetDouble(lowBufferPlotIndex, PLOT_EMPTY_VALUE, emptyValue); + PlotIndexSetInteger(lowBufferPlotIndex, PLOT_ARROW, lowArrowCode); + + // + // Data Buffers ... + + // + ArraySetAsSeries(lowRawBuffer, true); + SetIndexBuffer(lowRawBufferIndex, lowRawBuffer, INDICATOR_DATA); + + // + ArraySetAsSeries(highRawBuffer, true); + SetIndexBuffer(highRawBufferIndex, highRawBuffer, INDICATOR_DATA); +} + +/** + * Initial all Indicator Requirements ... + * + * @return ( false ) + * + */ +bool InitRequirements() +{ + // + bool result = true; + + // + // Handlers ... + + // + 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 ... + lowBuffer[barIndex] = emptyValue; + highBuffer[barIndex] = emptyValue; + peakBuffer[barIndex] = emptyValue; + valeBuffer[barIndex] = emptyValue; + highRawBuffer[barIndex] = emptyValue; + lowRawBuffer[barIndex] = emptyValue; +} + +/** + * 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[] // +) +{ + // + // Common Requirements ... + + // + int lastBarIndex = barIndex + 1; + int maxBarIndex = startCalculationForLastBars > 0 + ? startCalculationForLastBars + : ratesTotal; + + // + bool isFirstBar = + startCalculationForLastBars > 0 + ? barIndex == startCalculationForLastBars + : barIndex == firstBarIndex; + + // + // Calculate Highs and Lows ... + double iLow = IsLow(barIndex); + double iHigh = IsHigh(barIndex); +} + +// +// Calculator Functions ... + +bool IsLow( + double &value, + int barIndex // +) { + // + bool result = false; + + // + // Prepare ... + value = emptyValue; + + // + XOHCL iBar; + result = iBar.Init( + _Symbol, + _Period, + barIndex // + ); + if (!result) { + // + iBar.Clean(); + return result; + } + + // + value = iBar.FindXLowest(pvValidationLength, peakPriceType); + result = value >= iBar.low; + if (!result) { + // + iBar.Clean(); + value = emptyValue; + return result; + } + + // + // Cleanup Resources ... + iBar.Clean(); + + // + return result; +} + +bool IsHigh( + double &value, + int barIndex // +) { + // + bool result = false; + + // + // Prepare ... + value = emptyValue; + + // + XOHCL iBar; + result = iBar.Init( + _Symbol, + _Period, + barIndex // + ); + if (!result) { + // + iBar.Clean(); + return result; + } + + // + value = iBar.FindXHighest(pvValidationLength, valePriceType); + result = value <= iBar.high; + if (!result) { + // + iBar.Clean(); + value = emptyValue; + return result; + } + + // + // Cleanup Resources ... + iBar.Clean(); + + // + return result; +} + +// \ No newline at end of file diff --git a/Indicators/x-saherelm.xfima.mq5 b/Indicators/x-saherelm.xfima.mq5 index 0cb7e44a..e085725c 100644 --- a/Indicators/x-saherelm.xfima.mq5 +++ b/Indicators/x-saherelm.xfima.mq5 @@ -287,10 +287,10 @@ double zigzagBuffer[]; // #define maBondUpperBufferIndex 12 -#define maBondUpperBufferPlotIndex 9 double maBondUpperBuffer[]; // +#define maBondUpperBufferPlotIndex 9 #property indicator_label10 "UpperMA" #property indicator_type10 DRAW_LINE #property indicator_color10 clrLime @@ -301,10 +301,10 @@ double maBondUpperBuffer[]; // #define maBondLowerBufferIndex 13 -#define maBondLowerBufferPlotIndex 10 double maBondLowerBuffer[]; // +#define maBondLowerBufferPlotIndex 10 #property indicator_label11 "LowerMA" #property indicator_type11 DRAW_LINE #property indicator_color11 clrRed diff --git a/XFIMAEA/Classes/x-saherelm.xfima.signaller.class.mq5 b/XFIMAEA/Classes/x-saherelm.xfima.signaller.class.mq5 index 0d2bdaa3..70f09ed9 100644 --- a/XFIMAEA/Classes/x-saherelm.xfima.signaller.class.mq5 +++ b/XFIMAEA/Classes/x-saherelm.xfima.signaller.class.mq5 @@ -450,6 +450,8 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller public: // // Props ... + CArrayObj zoneObjects; + CArrayObj pivotObjects; XFIMAPatternDetectorConfig analyserConfig; // @@ -654,32 +656,69 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller // // // has = fimaHelper.HasFiboPush(iDir, iBar.Index(), 5); + // // + // XBoxZone fimaZones[]; + // int fimaZonesCount = fimaHelper.DetectXFIMAZones( + // fimaZones, + // iBar.Index(), + // true, // Only Valid Zones ... + // 50, // Number of Zones ... + // 4, // Shadow Multiplier ... + // 1, // Strength ... + // 7, // Validation Length ... + // 500 // Loopback .. + // ); + // - XBoxZone fimaZones[]; - int fimaZonesCount = fimaHelper.DetectXFIMAZones( - fimaZones, + XPivot fimaPivots[]; + int fimaPivotsCount = fimaHelper.DetecteXFIMAPivots( + fimaPivots, iBar.Index(), - true, // Only Valid Zones ... - 50, // Number of Zones ... - 5, // Shadow Multiplier ... - 500 // Loopback + 50, // Number of Pivots ... + 7, // Validation Length ... + 500 // Loopback ... ); - has = IsValidSize(fimaZonesCount); + + // // + // has = IsValidSize(fimaZonesCount); + // if (has) + // { + // // + // // Draw Detected Zones ... + // for (int i = 0; i < fimaZonesCount; i++) + // { + // // + // XCBoxObject *iObj; + // has = poiDrawer.DrawBox( + // fimaZones[i], + // iObj, + // true, // Ignore At ... + // fimaZones[i].type // Specified Name ... + // ); + // if (has) + // { + // zoneObjects.Add(iObj); + // } + // } + // } + + // + has = IsValidSize(fimaPivotsCount); if (has) { // - // Draw Detected Zones ... - CArrayObj zoneObjects; - for (int i = 0; i < fimaZonesCount; i++) + // Draw Detected Pivots ... + for (int i = 0; i < fimaPivotsCount; i++) { // - XCBoxObject *iObj; - has = poiDrawer.DrawBox( - fimaZones[i], - iObj, - false, // Ignore At ... - fimaZones[i].type // Specified Name ... - ); + XCBarArrowObject *iObj; + has = poiDrawer.DrawPivot( + fimaPivots[i], + iObj); + if (has) + { + pivotObjects.Add(iObj); + } } }