From d24610c47b304abfc2bd7f6b25bfce7e83a605aa Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Wed, 15 Oct 2025 13:24:34 +0330 Subject: [PATCH] last ... --- Classes/x-saherelm.x-market.pattern.class.mq5 | 339 ++++ Helpers/x-saherelm.xfima.helper.mq5 | 1585 +++++++++++++---- .../x-saherelm.common.extensions.lib.mq5 | 157 ++ .../x-saherelm.xfima.signaller.class.mq5 | 246 ++- 4 files changed, 1981 insertions(+), 346 deletions(-) diff --git a/Classes/x-saherelm.x-market.pattern.class.mq5 b/Classes/x-saherelm.x-market.pattern.class.mq5 index ddd9f2e7..64f1c37d 100644 --- a/Classes/x-saherelm.x-market.pattern.class.mq5 +++ b/Classes/x-saherelm.x-market.pattern.class.mq5 @@ -3519,6 +3519,345 @@ class XCMarketPatternDetector : public XCBase return result; } + int CollectOBs( + XOHCL &bar, + XBoxZone &dest[], + int zonesLoopback = 5, + int maxRequiredZone = 0, + int loopback = 100 // + ) + { + // + int result = 0; + + // + // Prepare ... + XClean(dest); + + // + // Normalize ... + loopback = NormalizeInt(loopback, 10); + zonesLoopback = NormalizeInt(zonesLoopback, 3); + maxRequiredZone = NormalizeInt(maxRequiredZone, 0); + + // + // Validate ... + bool has = bar.IsValid(); + if (!has) + { + return result; + } + + // + XOHCL iBar; + XBoxZone iBox; + ENUM_X_DIRECTION iDir; + int start = bar.Index(); + int end = start + loopback; + for (int i = start; i < end; i++) + { + // + iBar.Clean(); + iBox.Clean(); + iDir = X_DIRECTION_NONE; + + // + has = bar.BarAt(i, iBar); + has = has && + HasOB(iBar, iDir, iBox, zonesLoopback); + if (has) + { + // + AddIfNotExists( + iBox, + dest // + ); + } + + // + has = maxRequiredZone <= 0 || + (maxRequiredZone > 0 && ArraySize(dest) < maxRequiredZone); + if (!has) + { + break; + } + } + + // + result = ArraySize(dest); + + // + // Cleanup ... + iBar.Clean(); + iBox.Clean(); + iDir = X_DIRECTION_NONE; + + // + return result; + } + + int CollectFVGs( + XOHCL &bar, + XBoxZone &dest[], + int zonesLoopback = 5, + int maxRequiredZone = 0, + int loopback = 100 // + ) + { + // + int result = 0; + + // + // Prepare ... + XClean(dest); + + // + // Normalize ... + loopback = NormalizeInt(loopback, 10); + zonesLoopback = NormalizeInt(zonesLoopback, 3); + maxRequiredZone = NormalizeInt(maxRequiredZone, 0); + + // + // Validate ... + bool has = bar.IsValid(); + if (!has) + { + return result; + } + + // + XOHCL iBar; + XBoxZone iBox; + ENUM_X_DIRECTION iDir; + int start = bar.Index(); + int end = start + loopback; + for (int i = start; i < end; i++) + { + // + iBar.Clean(); + iBox.Clean(); + iDir = X_DIRECTION_NONE; + + // + has = bar.BarAt(i, iBar); + has = has && + HasFVG(iBar, iDir, iBox, zonesLoopback); + if (has) + { + // + AddIfNotExists( + iBox, + dest // + ); + } + + // + has = maxRequiredZone <= 0 || + (maxRequiredZone > 0 && ArraySize(dest) < maxRequiredZone); + if (!has) + { + break; + } + } + + // + result = ArraySize(dest); + + // + // Cleanup ... + iBar.Clean(); + iBox.Clean(); + iDir = X_DIRECTION_NONE; + + // + return result; + } + + int CollectZones( + XOHCL &bar, + XBoxZone &dest[], + int zonesLoopback = 5, + int zonesValidationLength = 21, + int maxRequiredZone = 0, + int loopback = 100 // + ) + { + // + int result = 0; + + // + // Prepare ... + XClean(dest); + + // + // Normalize ... + loopback = NormalizeInt(loopback, 10); + zonesLoopback = NormalizeInt(zonesLoopback, 3); + maxRequiredZone = NormalizeInt(maxRequiredZone, 0); + zonesValidationLength = NormalizeInt(zonesValidationLength, 3); + + // + // Validate ... + bool has = bar.IsValid(); + if (!has) + { + return result; + } + + // + XOHCL iBar; + XBoxZone iBox; + XOHCL iZoneBar; + int start = bar.Index(); + int end = start + loopback; + for (int i = start; i < end; i++) + { + // + iBar.Clean(); + iBox.Clean(); + iZoneBar.Clean(); + + // + has = bar.BarAt(i, iBar); + if (!has) + { + continue; + } + + // + // Support ... + has = HasSupport(iBar, iZoneBar, zonesValidationLength, zonesLoopback); + if (has) + { + // + has = ToSupportBox(iZoneBar, iBox, bar.time, zonesValidationLength); + if (has) + { + // + AddIfNotExists( + iBox, + dest // + ); + } + } + + // + // Resistance ... + has = HasResistance(iBar, iZoneBar, zonesValidationLength, zonesLoopback); + if (has) + { + // + has = ToResistanceBox(iZoneBar, iBox, bar.time, zonesValidationLength); + if (has) + { + // + AddIfNotExists( + iBox, + dest // + ); + } + } + + // + has = maxRequiredZone <= 0 || + (maxRequiredZone > 0 && ArraySize(dest) < maxRequiredZone); + if (!has) + { + break; + } + } + + // + result = ArraySize(dest); + + // + // Cleanup ... + iBar.Clean(); + iBox.Clean(); + iZoneBar.Clean(); + + // + return result; + } + + int FilterZones( + XOHCL &bar, + XBoxZone &source[], + ENUM_X_DIRECTION filterDir, + ENUM_X_PRICE priceType = X_PRICE_CLOSE, + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE // + ) + { + // + int result = 0; + + // + // Prepare ... + XBoxZone tmp[]; + Copy( + source, + tmp // + ); + XClean(source); + + // + // Validate ... + bool has = bar.IsValid() && + HasChild(tmp) && + IsXValid(priceType) && + HasDirection(filterDir); + if (!has) + { + // + XClean(tmp); + return result; + } + + // + XBoxZone iBox; + double price = bar.GetPrice(priceType); + bool isBullish = IsXBullish(filterDir); + while (HasChild(tmp)) + { + // + iBox = tmp[0]; + ArrayRemove(tmp, 0, 1); + + // + has = + // + // Direction Pass ... + (!HasDirection(forDir) + ? true + : forDir == iBox.dir) + // + && + // + // Price Pass ... + (isBullish + ? price > iBox.lower + : price < iBox.upper); + if (has) + { + AddIfNotExists(iBox, source); + } + + // + iBox.Clean(); + } + + // + result = ArraySize(source); + + // + // Cleanup ... + XClean(tmp); + iBox.Clean(); + + // + return result; + } + // // Protected ... protected: diff --git a/Helpers/x-saherelm.xfima.helper.mq5 b/Helpers/x-saherelm.xfima.helper.mq5 index 84dfe5b3..a6155eec 100644 --- a/Helpers/x-saherelm.xfima.helper.mq5 +++ b/Helpers/x-saherelm.xfima.helper.mq5 @@ -1129,321 +1129,6 @@ class XCXFIMAHelper : public XCBaseHelper return result; } - /** - * Check Specified Bar has HK Switch or not ... - * - * @param dir: reference for holds cross Direction ... - * @param barIndex: int, Specified Bar Index ... - * - * @return ( bool ) - */ - bool HasHKSwitch( - ENUM_X_DIRECTION &dir, - int barIndex = 0 // - ) - { - // - bool result = false; - - // - // Prepare ... - dir = X_DIRECTION_NONE; - - // - // Normalize ... - barIndex = NormalizeInt(barIndex, 0); - - // - double open[]; - int openCount = CopyHKOpen(barIndex, 2, open); - - // - double close[]; - int closeCount = CopyHKClose(barIndex, 2, close); - - // - bool isBullish = false; - bool isBearish = false; - - // - // Validate Readed Values ... - int count = MathMin(openCount, closeCount); - result = IsValidSize(count) && count >= 2; - if (result) - { - // - // Detect Direction Change ... - - // - bool notEmpty = - NotEmptyZero(open[0]) && - NotEmptyZero(open[1]) && - NotEmptyZero(close[0]) && - NotEmptyZero(close[1]); - - // - isBullish = - notEmpty && - open[0] < close[0] && - open[1] > close[1]; - - // - isBearish = - notEmpty && - open[0] > close[0] && - open[1] < close[1]; - - // - result = - isBullish || - isBearish; - } - - // - if (result) - { - // - // Setting Direction ... - dir = - isBullish - ? X_DIRECTION_BULLISH - : isBearish - ? X_DIRECTION_BEARISH - : X_DIRECTION_NONE; - } - - // - // Cleanup Resources ... - XClean(open); - XClean(close); - - // - return result; - } - - /** - * Check Specified Bar has HK Bond Based Trend or not ... - * - * @param dir: ENUM_X_DIRECTION, reference to holds trend direction, if exists ... - * @param barIndex: int, Specified Bar Index ... - * @param validationLength: int, validation of trend ... - * - * @return ( bool ) - */ - bool HasHKBasedTrend( - ENUM_X_DIRECTION &dir, - int barIndex = 0, - int validationLength = 5 // - ) - { - // - bool result = false; - - // - // Prepare ... - dir = X_DIRECTION_NONE; - - // - // Normalize ... - barIndex = NormalizeBarIndex(barIndex); - validationLength = NormalizeInt(validationLength, 1); - - // - // Validate ... - result = IsValid(); - if (!result) - { - return result; - } - - // - // Do ... - - // - // Define Requirements ... - XOHCL iBar; - double hkUpper; - double hkLower; - bool has = false; - int bullishCount = 0; - int bearishCount = 0; - bool isBullish = false; - bool isBearish = false; - - // - // Count Bullish/Bearish Directions ... - int start = barIndex + 1; - int end = start + validationLength; - for (int i = start; i < end; i++) - { - // - // Reading Requirements ... - - // - // Read Indexed Bar ... - iBar.Clean(); - result = iBar.Init( - mSymbol, - mPeriod, - i // - ); - if (!result) - { - break; - } - - // - // Reading Values ... - hkUpper = GetHKBondUpper(i); - hkLower = GetHKBondLower(i); - result = NotEmptyZero(hkUpper) && - NotEmptyZero(hkLower); - if (!result) - { - return result; - } - - // - // Check Trend ... - - // - // Bullish ... - isBullish = iBar.low > hkLower; - if (isBullish) - { - bullishCount++; - } - - // - // Bearish ... - isBearish = iBar.high < hkUpper; - if (isBearish) - { - bearishCount++; - } - - // - iBar.Clean(); - - // - } - - // - // Validate Results ... - isBullish = - bullishCount >= validationLength; - isBearish = - bearishCount >= validationLength; - - // - result = (isBullish && !isBearish) || - (isBearish && !isBullish); - - // - // Setting Direction if Has Trend ... - if (result) - { - // - dir = isBullish - ? X_DIRECTION_BULLISH - : X_DIRECTION_BEARISH; - } - - // - // Cleanup ... - iBar.Clean(); - - // - return result; - } - - /** - * Check Specified Bar has HK Bond Based Trend Switch or not ... - * - * @param dir: ENUM_X_DIRECTION, reference to holds trend direction, if exists ... - * @param barIndex: int, Specified Bar Index ... - * @param validationLength: int, validation of trend ... - * - * @return ( bool ) - */ - bool IsHKBasedTrendSwitch( - ENUM_X_DIRECTION &dir, - int barIndex = 0, - int validationLength = 5 // - ) - { - // - bool result = false; - - // - // Prepare ... - dir = X_DIRECTION_NONE; - - // - // Normalize ... - barIndex = NormalizeBarIndex(barIndex); - validationLength = NormalizeInt(validationLength, 1); - - // - // Validate ... - result = IsValid(); - if (!result) - { - return result; - } - - // - // Do ... - - // - bool hasTrend = HasHKBasedTrend( - dir, - barIndex, - validationLength // - ); - bool isBullish = hasTrend && - IsXBullish(dir); - bool isBearish = hasTrend && - IsXBearish(dir); - - // - bool hasPTrend = HasHKBasedTrend( - dir, - barIndex + 1, - validationLength // - ); - bool isPBullish = hasPTrend && - IsXBullish(dir); - bool isPBearish = hasPTrend && - IsXBearish(dir); - - // - dir = X_DIRECTION_NONE; - - // - // Checking Result ... - isBullish = isBullish && !isPBullish; - isBearish = isBearish && !isPBearish; - - // - result = - (isBullish && !isBearish) || - (isBearish && !isBullish); - if (result) - { - // - dir = isBullish - ? X_DIRECTION_BULLISH - : X_DIRECTION_BEARISH; - } - - // - // Cleanup ... - - // - return result; - } - /** * Check Specified Bar has SAR Switch or not ... * @@ -3074,15 +2759,1277 @@ class XCXFIMAHelper : public XCBaseHelper return result; } + // + // HK ... + + /** + * Check Specified Bar has HK Switch or not ... + * + * @param dir: reference for holds cross Direction ... + * @param barIndex: int, Specified Bar Index ... + * + * @return ( bool ) + */ + bool HasHKSwitch( + ENUM_X_DIRECTION &dir, + int barIndex = 0 // + ) + { + // + bool result = false; + + // + // Prepare ... + dir = X_DIRECTION_NONE; + + // + // Normalize ... + barIndex = NormalizeInt(barIndex, 0); + + // + double open[]; + int openCount = CopyHKOpen(barIndex, 2, open); + + // + double close[]; + int closeCount = CopyHKClose(barIndex, 2, close); + + // + bool isBullish = false; + bool isBearish = false; + + // + // Validate Readed Values ... + int count = MathMin(openCount, closeCount); + result = IsValidSize(count) && count >= 2; + if (result) + { + // + // Detect Direction Change ... + + // + bool notEmpty = + NotEmptyZero(open[0]) && + NotEmptyZero(open[1]) && + NotEmptyZero(close[0]) && + NotEmptyZero(close[1]); + + // + isBullish = + notEmpty && + open[0] < close[0] && + open[1] > close[1]; + + // + isBearish = + notEmpty && + open[0] > close[0] && + open[1] < close[1]; + + // + result = + isBullish || + isBearish; + } + + // + if (result) + { + // + // Setting Direction ... + dir = + isBullish + ? X_DIRECTION_BULLISH + : isBearish + ? X_DIRECTION_BEARISH + : X_DIRECTION_NONE; + } + + // + // Cleanup Resources ... + XClean(open); + XClean(close); + + // + return result; + } + + /** + * Check Specified Bar has HK Bond Based Trend or not ... + * + * @param dir: ENUM_X_DIRECTION, reference to holds trend direction, if exists ... + * @param barIndex: int, Specified Bar Index ... + * @param validationLength: int, validation of trend ... + * + * @return ( bool ) + */ + bool HasHKBasedTrend( + ENUM_X_DIRECTION &dir, + int barIndex = 0, + int validationLength = 5 // + ) + { + // + bool result = false; + + // + // Prepare ... + dir = X_DIRECTION_NONE; + + // + // Normalize ... + barIndex = NormalizeBarIndex(barIndex); + validationLength = NormalizeInt(validationLength, 1); + + // + // Validate ... + result = IsValid(); + if (!result) + { + return result; + } + + // + // Do ... + + // + // Define Requirements ... + XOHCL iBar; + double hkUpper; + double hkLower; + bool has = false; + int bullishCount = 0; + int bearishCount = 0; + bool isBullish = false; + bool isBearish = false; + + // + // Count Bullish/Bearish Directions ... + int start = barIndex + 1; + int end = start + validationLength; + for (int i = start; i < end; i++) + { + // + // Reading Requirements ... + + // + // Read Indexed Bar ... + iBar.Clean(); + result = iBar.Init( + mSymbol, + mPeriod, + i // + ); + if (!result) + { + break; + } + + // + // Reading Values ... + hkUpper = GetHKBondUpper(i); + hkLower = GetHKBondLower(i); + result = NotEmptyZero(hkUpper) && + NotEmptyZero(hkLower); + if (!result) + { + return result; + } + + // + // Check Trend ... + + // + // Bullish ... + isBullish = iBar.low > hkLower; + if (isBullish) + { + bullishCount++; + } + + // + // Bearish ... + isBearish = iBar.high < hkUpper; + if (isBearish) + { + bearishCount++; + } + + // + iBar.Clean(); + + // + } + + // + // Validate Results ... + isBullish = + bullishCount >= validationLength; + isBearish = + bearishCount >= validationLength; + + // + result = (isBullish && !isBearish) || + (isBearish && !isBullish); + + // + // Setting Direction if Has Trend ... + if (result) + { + // + dir = isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + } + + // + // Cleanup ... + iBar.Clean(); + + // + return result; + } + + /** + * Check Specified Bar has HK Bond Based Trend Switch or not ... + * + * @param dir: ENUM_X_DIRECTION, reference to holds trend direction, if exists ... + * @param barIndex: int, Specified Bar Index ... + * @param validationLength: int, validation of trend ... + * + * @return ( bool ) + */ + bool IsHKBasedTrendSwitch( + ENUM_X_DIRECTION &dir, + int barIndex = 0, + int validationLength = 5 // + ) + { + // + bool result = false; + + // + // Prepare ... + dir = X_DIRECTION_NONE; + + // + // Normalize ... + barIndex = NormalizeBarIndex(barIndex); + validationLength = NormalizeInt(validationLength, 1); + + // + // Validate ... + result = IsValid(); + if (!result) + { + return result; + } + + // + // Do ... + + // + bool hasTrend = HasHKBasedTrend( + dir, + barIndex, + validationLength // + ); + bool isBullish = hasTrend && + IsXBullish(dir); + bool isBearish = hasTrend && + IsXBearish(dir); + + // + bool hasPTrend = HasHKBasedTrend( + dir, + barIndex + 1, + validationLength // + ); + bool isPBullish = hasPTrend && + IsXBullish(dir); + bool isPBearish = hasPTrend && + IsXBearish(dir); + + // + dir = X_DIRECTION_NONE; + + // + // Checking Result ... + isBullish = isBullish && !isPBullish; + isBearish = isBearish && !isPBearish; + + // + result = + (isBullish && !isBearish) || + (isBearish && !isBullish); + if (result) + { + // + dir = isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + } + + // + // Cleanup ... + + // + return result; + } + + /** + * Check if Price Over HK Bond Upper or not ... + * + * @param priceType: ENUM_X_PRICE, Specified Price type ... + * @param barIndex: int, Specified Bar index ... + * + * @return ( bool ) + */ + bool IsOverHKBondUpper( + ENUM_X_PRICE priceType = X_PRICE_LOW, + int barIndex = 0 // + ) + { + // + bool result = false; + + // + // Normalize ... + barIndex = NormalizeBarIndex(barIndex); + + // + // Validate ... + result = IsValid() && + IsXValid(priceType); + if (!result) + { + return result; + } + + // + // Do ... + + // + XOHCL bar; + result = bar.Init(mSymbol, mPeriod, barIndex); + if (!result) + { + // + bar.Clean(); + return result; + } + + // + double price = bar.GetPrice(priceType); + double value = GetHKBondUpper(barIndex); + result = NotEmptyZero(price) && + NotEmptyZero(value) && + price > value; + + // + // Cleanup ... + bar.Clean(); + + // + return result; + } + + /** + * Check if Price Over HK Bond Lower or not ... + * + * @param priceType: ENUM_X_PRICE, Specified Price type ... + * @param barIndex: int, Specified Bar index ... + * + * @return ( bool ) + */ + bool IsOverHKBondLower( + ENUM_X_PRICE priceType = X_PRICE_LOW, + int barIndex = 0 // + ) + { + // + bool result = false; + + // + // Normalize ... + barIndex = NormalizeBarIndex(barIndex); + + // + // Validate ... + result = IsValid() && + IsXValid(priceType); + if (!result) + { + return result; + } + + // + // Do ... + + // + XOHCL bar; + result = bar.Init(mSymbol, mPeriod, barIndex); + if (!result) + { + // + bar.Clean(); + return result; + } + + // + double price = bar.GetPrice(priceType); + double value = GetHKBondLower(barIndex); + result = NotEmptyZero(price) && + NotEmptyZero(value) && + price > value; + + // + // Cleanup ... + bar.Clean(); + + // + return result; + } + + /** + * Check if Price Under HK Bond Upper or not ... + * + * @param priceType: ENUM_X_PRICE, Specified Price type ... + * @param barIndex: int, Specified Bar index ... + * + * @return ( bool ) + */ + bool IsUnderHKBondUpper( + ENUM_X_PRICE priceType = X_PRICE_HIGH, + int barIndex = 0 // + ) + { + // + bool result = false; + + // + // Normalize ... + barIndex = NormalizeBarIndex(barIndex); + + // + // Validate ... + result = IsValid() && + IsXValid(priceType); + if (!result) + { + return result; + } + + // + // Do ... + + // + XOHCL bar; + result = bar.Init(mSymbol, mPeriod, barIndex); + if (!result) + { + // + bar.Clean(); + return result; + } + + // + double price = bar.GetPrice(priceType); + double value = GetHKBondUpper(barIndex); + result = NotEmptyZero(price) && + NotEmptyZero(value) && + price < value; + + // + // Cleanup ... + bar.Clean(); + + // + return result; + } + + /** + * Check if Price Under HK Bond Lower or not ... + * + * @param priceType: ENUM_X_PRICE, Specified Price type ... + * @param barIndex: int, Specified Bar index ... + * + * @return ( bool ) + */ + bool IsUnderHKBondLower( + ENUM_X_PRICE priceType = X_PRICE_HIGH, + int barIndex = 0 // + ) + { + // + bool result = false; + + // + // Normalize ... + barIndex = NormalizeBarIndex(barIndex); + + // + // Validate ... + result = IsValid() && + IsXValid(priceType); + if (!result) + { + return result; + } + + // + // Do ... + + // + XOHCL bar; + result = bar.Init(mSymbol, mPeriod, barIndex); + if (!result) + { + // + bar.Clean(); + return result; + } + + // + double price = bar.GetPrice(priceType); + double value = GetHKBondLower(barIndex); + result = NotEmptyZero(price) && + NotEmptyZero(value) && + price < value; + + // + // Cleanup ... + bar.Clean(); + + // + return result; + } + + /** + * Check Price Switched Over HK Bond Upper or not ... + * + * @param priceType: ENUM_X_PRICE, Specified Price type ... + * @param barIndex: int, Specified Bar index ... + * + * @return ( bool ) + */ + bool IsSwitchedOverHKBondUpper( + ENUM_X_PRICE priceType = X_PRICE_HIGH, + int barIndex = 0 // + ) + { + // + bool result = false; + + // + // Normalize ... + barIndex = NormalizeBarIndex(barIndex); + + // + // Validate ... + result = IsValid() && + IsXValid(priceType); + if (!result) + { + return result; + } + + // + // Do ... + + // + int pBarIndex = barIndex + 1; + bool isBarPassed = IsOverHKBondUpper(priceType, barIndex); + bool isPBarPassed = !IsOverHKBondUpper(priceType, pBarIndex); + + // + result = isBarPassed && isPBarPassed; + + // + // Cleanup ... + + // + return result; + } + + /** + * Check Price Switched Under HK Bond Upper or not ... + * + * @param priceType: ENUM_X_PRICE, Specified Price type ... + * @param barIndex: int, Specified Bar index ... + * + * @return ( bool ) + */ + bool IsSwitchedUnderHKBondUpper( + ENUM_X_PRICE priceType = X_PRICE_LOW, + int barIndex = 0 // + ) + { + // + bool result = false; + + // + // Normalize ... + barIndex = NormalizeBarIndex(barIndex); + + // + // Validate ... + result = IsValid() && + IsXValid(priceType); + if (!result) + { + return result; + } + + // + // Do ... + + // + int pBarIndex = barIndex + 1; + bool isBarPassed = IsUnderHKBondUpper(priceType, barIndex); + bool isPBarPassed = !IsUnderHKBondUpper(priceType, pBarIndex); + + // + result = isBarPassed && isPBarPassed; + + // + // Cleanup ... + + // + return result; + } + + /** + * Check Price Switched Over HK Bond Lower or not ... + * + * @param priceType: ENUM_X_PRICE, Specified Price type ... + * @param barIndex: int, Specified Bar index ... + * + * @return ( bool ) + */ + bool IsSwitchedOverHKBondLower( + ENUM_X_PRICE priceType = X_PRICE_LOW, + int barIndex = 0 // + ) + { + // + bool result = false; + + // + // Normalize ... + barIndex = NormalizeBarIndex(barIndex); + + // + // Validate ... + result = IsValid() && + IsXValid(priceType); + if (!result) + { + return result; + } + + // + // Do ... + + // + int pBarIndex = barIndex + 1; + bool isBarPassed = IsOverHKBondLower(priceType, barIndex); + bool isPBarPassed = !IsOverHKBondLower(priceType, pBarIndex); + + // + result = isBarPassed && isPBarPassed; + + // + // Cleanup ... + + // + return result; + } + + /** + * Check Price Switched Under HK Bond Lower or not ... + * + * @param priceType: ENUM_X_PRICE, Specified Price type ... + * @param barIndex: int, Specified Bar index ... + * + * @return ( bool ) + */ + bool IsSwitchedUnderHKBondLower( + ENUM_X_PRICE priceType = X_PRICE_HIGH, + int barIndex = 0 // + ) + { + // + bool result = false; + + // + // Normalize ... + barIndex = NormalizeBarIndex(barIndex); + + // + // Validate ... + result = IsValid() && + IsXValid(priceType); + if (!result) + { + return result; + } + + // + // Do ... + + // + int pBarIndex = barIndex + 1; + bool isBarPassed = IsUnderHKBondLower(priceType, barIndex); + bool isPBarPassed = !IsUnderHKBondLower(priceType, pBarIndex); + + // + result = isBarPassed && isPBarPassed; + + // + // Cleanup ... + + // + return result; + } + + /** + * Detect Previous HK Bond ... + * + * @param index: int, reference to holds index ... + * @param priceType: ENUM_X_PRICE, Specified Price Type ... + * @param barIndex: int, Specified Bar Index ... + * @param loopback: int, Max Allowed Loopback Length ... + * + * @return ( bool ) + */ + bool FindLastOverHKBondUpper( + int &index, + ENUM_X_PRICE priceType = X_PRICE_HIGH, + int barIndex = 0, + int loopback = 500 // + ) + { + // + bool result = false; + + // + // Prepare ... + index = -1; + + // + // Normalize ... + loopback = NormalizeInt(loopback, 50); + barIndex = NormalizeBarIndex(barIndex); + + // + // Validate ... + result = IsValid() && + IsXValid(priceType); + if (!result) + { + return result; + } + + // + // Do ... + + // + int idx = barIndex; + while (idx < barIndex + loopback) + { + // + idx++; + result = IsOverHKBondUpper(priceType, idx); + if (result) + { + // + index = idx - 1; + break; + } + } + + // + result = IsValidIndex(index); + + // + // Cleanup ... + + // + return result; + } + + /** + * Detect Previous HK Bond ... + * + * @param index: int, reference to holds index ... + * @param priceType: ENUM_X_PRICE, Specified Price Type ... + * @param barIndex: int, Specified Bar Index ... + * @param loopback: int, Max Allowed Loopback Length ... + * + * @return ( bool ) + */ + bool FindLastUnderHKBondUpper( + int &index, + ENUM_X_PRICE priceType = X_PRICE_HIGH, + int barIndex = 0, + int loopback = 500 // + ) + { + // + bool result = false; + + // + // Prepare ... + index = -1; + + // + // Normalize ... + loopback = NormalizeInt(loopback, 50); + barIndex = NormalizeBarIndex(barIndex); + + // + // Validate ... + result = IsValid() && + IsXValid(priceType); + if (!result) + { + return result; + } + + // + // Do ... + + // + int idx = barIndex; + while (idx < barIndex + loopback) + { + // + idx++; + result = IsUnderHKBondUpper(priceType, idx); + if (result) + { + // + index = idx - 1; + break; + } + } + + // + result = IsValidIndex(index); + + // + // Cleanup ... + + // + return result; + } + + /** + * Detect Previous HK Bond ... + * + * @param index: int, reference to holds index ... + * @param priceType: ENUM_X_PRICE, Specified Price Type ... + * @param barIndex: int, Specified Bar Index ... + * @param loopback: int, Max Allowed Loopback Length ... + * + * @return ( bool ) + */ + bool FindLastOverHKBondLower( + int &index, + ENUM_X_PRICE priceType = X_PRICE_HIGH, + int barIndex = 0, + int loopback = 500 // + ) + { + // + bool result = false; + + // + // Prepare ... + index = -1; + + // + // Normalize ... + loopback = NormalizeInt(loopback, 50); + barIndex = NormalizeBarIndex(barIndex); + + // + // Validate ... + result = IsValid() && + IsXValid(priceType); + if (!result) + { + return result; + } + + // + // Do ... + + // + int idx = barIndex; + while (idx < barIndex + loopback) + { + // + idx++; + result = IsOverHKBondLower(priceType, idx); + if (result) + { + // + index = idx - 1; + break; + } + } + + // + result = IsValidIndex(index); + + // + // Cleanup ... + + // + return result; + } + + /** + * Detect Previous HK Bond ... + * + * @param index: int, reference to holds index ... + * @param priceType: ENUM_X_PRICE, Specified Price Type ... + * @param barIndex: int, Specified Bar Index ... + * @param loopback: int, Max Allowed Loopback Length ... + * + * @return ( bool ) + */ + bool FindLastUnderHKBondLower( + int &index, + ENUM_X_PRICE priceType = X_PRICE_HIGH, + int barIndex = 0, + int loopback = 500 // + ) + { + // + bool result = false; + + // + // Prepare ... + index = -1; + + // + // Normalize ... + loopback = NormalizeInt(loopback, 50); + barIndex = NormalizeBarIndex(barIndex); + + // + // Validate ... + result = IsValid() && + IsXValid(priceType); + if (!result) + { + return result; + } + + // + // Do ... + + // + int idx = barIndex; + while (idx < barIndex + loopback) + { + // + idx++; + result = IsUnderHKBondLower(priceType, idx); + if (result) + { + // + index = idx - 1; + break; + } + } + + // + result = IsValidIndex(index); + + // + // Cleanup ... + + // + return result; + } + + /** + * Detect Previous HK Bond Switch ... + * + * @param index: int, reference to holds switched index ... + * @param priceType: ENUM_X_PRICE, Specified Price Type ... + * @param barIndex: int, Specified Bar Index ... + * @param loopback: int, Max Allowed Loopback Length ... + * + * @return ( bool ) + */ + bool FindLastSwitchedOverHKBondUpper( + int &index, + ENUM_X_PRICE priceType = X_PRICE_HIGH, + int barIndex = 0, + int loopback = 500 // + ) + { + // + bool result = false; + + // + // Prepare ... + index = -1; + + // + // Normalize ... + loopback = NormalizeInt(loopback, 50); + barIndex = NormalizeBarIndex(barIndex); + + // + // Validate ... + result = IsValid() && + IsXValid(priceType); + if (!result) + { + return result; + } + + // + // Do ... + + // + int idx = barIndex; + while (idx < barIndex + loopback) + { + // + idx++; + result = IsSwitchedOverHKBondUpper(priceType, idx); + if (result) + { + // + index = idx - 1; + break; + } + } + + // + result = IsValidIndex(index); + + // + // Cleanup ... + + // + return result; + } + + /** + * Detect Previous HK Bond Switch ... + * + * @param index: int, reference to holds switched index ... + * @param priceType: ENUM_X_PRICE, Specified Price Type ... + * @param barIndex: int, Specified Bar Index ... + * @param loopback: int, Max Allowed Loopback Length ... + * + * @return ( bool ) + */ + bool FindLastSwitchedUnderHKBondUpper( + int &index, + ENUM_X_PRICE priceType = X_PRICE_HIGH, + int barIndex = 0, + int loopback = 500 // + ) + { + // + bool result = false; + + // + // Prepare ... + index = -1; + + // + // Normalize ... + loopback = NormalizeInt(loopback, 50); + barIndex = NormalizeBarIndex(barIndex); + + // + // Validate ... + result = IsValid() && + IsXValid(priceType); + if (!result) + { + return result; + } + + // + // Do ... + + // + int idx = barIndex; + while (idx < barIndex + loopback) + { + // + idx++; + result = IsSwitchedUnderHKBondUpper(priceType, idx); + if (result) + { + // + index = idx - 1; + break; + } + } + + // + result = IsValidIndex(index); + + // + // Cleanup ... + + // + return result; + } + + /** + * Detect Previous HK Bond Switch ... + * + * @param index: int, reference to holds switched index ... + * @param priceType: ENUM_X_PRICE, Specified Price Type ... + * @param barIndex: int, Specified Bar Index ... + * @param loopback: int, Max Allowed Loopback Length ... + * + * @return ( bool ) + */ + bool FindLastSwitchedOverHKBondLower( + int &index, + ENUM_X_PRICE priceType = X_PRICE_HIGH, + int barIndex = 0, + int loopback = 500 // + ) + { + // + bool result = false; + + // + // Prepare ... + index = -1; + + // + // Normalize ... + loopback = NormalizeInt(loopback, 50); + barIndex = NormalizeBarIndex(barIndex); + + // + // Validate ... + result = IsValid() && + IsXValid(priceType); + if (!result) + { + return result; + } + + // + // Do ... + + // + int idx = barIndex; + while (idx < barIndex + loopback) + { + // + idx++; + result = IsSwitchedOverHKBondLower(priceType, idx); + if (result) + { + // + index = idx - 1; + break; + } + } + + // + result = IsValidIndex(index); + + // + // Cleanup ... + + // + return result; + } + + /** + * Detect Previous HK Bond Switch ... + * + * @param index: int, reference to holds switched index ... + * @param priceType: ENUM_X_PRICE, Specified Price Type ... + * @param barIndex: int, Specified Bar Index ... + * @param loopback: int, Max Allowed Loopback Length ... + * + * @return ( bool ) + */ + bool FindLastSwitchedUnderHKBondLower( + int &index, + ENUM_X_PRICE priceType = X_PRICE_HIGH, + int barIndex = 0, + int loopback = 500 // + ) + { + // + bool result = false; + + // + // Prepare ... + index = -1; + + // + // Normalize ... + loopback = NormalizeInt(loopback, 50); + barIndex = NormalizeBarIndex(barIndex); + + // + // Validate ... + result = IsValid() && + IsXValid(priceType); + if (!result) + { + return result; + } + + // + // Do ... + + // + int idx = barIndex; + while (idx < barIndex + loopback) + { + // + idx++; + result = IsSwitchedUnderHKBondLower(priceType, idx); + if (result) + { + // + index = idx - 1; + break; + } + } + + // + result = IsValidIndex(index); + + // + // Cleanup ... + + // + return result; + } + // // ZigZag Pivots With Liquidity ... /** * Check ZigZag has Lower Low by Liquidity or Not ... - * + * * @param barIndex: int, Specified Bar Index ... * @param forceBarValidation: bool, Force Bar Price based on Pivot ... - * + * * @return ( bool ) */ bool HasZigZagLowerLowByLiquidity( @@ -3186,10 +4133,10 @@ class XCXFIMAHelper : public XCBaseHelper /** * Check ZigZag has Higher High by Liquidity or Not ... - * + * * @param barIndex: int, Specified Bar Index ... * @param forceBarValidation: bool, Force Bar Price based on Pivot ... - * + * * @return ( bool ) */ bool HasZigZagHigherHighByLiquidity( diff --git a/Libraries/x-saherelm.common.extensions.lib.mq5 b/Libraries/x-saherelm.common.extensions.lib.mq5 index d794115e..097bcff8 100644 --- a/Libraries/x-saherelm.common.extensions.lib.mq5 +++ b/Libraries/x-saherelm.common.extensions.lib.mq5 @@ -7095,6 +7095,163 @@ bool SetChartVolumesColor( // END Chart Info ... // +// +// START ATR ... +// + +/** + * Calculate True Range of Specified Bar ... + * + * @param _symbol: string, Symbol ... + * @param _period: ENUM_TIMEFRAMES, period ... + * @param _barIndex: int, Specified Bar Index ... + * @param ignorePC: bool, Ignore Previous Bar ... + * + * @return ( double ) + */ +double GetTrueRange( + string _symbol = NULL, + ENUM_TIMEFRAMES _period = NULL, + int _barIndex = 0, + bool ignorePC = false // Ignore Previous Close ... +) +{ + // + double result = EMPTY_VALUE; + + // + // Normalize ... + _symbol = NormalizeSymbol(_symbol); + _period = NormalizePeriod(_period); + _barIndex = NormalizeInt(_barIndex, 0); + + // + XOHCL bar; + XOHCL pBar; + + // + bool has = + bar.Init( + _symbol, + _period, + _barIndex // + ); + if (!ignorePC) + { + // + has = has && + bar.GetPreviousBar(pBar); + } + if (!has) + { + return result; + } + + // + double hlDiff = bar.high - bar.low; + + // + if (!ignorePC) + { + // + double hpcDiff = MathAbs(bar.high - pBar.close); + double lpcDiff = MathAbs(bar.high - pBar.close); + + // + result = MathMax(hlDiff, hpcDiff); + result = MathMax(result, lpcDiff); + } + else + { + result = hlDiff; + } + + // + // Cleanup ... + bar.Clean(); + pBar.Clean(); + + // + return result; +} + +/** + * Calculate ATR ... + * + * @param _symbol: string, Symbol ... + * @param _period: ENUM_TIMEFRAMES, period ... + * @param _barIndex: int, Specified Bar Index ... + * @param _length: int ATR Period ... + * + * @return ( double ) + */ +double GetAverageTrueRange( + string _symbol = NULL, + ENUM_TIMEFRAMES _period = NULL, + int _barIndex = 0, + int _length = 14 // +) +{ + // + double result = EMPTY_VALUE; + + // + // Normalize ... + _symbol = NormalizeSymbol(_symbol); + _period = NormalizePeriod(_period); + _length = NormalizeInt(_length, 2); + _barIndex = NormalizeInt(_barIndex, 0); + + // + // Collect True Ranges ... + double itr; + double _trs[]; + bool has = false; + int start = _barIndex; + int end = start + _length; + for (int i = start; i < end; i++) + { + // + itr = GetTrueRange( + _symbol, + _period, + _barIndex, + i == end - 1 // Ignore PC ... + ); + has = NotEmptyZero(itr); + if (has) + { + // + Add( + itr, + _trs // + ); + } + } + + // + int count = ArraySize(_trs); + has = HasChild(_trs); + if (!has) + { + return result; + } + + // + result = GetAverage(_trs); + + // + // Cleanup ... + XClean(_trs); + + // + return result; +} + +// +// END َATR ... +// + // // START Linear Regression ... // diff --git a/XFIMAEA/Classes/x-saherelm.xfima.signaller.class.mq5 b/XFIMAEA/Classes/x-saherelm.xfima.signaller.class.mq5 index bdf16d64..f38dd1e5 100644 --- a/XFIMAEA/Classes/x-saherelm.xfima.signaller.class.mq5 +++ b/XFIMAEA/Classes/x-saherelm.xfima.signaller.class.mq5 @@ -372,11 +372,11 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller structureConfig, barIndex // ); - poiDrawer.drawnObjects.Clear(); - poiDrawer.DrawMarketStructure( - structure, - structureDrawConfig // - ); + // poiDrawer.drawnObjects.Clear(); + // poiDrawer.DrawMarketStructure( + // structure, + // structureDrawConfig // + // ); // // Strategy 1 ... @@ -391,10 +391,9 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller // // Strategy 2 ... - has = false; if (!has) { - // + // // // has = Strategy2HasSignal( // iBar, // iZone, @@ -407,6 +406,7 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller // // Strategy 3 ... + has = false; if (!has) { // @@ -423,13 +423,13 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller // has = HasDirection(iDir) && iZone.IsValid(); - if (has) - { - // - has = false; - iZone.Clean(); - iDir = X_DIRECTION_NONE; - } + // if (has) + // { + // // + // has = false; + // iZone.Clean(); + // iDir = X_DIRECTION_NONE; + // } // if (has) @@ -442,6 +442,11 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller // TODO: Provided SL ... double _point = GetPoints(iBar.symbol); double slAddition = 5 * _point; + double atrAddition = GetAverageTrueRange( + iZone.symbol, + iZone.period, + 0 // + ); double slPrice = isBullish ? iZone.lower - slAddition @@ -1232,27 +1237,182 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller // Define Requirements ... bool isBullish = false; bool isBearish = false; + + // + XOHCL pBar; int barIndex = bar.Index(); + int pBarIndex = barIndex + 1; + result = bar.GetPreviousBar(pBar); + if (!result) + { + return result; + } // // Do Conditions Checking ... // - result = fimaHelper.HasMACross( - dir, - barIndex, - structureConfig.maCrossValidationDiffMultiplier // - ); - isBullish = - result && - IsXBullish(dir); - isBearish = - result && - IsXBearish(dir); + XBoxZone zones[]; + int zonesCount = 0; + ENUM_X_PRICE bullishPriceType = X_PRICE_LOW; + ENUM_X_PRICE bearishPriceType = X_PRICE_HIGH; // - result = isBullish || - isBearish; + isBullish = fimaHelper.IsSwitchedUnderHKBondLower(bullishPriceType, pBarIndex); + + // + isBearish = fimaHelper.IsSwitchedOverHKBondUpper(bearishPriceType, pBarIndex); + + // + result = + isBullish || + isBearish; + + // + // Do Validations ... + if (result) + { + // + // Direction Assignment ... + dir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + int lastIDX; + XBoxZone tmpZones[]; + int tmpZonesCount = 0; + int validationCount = 0; + ENUM_X_PRICE priceType = + isBullish + ? bullishPriceType + : bearishPriceType; + + // + // Detect Last Direction Change ... + if (isBullish) + { + result = fimaHelper.FindLastUnderHKBondLower(lastIDX, bullishPriceType, pBarIndex); + } + else + { + result = fimaHelper.FindLastOverHKBondUpper(lastIDX, bearishPriceType, pBarIndex); + } + + // + // Validate Direction Changed ... + if (result) + { + // + validationCount = lastIDX - pBarIndex; + result = validationCount >= 10; + } + + // + // Collect Zones ... + if (result) + { + // + // Support and Resistances ... + tmpZonesCount = poiDetector.CollectZones( + pBar, + tmpZones, + 5, + 14, // Zones Validation Length ... + 0, // Required Count ... + validationCount // Loopback ... + ); + if (IsValidSize(tmpZonesCount)) + { + // + Copy( + tmpZones, + zones, + false // ignore Clean ... + ); + } + + // + // OB ... + tmpZonesCount = poiDetector.CollectOBs( + pBar, + tmpZones, + 5, // Zones Loopback ... + 0, // Required Count ... + validationCount // Loopback ... + ); + if (IsValidSize(tmpZonesCount)) + { + // + Copy( + tmpZones, + zones, + false // ignore Clean ... + ); + } + + // + // FVG ... + tmpZonesCount = poiDetector.CollectFVGs( + pBar, + tmpZones, + 5, // Zones Loopback ... + 0, // Required Count ... + validationCount // Loopback ... + ); + if (IsValidSize(tmpZonesCount)) + { + // + Copy( + tmpZones, + zones, + false // ignore Clean ... + ); + } + + // + // Filter Zones Based on pBar ... + zonesCount = poiDetector.FilterZones( + pBar, + zones, + dir, + priceType, + dir // + ); + + // + // Extract Affected Zones ... + XClean(tmpZones); + tmpZonesCount = ExtractAffectedZones( + pBar, + zones, + tmpZones, + dir // + ); + Copy(tmpZones, zones); + zonesCount = ArraySize(zones); + + // + // Update Zones Time ... + UpdateToTime(zones); + } + + // + // Draw Zones ... + result = IsValidSize(zonesCount); + if (result) + { + // + for (int i = 0; i < zonesCount; i++) + { + poiDrawer.DrawZone(zones[i], structureDrawConfig.drawConfig); + } + } + + // + XClean(tmpZones); + } // // Prepare Zone ... @@ -1260,6 +1420,35 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller { // // Zone Detection ... + zone.Clean(); + if (isBullish) + { + // + int idx = GetLowest(zones); + if (IsValidIndex(idx)) + { + zone = zones[idx]; + } + } + else + { + // + int idx = GetHighest(zones); + if (IsValidIndex(idx)) + { + zone = zones[idx]; + } + } + + // zone.dir = dir; + // zone.type = name; + // zone.to = bar.time; + // zone.at = pBar.time; + // zone.from = pBar.time; + // zone.symbol = bar.symbol; + // zone.period = bar.period; + // zone.lower = MathMin(pBar.low, bar.low); + // zone.upper = MathMax(pBar.high, bar.high); // result = zone.IsValid(); @@ -1274,6 +1463,7 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller } // + // Cleanup ... if (!result) { // @@ -1281,6 +1471,8 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller XClean(targets); dir = X_DIRECTION_NONE; } + pBar.Clean(); + XClean(zones); // return result;