From 7c0c48128e0e4c9b6cdc722d4fbaadb5397bfed2 Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Sat, 25 Oct 2025 16:45:25 +0330 Subject: [PATCH] last ... --- Classes/x-saherelm.x-market.pattern.class.mq5 | 490 +++++++++++ Libraries/x-saherelm.x-pivot.analysis.lib.mq5 | 9 + Libraries/x-saherelm.x-poi.extensions.lib.mq5 | 94 +++ Libraries/x-saherelm.x-poi.lib.mq5 | 45 +- .../Classes/x-saherelm.xfima.parser.class.mq5 | 785 ++++++++++++++++++ .../x-saherelm.xfima.signaller.class.mq5 | 10 + 6 files changed, 1416 insertions(+), 17 deletions(-) diff --git a/Classes/x-saherelm.x-market.pattern.class.mq5 b/Classes/x-saherelm.x-market.pattern.class.mq5 index 13dbed0f..cf1bf71e 100644 --- a/Classes/x-saherelm.x-market.pattern.class.mq5 +++ b/Classes/x-saherelm.x-market.pattern.class.mq5 @@ -1660,6 +1660,402 @@ class XCMarketPatternDetector : public XCBase return result; } + /** + * Leg Pattern Detection ... + * + * @param bar: XOHCL, reference to Specified Bar ... + * @param zone: XBoxZone, reference to Holds Detection Zone ... + * @param validationLength: int, leg minimum Validation Length ... + * @param loopback: int, Max Allowed Loopback Length ... + * + * @return ( bool ) + */ + bool IsLegPattern( + XOHCL &bar, + XBoxZone &zone, + int validationLength = 3, + int loopback = 10 //, + // Forces ... + ) + { + // + bool result = false; + + // + // Prepare ... + zone.Clean(); + + // + // Normalize ... + loopback = NormalizeInt(loopback, 5); + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + // Prepare Patterns Analysis Config ... + XPatternAnalysisConfig iPatternsConfig; + iPatternsConfig.Default(); + iPatternsConfig.CleanPatterns(); + iPatternsConfig.AddPattern(X_BAR_PATTERN_LOW); + iPatternsConfig.AddPattern(X_BAR_PATTERN_HIGH); + iPatternsConfig.AddPattern(X_BAR_PATTERN_FLAG); + iPatternsConfig.AddPattern(X_BAR_PATTERN_STAR); + iPatternsConfig.AddPattern(X_BAR_PATTERN_RISING); + iPatternsConfig.AddPattern(X_BAR_PATTERN_PIERCING); + iPatternsConfig.AddPattern(X_BAR_PATTERN_ENGULFED); + iPatternsConfig.AddPattern(X_BAR_PATTERN_MOMENTUM); + iPatternsConfig.AddPattern(X_BAR_PATTERN_SIGNALKEY); + iPatternsConfig.AddPattern(X_BAR_PATTERN_TRUE_GAPED); + + // + XOHCL iBar; + XOHCL pBar; + XOHCL iZBar; + XBoxZone iZone; + XBoxZone jZone; + bool has = false; + XBoxZone supports[]; + XOHCL bullishBars[]; + XOHCL bearishBars[]; + XBoxZone bullishFVGs[]; + XBoxZone bearishFVGs[]; + bool isBullish = false; + bool isBearish = false; + XBoxZone resistances[]; + double bullishPower = 0; + double bearishPower = 0; + int bullishBarsCount = 0; + int bearishBarsCount = 0; + int barIndex = bar.Index(); + int start = barIndex + 1; + XPatternAnalysis iPattern; + int end = start + loopback; + XPatternAnalysis patterns[]; + int bullishPatternsCount = 0; + int bearishPatternsCount = 0; + int sequentialsBullishBarsCount = 0; + int sequentialsBearishBarsCount = 0; + ENUM_X_DIRECTION iDir = X_DIRECTION_NONE; + + // + for (int i = end; i >= start; i--) + { + // + // Initialize Indexed Bar ... + iBar.Clean(); + pBar.Clean(); + result = bar.BarAt(i, iBar); + result = result && + iBar.GetPreviousBar(pBar); + if (!result) + { + break; + } + + // + // Fill Bar Direction ... + isBullish = iBar.IsBullish(); + isBearish = iBar.IsBearish(); + + // + // Directional ... + + // + if (isBullish) + { + // + bullishBarsCount++; + + // + bullishPower += iBar.GetBody(); + bullishPower += iBar.GetLowShadow(); + bullishPower -= iBar.GetHighShadow(); + + // + AddIfNotExists(iBar, bullishBars); + } + + // + if (isBearish) + { + // + bearishBarsCount++; + + // + bearishPower += iBar.GetBody(); + bearishPower -= iBar.GetLowShadow(); + bearishPower += iBar.GetHighShadow(); + + // + AddIfNotExists(iBar, bearishBars); + } + + // + // Sequentail .... + + // + // Bullish ... + if (isBullish) + { + // + if (pBar.IsBullish()) + { + sequentialsBullishBarsCount++; + } + else if (pBar.IsBearish()) + { + sequentialsBullishBarsCount = 0; + } + } + + // + // Bearish ... + if (isBearish) + { + // + if (pBar.IsBearish()) + { + sequentialsBearishBarsCount++; + } + else if (pBar.IsBullish()) + { + sequentialsBearishBarsCount = 0; + } + } + + // + // Detect Patterns ... + iPattern.Clean(); + has = AnalyseBarPatterns(iBar, iPattern, iPatternsConfig); + if (has) + { + // + AddRef(iPattern, patterns); + + // + bullishPatternsCount += iPattern.Count(X_DIRECTION_BULLISH); + bearishPatternsCount += iPattern.Count(X_DIRECTION_BEARISH); + } + + // + // FVG Detection ... + CleanDirection(iDir); + has = HasFVG(iBar, iDir, iZone); + if (has) + { + // + if (iZone.IsBullish()) + { + AddIfNotExists(iZone, bullishFVGs); + } + else + { + AddIfNotExists(iZone, bearishFVGs); + } + } + + // + // Support / Resistance Detection ... + has = HasSupportResistance( + iBar, + iZone, + jZone, + 5 // + ); + if (has) + { + // + if (iZone.IsValid()) + { + AddIfNotExists(iZone, supports); + } + + // + if (jZone.IsValid()) + { + AddIfNotExists(jZone, resistances); + } + } + } + + // + // Summarizing ... + + // + // Detect Direction ... + zone.Clean(); + isBullish = false; + isBearish = false; + CleanDirection(iDir); + + // + isBullish = + // + bullishPower > 0 && + bullishBarsCount > 0 && + bullishPatternsCount > 0 && + sequentialsBullishBarsCount > 0 && + // + bullishPower > bearishPower && + bullishBarsCount > bearishBarsCount && + bullishPatternsCount > bearishPatternsCount && + sequentialsBullishBarsCount > sequentialsBearishBarsCount + // + ; + + // + isBearish = + // + bearishPower > 0 && + bearishBarsCount > 0 && + bearishPatternsCount > 0 && + sequentialsBearishBarsCount > 0 && + // + bearishPower > bullishPower && + bearishBarsCount > bullishBarsCount && + bearishPatternsCount > bullishPatternsCount && + sequentialsBearishBarsCount > sequentialsBullishBarsCount + // + ; + + // + // Validate ... + result = + (isBullish && !isBearish) || + (isBearish && !isBullish); + + // + // PRICE Types ... + ENUM_X_PRICE lowerPriceType = X_PRICE_LOW; + ENUM_X_PRICE upperPriceType = X_PRICE_HIGH; + + // + // Prepare Zone ... + if (result) + { + // + zone.at = bar.time; + zone.to = bar.time; + zone.period = bar.period; + zone.symbol = bar.symbol; + + // + zone.type = ToXString(X_BAR_PATTERN_LEG); + zone.dir = isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + int idx = -1; + if (isBullish) + { + idx = GetOldest(bullishBars); + } + else + { + idx = GetOldest(bearishBars); + } + + // + result = IsValidIndex(idx); + if (result) + { + // + iZBar.Clean(); + if (isBullish) + { + iZBar = bullishBars[idx]; + } + else + { + iZBar = bearishBars[idx]; + } + + // + zone.from = iZBar.time; + + // + iZBar.Clean(); + } + + // + if (isBullish) + { + // + // Prepare Upper and Lower ... + + // + // Upper ... + idx = GetHighestBarPrice(bullishBars, upperPriceType); + if (IsValidIndex(idx)) + { + zone.upper = bullishBars[idx].GetPrice(upperPriceType); + } + + // + // Lower ... + idx = GetLowestBarPrice(bullishBars, upperPriceType); + if (IsValidIndex(idx)) + { + zone.lower = bullishBars[idx].GetPrice(lowerPriceType); + } + } + else + { + // + // Prepare Upper and Lower ... + + // + // Upper ... + idx = GetHighestBarPrice(bearishBars, upperPriceType); + if (IsValidIndex(idx)) + { + zone.upper = bearishBars[idx].GetPrice(upperPriceType); + } + + // + // Lower ... + idx = GetLowestBarPrice(bearishBars, upperPriceType); + if (IsValidIndex(idx)) + { + zone.lower = bearishBars[idx].GetPrice(lowerPriceType); + } + } + + // + result = zone.IsValid(); + } + + // + // Cleanup ... + if (!result) + { + zone.Clean(); + } + iBar.Clean(); + pBar.Clean(); + iZBar.Clean(); + iZone.Clean(); + jZone.Clean(); + iPattern.Clean(); + XClean(supports); + XClean(patterns); + XClean(bullishBars); + XClean(bearishBars); + XClean(bullishFVGs); + XClean(bearishFVGs); + XClean(resistances); + + // + return result; + } + /** * Detect Order Flow ... * @@ -2700,6 +3096,100 @@ class XCMarketPatternDetector : public XCBase return result; } + /** + * Check Specified Bar Has Support or Resistance and Extract them ... + * + * @param bar: XOHCL, reference to Specified Bar ... + * @param support: XBoxZone, reference to holds Detected Support ... + * @param resistance: XBoxZone, reference to holds Detected Resistance ... + * @param validationLength: int, Specified Validation Length ... + * @param loopback: int, Max Allowed Loopback Bars for Detection ... + * + * @return ( bool ) + */ + bool HasSupportResistance( + XOHCL &bar, + XBoxZone &support, + XBoxZone &resistance, + int validationLength = 7, + int loopback = 100 // + ) + { + // + bool result = false; + + // + // Prepare ... + support.Clean(); + resistance.Clean(); + + // + // Normalize ... + loopback = NormalizeInt(loopback, 50); + validationLength = NormalizeInt(validationLength, 3); + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + XOHCL iZBar; + + // + // Support ... + iZBar.Clean(); + bool hasSupport = HasSupport( + bar, + iZBar, + validationLength, + loopback // + ); + if (hasSupport) + { + // + hasSupport = ToSupportBox( + iZBar, + support, + bar.time // + ); + } + + // + // Resistance ... + iZBar.Clean(); + bool hasResistance = HasResistance( + bar, + iZBar, + validationLength, + loopback // + ); + if (hasResistance) + { + // + hasResistance = ToResistanceBox( + iZBar, + resistance, + bar.time // + ); + } + + // + // Summarize Result ... + result = hasSupport || + hasResistance; + + // + // Cleanup ... + iZBar.Clean(); + + // + return result; + } + // // Analysers ... diff --git a/Libraries/x-saherelm.x-pivot.analysis.lib.mq5 b/Libraries/x-saherelm.x-pivot.analysis.lib.mq5 index 98ad2a02..29ae1c11 100644 --- a/Libraries/x-saherelm.x-pivot.analysis.lib.mq5 +++ b/Libraries/x-saherelm.x-pivot.analysis.lib.mq5 @@ -2581,6 +2581,15 @@ struct XPatternAnalysisConfig // // Collection Manipulations ... + /** + * Remove all Allowed Patterns and Directions ... + */ + void CleanPatterns() { + // + XClean(allowedDirs); + XClean(allowedPatterns); + } + /** * Full Detect Patterns ... * diff --git a/Libraries/x-saherelm.x-poi.extensions.lib.mq5 b/Libraries/x-saherelm.x-poi.extensions.lib.mq5 index 97d9ded2..0a93ceb1 100644 --- a/Libraries/x-saherelm.x-poi.extensions.lib.mq5 +++ b/Libraries/x-saherelm.x-poi.extensions.lib.mq5 @@ -652,6 +652,53 @@ int GetHighestByBar( return result; } +/** + * Get Highest Bar Price Index of Specified Collection ... + * + * @param source: reference collection, Provides Data Source ... + * + * @return ( int ) + */ +int GetHighestBarPrice( + XOHCL &source[], + ENUM_X_PRICE priceType // +) +{ + // + int result = -1; + + // + // Validate ... + bool has = HasChild(source) && + IsXValid(priceType); + if (!has) + { + return result; + } + + // + double price = EMPTY_VALUE; + double selected = EMPTY_VALUE; + int count = ArraySize(source); + for (int i = 0; i < count; i++) + { + // + price = source[i].GetPrice(priceType); + has = !NotEmptyZero(selected) + ? true + : price > selected; + if (has) + { + // + result = i; + selected = price; + } + } + + // + return result; +} + /** * Get Highest Index of Specified Collection ... * @@ -903,6 +950,53 @@ int GetLowestByBar( return result; } +/** + * Get Lowest Bar Price Index of Specified Collection ... + * + * @param source: reference collection, Provides Data Source ... + * + * @return ( int ) + */ +int GetLowestBarPrice( + XOHCL &source[], + ENUM_X_PRICE priceType // +) +{ + // + int result = -1; + + // + // Validate ... + bool has = HasChild(source) && + IsXValid(priceType); + if (!has) + { + return result; + } + + // + double price = EMPTY_VALUE; + double selected = EMPTY_VALUE; + int count = ArraySize(source); + for (int i = 0; i < count; i++) + { + // + price = source[i].GetPrice(priceType); + has = !NotEmptyZero(selected) + ? true + : price < selected; + if (has) + { + // + result = i; + selected = price; + } + } + + // + return result; +} + /** * Get Lowest Index of Specified Collection ... * diff --git a/Libraries/x-saherelm.x-poi.lib.mq5 b/Libraries/x-saherelm.x-poi.lib.mq5 index c5723bd6..7c691eab 100644 --- a/Libraries/x-saherelm.x-poi.lib.mq5 +++ b/Libraries/x-saherelm.x-poi.lib.mq5 @@ -51,6 +51,7 @@ enum ENUM_X_BAR_PATTERN X_BAR_PATTERN_RESISTANCE = 15, X_BAR_PATTERN_PULLBACK = 16, X_BAR_PATTERN_CONSOLIDATION = 17, + X_BAR_PATTERN_LEG = 18, }; /** @@ -87,87 +88,92 @@ string ToXString(ENUM_X_BAR_PATTERN value) // case X_BAR_PATTERN_HIGH: - result = "XHIGH"; + result = "XHIGHP"; break; // case X_BAR_PATTERN_LOW: - result = "XLOW"; + result = "XLOWP"; break; // case X_BAR_PATTERN_MOMENTUM: - result = "XMOMENTUM"; + result = "XMOMENTUMP"; break; // case X_BAR_PATTERN_ENGULFED: - result = "XENGULFED"; + result = "XENGULFEDP"; break; // case X_BAR_PATTERN_TRUE_GAPED: - result = "XGAPED"; + result = "XGAPEDP"; break; // case X_BAR_PATTERN_PINNED: - result = "XPINNED"; + result = "XPINNEDP"; break; // case X_BAR_PATTERN_STAR: - result = "XSTAR"; + result = "XSTARP"; break; // case X_BAR_PATTERN_PIERCING: - result = "XPIERCING"; + result = "XPIERCINGP"; break; // case X_BAR_PATTERN_RISING: - result = "XRISING"; + result = "XRISINGP"; break; // case X_BAR_PATTERN_FLAG: - result = "XFLAG"; + result = "XFLAGP"; break; // case X_BAR_PATTERN_SIGNALKEY: - result = "XSIGNALKEY"; + result = "XSIGNALKEYP"; break; // case X_BAR_PATTERN_OB: - result = "XOB"; + result = "XOBP"; break; // case X_BAR_PATTERN_FVG: - result = "XFVG"; + result = "XFVGP"; break; // case X_BAR_PATTERN_SUPPORT: - result = "XSUPPORT"; + result = "XSUPPORTP"; break; // case X_BAR_PATTERN_RESISTANCE: - result = "XRESISTANCE"; + result = "XRESISTANCEP"; break; // case X_BAR_PATTERN_PULLBACK: - result = "XPULLBACK"; + result = "XPULLBACKP"; break; // case X_BAR_PATTERN_CONSOLIDATION: - result = "XCONSOLIDATION"; + result = "XCONSOLIDATIONP"; + break; + + // + case X_BAR_PATTERN_LEG: + result = "XLEGP"; break; } @@ -267,6 +273,10 @@ ENUM_X_BAR_PATTERN ToBarPattern(string value) { result = X_BAR_PATTERN_CONSOLIDATION; } + else if (value == ToXString(X_BAR_PATTERN_LEG)) + { + result = X_BAR_PATTERN_LEG; + } // return result; @@ -302,6 +312,7 @@ int GetAllBarPatters(ENUM_X_BAR_PATTERN &dest[]) Add(X_BAR_PATTERN_RESISTANCE, dest); Add(X_BAR_PATTERN_PULLBACK, dest); Add(X_BAR_PATTERN_CONSOLIDATION, dest); + Add(X_BAR_PATTERN_LEG, dest); // return ArraySize(dest); diff --git a/XFIMAEA/Classes/x-saherelm.xfima.parser.class.mq5 b/XFIMAEA/Classes/x-saherelm.xfima.parser.class.mq5 index 41e24005..329ae440 100644 --- a/XFIMAEA/Classes/x-saherelm.xfima.parser.class.mq5 +++ b/XFIMAEA/Classes/x-saherelm.xfima.parser.class.mq5 @@ -2712,6 +2712,791 @@ class XCXFIMAHelperParser : XCBase return result; } + // + // Boundary Tools ... + // ============================= + // Boundary Includes: + // MA Band ... + // PB Band ... + // HK Band ... + // ATR Band ... + + /** + * Reading Boundary Values ... + * + * @param maBandUpper: double, reference to holds MA Band Upper value ... + * @param maBandLower: double, reference to holds MA Band Lower value ... + * @param pbBandUpper: double, reference to holds PB Band Upper value ... + * @param pbBandLower: double, reference to holds PB Band Lower value ... + * @param hkBandUpper: double, reference to holds HK Band Upper value ... + * @param hkBandLower: double, reference to holds HK Band Lower value ... + * @param atrBandUpper: double, reference to holds ATR Band Upper value ... + * @param atrBandLower: double, reference to holds ATR Band Lower value ... + * @param barIndex: int, Specified Bar Index ... + */ + void GetBoundaryValues( + double &maBandUpper, + double &maBandLower, + double &pbBandUpper, + double &pbBandLower, + double &hkBandUpper, + double &hkBandLower, + double &atrBandUpper, + double &atrBandLower, + int barIndex = 0 // + ) + { + // + // Normalize ... + barIndex = NormalizeBarIndex(barIndex); + + // + // Prepare ... + maBandUpper = EMPTY_VALUE; + maBandLower = EMPTY_VALUE; + pbBandUpper = EMPTY_VALUE; + pbBandLower = EMPTY_VALUE; + hkBandUpper = EMPTY_VALUE; + hkBandLower = EMPTY_VALUE; + atrBandUpper = EMPTY_VALUE; + atrBandLower = EMPTY_VALUE; + + // + // Validate ... + bool has = IsValid(); + if (!has) + { + return; + } + + // + maBandUpper = helper.GetMABandUpper(barIndex); + maBandLower = helper.GetMABandLower(barIndex); + pbBandUpper = helper.GetPBBandUpper(barIndex); + pbBandLower = helper.GetPBBandLower(barIndex); + hkBandUpper = helper.GetHKBandUpper(barIndex); + hkBandLower = helper.GetHKBandLower(barIndex); + atrBandUpper = helper.GetATRBandUpper(barIndex); + atrBandLower = helper.GetATRBandLower(barIndex); + } + + /** + * Read Boundary Values and Fill as an Array ... + * + * @param values: double, collection reference to fill results ... + * @param barIndex: int, Specified Bar Index ... + */ + void GetBoundaryValuesArray( + double &values[], + int barIndex = 0 // + ) + { + // + // Prepare ... + XClean(values); + + // + // Normalize ... + barIndex = NormalizeBarIndex(barIndex); + + // + // Validate ... + bool has = IsValid(); + if (!has) + { + return; + } + + // + // Reading Boundary Values ... + + // + double maBandUpper = EMPTY_VALUE; + double maBandLower = EMPTY_VALUE; + double pbBandUpper = EMPTY_VALUE; + double pbBandLower = EMPTY_VALUE; + double hkBandUpper = EMPTY_VALUE; + double hkBandLower = EMPTY_VALUE; + double atrBandUpper = EMPTY_VALUE; + double atrBandLower = EMPTY_VALUE; + + // + GetBoundaryValues( + maBandUpper, + maBandLower, + pbBandUpper, + pbBandLower, + hkBandUpper, + hkBandLower, + atrBandUpper, + atrBandLower, + barIndex // + ); + + // + // Validate ... + has = + NotEmptyZero(maBandUpper) && + NotEmptyZero(maBandLower) && + NotEmptyZero(pbBandUpper) && + NotEmptyZero(pbBandLower) && + NotEmptyZero(hkBandUpper) && + NotEmptyZero(hkBandLower) && + NotEmptyZero(atrBandUpper) && + NotEmptyZero(atrBandLower); + if (!has) + { + return; + } + + // + Add(maBandUpper, values); + Add(maBandLower, values); + Add(pbBandUpper, values); + Add(pbBandLower, values); + Add(hkBandUpper, values); + Add(hkBandLower, values); + Add(atrBandUpper, values); + Add(atrBandLower, values); + } + + /** + * Read Boundary Min Value ... + * + * @param barIndex: int, Specified Bar Index ... + * + * @return ( double ) + */ + double GetBoundaryMin(int barIndex = 0) + { + // + double result = EMPTY_VALUE; + + // + // Normalize ... + barIndex = NormalizeBarIndex(barIndex); + + // + // Validate ... + bool has = IsValid(); + if (!has) + { + return result; + } + + // + double values[]; + GetBoundaryValuesArray(values, barIndex); + result = GetMax(values); + + // + return result; + } + + /** + * Read Boundary Max Value ... + * + * @param barIndex: int, Specified BAr Index ... + * + * @return ( double ) + */ + double GetBoundaryMax(int barIndex = 0) + { + // + double result = EMPTY_VALUE; + + // + // Normalize ... + barIndex = NormalizeBarIndex(barIndex); + + // + // Validate ... + bool has = IsValid(); + if (!has) + { + return result; + } + + // + double values[]; + GetBoundaryValuesArray(values, barIndex); + result = GetMin(values); + + // + return result; + } + + // + // Bars and Boundary ... + + /** + * Check Bar's Price is Over Boundary Max or not ... + * + * @param barIndex: int, Specified Bar Index ... + * @param priceType: ENUM_X_PRICE, Specified Price Type ... + * + * @return ( bool ) + */ + bool IsBarOverBoundaryMax( + int barIndex = 0, + ENUM_X_PRICE priceType = X_PRICE_HIGH // + ) + { + // + bool result = false; + + // + // Normalize ... + barIndex = NormalizeBarIndex(barIndex); + + // + // Validate ... + result = IsValid() && + IsXValid(priceType); + if (!result) + { + return result; + } + + // + XOHCL bar; + double price = EMPTY_VALUE; + double value = GetBoundaryMax(barIndex); + result = bar.Init(symbol, period, barIndex); + if (result) + { + price = bar.GetPrice(priceType); + } + result = bar.IsValid() && + NotEmptyZero(price) && + NotEmptyZero(value) && + price > value; + + // + // Cleanup ... + bar.Clean(); + + // + return result; + } + + /** + * Check Bar's Price is Over Boundary Min or not ... + * + * @param barIndex: int, Specified Bar Index ... + * @param priceType: ENUM_X_PRICE, Specified Price Type ... + * + * @return ( bool ) + */ + bool IsBarOverBoundaryMin( + int barIndex = 0, + ENUM_X_PRICE priceType = X_PRICE_LOW // + ) + { + // + bool result = false; + + // + // Normalize ... + barIndex = NormalizeBarIndex(barIndex); + + // + // Validate ... + result = IsValid() && + IsXValid(priceType); + if (!result) + { + return result; + } + + // + XOHCL bar; + double price = EMPTY_VALUE; + double value = GetBoundaryMin(barIndex); + result = bar.Init(symbol, period, barIndex); + if (result) + { + price = bar.GetPrice(priceType); + } + result = bar.IsValid() && + NotEmptyZero(price) && + NotEmptyZero(value) && + price > value; + + // + // Cleanup ... + bar.Clean(); + + // + return result; + } + + /** + * Check Bar's Price is Under Boundary Max or not ... + * + * @param barIndex: int, Specified Bar Index ... + * @param priceType: ENUM_X_PRICE, Specified Price Type ... + * + * @return ( bool ) + */ + bool IsBarUnderBoundaryMax( + int barIndex = 0, + ENUM_X_PRICE priceType = X_PRICE_HIGH // + ) + { + // + bool result = false; + + // + // Normalize ... + barIndex = NormalizeBarIndex(barIndex); + + // + // Validate ... + result = IsValid() && + IsXValid(priceType); + if (!result) + { + return result; + } + + // + XOHCL bar; + double price = EMPTY_VALUE; + double value = GetBoundaryMax(barIndex); + result = bar.Init(symbol, period, barIndex); + if (result) + { + price = bar.GetPrice(priceType); + } + result = bar.IsValid() && + NotEmptyZero(price) && + NotEmptyZero(value) && + price < value; + + // + // Cleanup ... + bar.Clean(); + + // + return result; + } + + /** + * Check Bar's Price is Under Boundary Min or not ... + * + * @param barIndex: int, Specified Bar Index ... + * @param priceType: ENUM_X_PRICE, Specified Price Type ... + * + * @return ( bool ) + */ + bool IsBarUnderBoundaryMin( + int barIndex = 0, + ENUM_X_PRICE priceType = X_PRICE_LOW // + ) + { + // + bool result = false; + + // + // Normalize ... + barIndex = NormalizeBarIndex(barIndex); + + // + // Validate ... + result = IsValid() && + IsXValid(priceType); + if (!result) + { + return result; + } + + // + XOHCL bar; + double price = EMPTY_VALUE; + double value = GetBoundaryMin(barIndex); + result = bar.Init(symbol, period, barIndex); + if (result) + { + price = bar.GetPrice(priceType); + } + result = bar.IsValid() && + NotEmptyZero(price) && + NotEmptyZero(value) && + price < value; + + // + // Cleanup ... + bar.Clean(); + + // + return result; + } + + /** + * Check Bar's Price is Crossed Over Boundary Max or not ... + * + * @param barIndex: int, Specified Bar Index ... + * @param priceType: ENUM_X_PRICE, Specified Price Type ... + * + * @return ( bool ) + */ + bool IsBarCrossedOverBoundaryMax( + int barIndex = 0, + ENUM_X_PRICE priceType = X_PRICE_HIGH // + ) + { + // + bool result = false; + + // + // Normalize ... + barIndex = NormalizeBarIndex(barIndex); + + // + // Validate ... + result = IsValid() && + IsXValid(priceType); + if (!result) + { + return result; + } + + // + bool isC = IsBarOverBoundaryMax(barIndex, priceType); + bool isP = IsBarOverBoundaryMax(barIndex + 1, priceType); + + // + result = isC && !isP; + + // + return result; + } + + /** + * Check Bar's Price is Crossed Over Boundary Min or not ... + * + * @param barIndex: int, Specified Bar Index ... + * @param priceType: ENUM_X_PRICE, Specified Price Type ... + * + * @return ( bool ) + */ + bool IsBarCrossedOverBoundaryMin( + int barIndex = 0, + ENUM_X_PRICE priceType = X_PRICE_LOW // + ) + { + // + bool result = false; + + // + // Normalize ... + barIndex = NormalizeBarIndex(barIndex); + + // + // Validate ... + result = IsValid() && + IsXValid(priceType); + if (!result) + { + return result; + } + + // + bool isC = IsBarOverBoundaryMin(barIndex, priceType); + bool isP = IsBarOverBoundaryMin(barIndex + 1, priceType); + + // + result = isC && !isP; + + // + return result; + } + + /** + * Check Bar's Price is Crossed Under Boundary Max or not ... + * + * @param barIndex: int, Specified Bar Index ... + * @param priceType: ENUM_X_PRICE, Specified Price Type ... + * + * @return ( bool ) + */ + bool IsBarCrossedUnderBoundaryMax( + int barIndex = 0, + ENUM_X_PRICE priceType = X_PRICE_HIGH // + ) + { + // + bool result = false; + + // + // Normalize ... + barIndex = NormalizeBarIndex(barIndex); + + // + // Validate ... + result = IsValid() && + IsXValid(priceType); + if (!result) + { + return result; + } + + // + bool isC = IsBarUnderBoundaryMax(barIndex, priceType); + bool isP = IsBarUnderBoundaryMax(barIndex + 1, priceType); + + // + result = isC && !isP; + + // + return result; + } + + /** + * Check Bar's Price is Crossed Under Boundary Min or not ... + * + * @param barIndex: int, Specified Bar Index ... + * @param priceType: ENUM_X_PRICE, Specified Price Type ... + * + * @return ( bool ) + */ + bool IsBarCrossedUnderBoundaryMin( + int barIndex = 0, + ENUM_X_PRICE priceType = X_PRICE_LOW // + ) + { + // + bool result = false; + + // + // Normalize ... + barIndex = NormalizeBarIndex(barIndex); + + // + // Validate ... + result = IsValid() && + IsXValid(priceType); + if (!result) + { + return result; + } + + // + bool isC = IsBarUnderBoundaryMin(barIndex, priceType); + bool isP = IsBarUnderBoundaryMin(barIndex + 1, priceType); + + // + result = isC && !isP; + + // + return result; + } + + /** + * Count Over Boundary Max Bar's Prices ... + * + * @param barIndex: int, Specified Bar Index ... + * @param priceType: ENUM_X_PRICE, Specified Price Type ... + * @param loopback: int, Max Allowed Loopback Length ... + * + * @return ( int ) + */ + int CountBarsOverBoundaryMax( + int barIndex = 0, + ENUM_X_PRICE priceType = X_PRICE_HIGH, + int loopback = 500 // + ) + { + // + int result = 0; + + // + // Normalize ... + loopback = NormalizeInt(loopback, 50); + barIndex = NormalizeBarIndex(barIndex); + + // + // Validate ... + bool has = IsValid() && + IsXValid(priceType); + if (!result) + { + return result; + } + + // + // Do ... + int idx = barIndex; + while (idx < barIndex + loopback) + { + // + idx++; + has = IsBarOverBoundaryMax(idx); + if (!has) + { + break; + } + result++; + } + + // + return result; + } + + /** + * Count Over Boundary Min Bar's Prices ... + * + * @param barIndex: int, Specified Bar Index ... + * @param priceType: ENUM_X_PRICE, Specified Price Type ... + * @param loopback: int, Max Allowed Loopback Length ... + * + * @return ( int ) + */ + int CountBarsOverBoundaryMin( + int barIndex = 0, + ENUM_X_PRICE priceType = X_PRICE_LOW, + int loopback = 500 // + ) + { + // + int result = 0; + + // + // Normalize ... + loopback = NormalizeInt(loopback, 50); + barIndex = NormalizeBarIndex(barIndex); + + // + // Validate ... + bool has = IsValid() && + IsXValid(priceType); + if (!result) + { + return result; + } + + // + // Do ... + int idx = barIndex; + while (idx < barIndex + loopback) + { + // + idx++; + has = IsBarOverBoundaryMin(idx); + if (!has) + { + break; + } + result++; + } + + // + return result; + } + + /** + * Count Under Boundary Max Bar's Prices ... + * + * @param barIndex: int, Specified Bar Index ... + * @param priceType: ENUM_X_PRICE, Specified Price Type ... + * @param loopback: int, Max Allowed Loopback Length ... + * + * @return ( int ) + */ + int CountBarsUnderBoundaryMax( + int barIndex = 0, + ENUM_X_PRICE priceType = X_PRICE_HIGH, + int loopback = 500 // + ) + { + // + int result = 0; + + // + // Normalize ... + loopback = NormalizeInt(loopback, 50); + barIndex = NormalizeBarIndex(barIndex); + + // + // Validate ... + bool has = IsValid() && + IsXValid(priceType); + if (!result) + { + return result; + } + + // + // Do ... + int idx = barIndex; + while (idx < barIndex + loopback) + { + // + idx++; + has = IsBarUnderBoundaryMax(idx); + if (!has) + { + break; + } + result++; + } + + // + return result; + } + + /** + * Count Under Boundary Min Bar's Prices ... + * + * @param barIndex: int, Specified Bar Index ... + * @param priceType: ENUM_X_PRICE, Specified Price Type ... + * @param loopback: int, Max Allowed Loopback Length ... + * + * @return ( int ) + */ + int CountBarsUnderBoundaryMin( + int barIndex = 0, + ENUM_X_PRICE priceType = X_PRICE_LOW, + int loopback = 500 // + ) + { + // + int result = 0; + + // + // Normalize ... + loopback = NormalizeInt(loopback, 50); + barIndex = NormalizeBarIndex(barIndex); + + // + // Validate ... + bool has = IsValid() && + IsXValid(priceType); + if (!result) + { + return result; + } + + // + // Do ... + int idx = barIndex; + while (idx < barIndex + loopback) + { + // + idx++; + has = IsBarUnderBoundaryMin(idx); + if (!has) + { + break; + } + result++; + } + + // + return result; + } + // // Protected ... protected: diff --git a/XFIMAEA/Classes/x-saherelm.xfima.signaller.class.mq5 b/XFIMAEA/Classes/x-saherelm.xfima.signaller.class.mq5 index a52dfbc8..798544f0 100644 --- a/XFIMAEA/Classes/x-saherelm.xfima.signaller.class.mq5 +++ b/XFIMAEA/Classes/x-saherelm.xfima.signaller.class.mq5 @@ -1941,6 +1941,16 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller Print("OrderFlow ..."); } + // + XBoxZone legZone; + result = poiDetector.IsLegPattern(pBar, legZone); + if (result) + { + // + poiDrawer.DrawZone(legZone, structureDrawConfig.drawConfig); + Print("Leg Pattern Detected ..."); + } + // isBullish = //