/////////////////////////////////////////////////////// // // SaherElm IT Center MQL5 Class Library // ---------------------------------------------- // Name: XCMarketPatternDetector // Description: provides all Alerts requirements ... // // // Maintainer: // ------------ // Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) // ////////////////////////////////////////////////////// // // Global Properties ... #property library #property copyright "Copyright 2023, SaherElm IT Center" #property link "https://www.saherelm.ir" #property version "1.00" #property strict // // Imports ... #include "../Classes/x-saherelm.base.class.mq5" #include "../Classes/x-saherelm.x-bar.analyser.class.mq5" #include "../Libraries/x-saherelm.x-pivot.analysis.lib.mq5" #include "../Libraries/x-saherelm.x-poi.extensions.lib.mq5" #include "../Libraries/x-saherelm.x-poi.lib.mq5" // // Definitions ... // // Implementation ... class XCMarketPatternDetector : public XCBase { // // Public ... public: // // Props ... // // Constructor ... XCMarketPatternDetector() { barAnalyser = new XCBarAnalyser(); } // // Deconstructor ... ~XCMarketPatternDetector() { // delete barAnalyser; ZeroMemory(barAnalyser); } // // Analysers ... /** * Check for Price Touch Support Level ... * * @param bar: XOHCL, Specified Bar ... * @param supportBar: XOHCL, reference to holds Zone Bar ... * @param supportBox: XBoxZone, reference to holds Zone Box ... * @param validationLength: int, Validation Length ... * @param maxAllowedLoopback: int, Max Allowed Loopback to Detection ... * * @return ( bool ) */ bool IsSupportTouched( XOHCL &bar, XOHCL &supportBar, XBoxZone &supportBox, int validationLength = 21, int maxAllowedLoopback = 1500 // ) { // bool result = false; // // Prepare ... supportBar.Clean(); supportBox.Clean(); // // Validate ... result = bar.IsValid(); if (!result) { return result; } // // Check Support Exists ... result = HasSupport( bar, supportBar, validationLength, maxAllowedLoopback // ); if (!result) { // supportBar.Clean(); return result; } // // Extract Support Box ... result = ToSupportBox( supportBar, supportBox // ); // // Retrieve Previous Bar ... XOHCL pBar; result = result && bar.GetPreviousBar(pBar); // // Chekc Price of Bar ... result = result && pBar.low < supportBox.upper; // // Cleanup Resources ... if (!result) { // supportBar.Clean(); supportBox.Clean(); } pBar.Clean(); // return result; } /** * Check for Price Touch Resistance Level ... * * @param bar: XOHCL, Specified Bar ... * @param supportBar: XOHCL, reference to holds Zone Bar ... * @param supportBox: XBoxZone, reference to holds Zone Box ... * @param validationLength: int, Validation Length ... * @param maxAllowedLoopback: int, Max Allowed Loopback to Detection ... * * @return ( bool ) */ bool IsResistanceTouched( XOHCL &bar, XOHCL &resistanceBar, XBoxZone &resistanceBox, int validationLength = 21, int maxAllowedLoopback = 1500 // ) { // bool result = false; // // Prepare ... resistanceBar.Clean(); resistanceBox.Clean(); // // Validate ... result = bar.IsValid(); if (!result) { return result; } // // Check Resistance Exists ... result = HasResistance( bar, resistanceBar, validationLength, maxAllowedLoopback // ); if (!result) { // resistanceBar.Clean(); return result; } // // Extract Resistance Box ... result = ToResistanceBox( resistanceBar, resistanceBox // ); // // Retrieve Previous Bar ... XOHCL pBar; result = result && bar.GetPreviousBar(pBar); // // Chekc Price of Bar ... result = result && pBar.high > resistanceBox.lower; // // Cleanup Resources ... if (!result) { // resistanceBar.Clean(); resistanceBox.Clean(); } pBar.Clean(); // return result; } /** * Check a Bar has Same Sequence Directionalo Bar or Not ... * * @param bar: XOHCL, Specified Bar ... * @param dir: ENUM_X_DIRECTION, Detected Bars Direction ... * @param count: int, Number of Same Bars ... * @param validation: int, Validation of Same Bars ... * @param loopback: int, Loopback for Detection ... * * @return ( bool ) */ bool HasSameBars( XOHCL &bar, ENUM_X_DIRECTION &dir, int &count, int validation = 3 // ) { // bool result = false; // // Normalize ... count = 0; dir = X_DIRECTION_NONE; // // Validate ... result = bar.IsValid() && validation > 1; if (!result) { return result; } // XOHCL tmpBar; bar.GetPreviousBar(tmpBar); while ((tmpBar.GetDirection() == bar.GetDirection()) || ((bar.IsBullish() && !tmpBar.IsBearish()) || (bar.IsBearish() && !tmpBar.IsBullish()))) { // count++; tmpBar.GetPreviousBar(tmpBar); } // // Validate Count ... result = count >= validation; if (result) { dir = bar.GetDirection(); } // result = result && count > 0 && HasDirection(dir) && count >= validation; // tmpBar.Clean(); // return result; } /** * Detect Confluence Statck based on Given Bar ... * * @param bar: XOHCL, Specified Bar for Start Detection ... * @param zone: XBoxZone, confluence Zone, if exists ... * @param forDir: ENUM_X_DIRECTION, Specified Required Zone Confluence ... * @param retests: int, Number of Zone retesting ... * @param loopback: int, Max allowed Loopback for Confluence Detection ... * @param rangeLength: int, Loopback for Range Detecttion ... * @param upperPriceType: ENUM_X_PRICE, zone upper Price Type ... * @param lowerPriceType: ENUM_X_PRICE, * @return ( bool ) */ bool HasConfluence( XOHCL &bar, XBoxZone &confluence, ENUM_X_DIRECTION forDir, int retests = 2, int loopback = 15, int rangeLength = 5, ENUM_X_PRICE upperPriceType = X_PRICE_HIGH, ENUM_X_PRICE lowerPriceType = X_PRICE_LOW // ) { // bool result = false; // // Normalize ... confluence.Clean(); if (retests < 0) { retests = 0; } if (loopback < 2) { loopback = 2; } if (rangeLength < 2) { rangeLength = 2; } // // Validate ... result = bar.IsValid() && HasDirection(forDir) && IsXValid(upperPriceType) && IsXValid(lowerPriceType); if (!result) { return result; } // // Retrieve Upper and Lower ... int mIndex = -1; double upper = bar.FindHighest( mIndex, rangeLength, upperPriceType // ); double lower = bar.FindLowest( mIndex, rangeLength, lowerPriceType // ); // // Validate Upper/Lower ... result = NotEmptyZero(upper) && NotEmptyZero(lower) && upper > lower; if (!result) { return result; } // // Validate Confluence ... XOHCL tmpBar; bool has = false; int tmpCount = 0; double tmpPrice = EMPTY_VALUE; for (int i = bar.Index() + 1; i < bar.Index() + loopback; i++) { // has = tmpBar.Init(bar.symbol, bar.period, i); if (!has) { continue; } // tmpPrice = IsXBullish(forDir) ? tmpBar.GetPrice(upperPriceType) : tmpBar.GetPrice(lowerPriceType); has = NotEmptyZero(tmpPrice) && (IsXBullish(forDir) ? tmpPrice < upper : tmpPrice > lower); if (!has) { // tmpBar.Clean(); // result = false; break; } // // Counting retests ... has = IsXBullish(forDir) ? tmpPrice > lower : tmpPrice > upper; if (has) { tmpCount++; } // tmpBar.Clean(); } // // Validating Retests ... if (result && retests > 0) { // result = result && tmpCount >= retests; } // if (!result) { return result; } // result = confluence.Init( bar.symbol, bar.period, upper, lower, GetBarTime(bar.symbol, bar.period, bar.Index() + loopback + 1), bar.time, forDir, "XConfluence", NULL // At ... ); // return result; } // // Detectors ... /** * 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, ENUM_X_PRICE peakPriceType = X_PRICE_HIGH, // ENUM_X_PRICE valePriceType = X_PRICE_LOW // ) { // bool result = false; // // Prepare ... CleanDirection(dir); // // Normalize ... validationLength = NormalizeInt(validationLength, 2); // // Validate ... result = bar.IsValid() && IsXValid(peakPriceType) && IsXValid(valePriceType); if (!result) { return result; } // int valeIndex = -1; double vale = bar.FindLowest( valeIndex, validationLength, valePriceType // ); double barVale = bar.GetPrice(valePriceType); bool isVale = NotEmptyZero(vale) && NotEmptyZero(barVale) && IsValidIndex(valeIndex) && vale >= barVale; // int peakIndex = -1; double peak = bar.FindHighest( peakIndex, validationLength, peakPriceType // ); double barPeak = bar.GetPrice(peakPriceType); bool isPeak = NotEmptyZero(peak) && NotEmptyZero(barPeak) && IsValidIndex(peakIndex) && peak <= barPeak; // result = (isVale && !isPeak) || (isPeak && !isVale); if (result) { // dir = isVale ? X_DIRECTION_BULLISH : isPeak ? X_DIRECTION_BEARISH : X_DIRECTION_NONE; } // // Get Result ... result = HasDirection(dir); // // Cleanup Resources ... // return result; } /** * Check Specified Bar is Momentum Bar or not ... * * @param bar: XOHCL, Specified Bar ... * @param dir: ENUM_X_DIRECTION a reference for Direction ... * @param requiredBars: int, bar range for approve Momentum ... * @param approvedMultiplier: double, a Multipler for approve Momentum ... * * @return ( bool ) */ bool IsMomentumBar( XOHCL &bar, ENUM_X_DIRECTION &dir, int requiredBars = 3, double approvedMultiplier = 2 // ) { // bool result = false; // // Prepare ... CleanDirection(dir); // // Normalizing ... requiredBars = NormalizeInt(requiredBars, 3, 10); approvedMultiplier = NormalizeDouble(approvedMultiplier, 2, 5); // // Validate ... result = bar.IsValid(); if (!result) { return result; } // // Calculate Requirements ... // XOHCL iBar; bool has = false; double rangeBody = 0; int start = bar.Index() + 1; int end = start + requiredBars; for (int i = start; i < end; i++) { // // Initialized Bar ... has = iBar.Init( bar.symbol, bar.period, i // ); // // Summarize Body Sizes ... if (has) { rangeBody += iBar.GetBody(); } // iBar.Clean(); } // // Calculate Body Approvement ... result = bar.GetBody() >= (approvedMultiplier * rangeBody); if (!result) { return result; } // // Check Direction ... dir = bar.GetDirection(); // // Get Result ... result = HasDirection(dir); // // Cleanup Resources ... iBar.Clean(); // return result; } /** * Check Specified Bar is Engulfed Bar or not ... * * @param bar: XOHCL, Specified Bar ... * @param dir: ENUM_X_DIRECTION a reference for Direction ... * * @return ( bool ) */ bool IsEngulfedBar( XOHCL &bar, ENUM_X_DIRECTION &dir // ) { // bool result = false; // // Prepare ... CleanDirection(dir); // // Validate ... result = bar.IsValid(); if (!result) { return result; } // // Calculate Requirements ... // XOHCL iBar; result = bar.GetPreviousBar(iBar); if (!result) { // iBar.Clean(); return result; } // // Check Prev Bar Must Inside Bar ... result = bar.GetUp() > iBar.GetUp() && bar.GetDown() < iBar.GetDown(); if (!result) { // iBar.Clean(); return result; } // // Check Directions ... bool isBullish = iBar.IsBearish() && bar.IsBullish(); bool isBearish = iBar.IsBullish() && bar.IsBearish(); result = isBullish || isBearish; if (!result) { // iBar.Clean(); return result; } // dir = bar.GetDirection(); // // Get Result ... result = HasDirection(dir); // // Cleanup Resources ... iBar.Clean(); // return result; } /** * Check Specified Bar is True Gapped Bar or not ... * * @param bar: XOHCL, Specified Bar ... * @param dir: ENUM_X_DIRECTION a reference for Direction ... * @param approvedPointMultiplier: double, Gap Validation Multiplier in Point ... * * @return ( bool ) */ bool IsTrueGapedBar( XOHCL &bar, ENUM_X_DIRECTION &dir, double approvedPointMultiplier = 1 // ) { // bool result = false; // // Prepare ... CleanDirection(dir); // // Normalizing ... approvedPointMultiplier = NormalizeDouble(approvedPointMultiplier, 1, 100); // // Validate ... result = bar.IsValid(); if (!result) { return result; } // // Calculate Requirements ... // XOHCL iBar; result = bar.GetPreviousBar(iBar); if (!result) { // iBar.Clean(); return result; } // // Check Directions ... bool isBullish = iBar.IsBullish() && bar.IsBullish(); bool isBearish = iBar.IsBearish() && bar.IsBearish(); result = isBullish || isBearish; if (!result) { // iBar.Clean(); return result; } // double point = GetPoints(bar.symbol); double approvedGapSize = approvedPointMultiplier * point; // // Check Gap Exists ... result = isBullish ? bar.low > iBar.high : iBar.low > bar.high; if (!result) { // iBar.Clean(); return result; } // // Validate Gap Size ... double gapSize = isBullish ? bar.low - iBar.high : iBar.low - bar.high; result = gapSize >= approvedGapSize; if (!result) { // iBar.Clean(); return result; } // dir = bar.GetDirection(); // // Get Result ... result = HasDirection(dir); // // Cleanup Resources ... iBar.Clean(); // return result; } /** * Check Specified Bar is Pinned Bar or not ... * * @param bar: XOHCL, Specified Bar ... * @param dir: ENUM_X_DIRECTION a reference for Direction ... * @param shadowApprovedMultiplier: double, Shadow Size Approve Multiplier ... * @param minimumPinBarRangeMultiplier: doubble, Range Size Approve Multiplier in Point ... * @param forceDirection: bool, Apply Force Bar Type ... * * @return ( bool ) */ bool IsPinnedBar( XOHCL &bar, ENUM_X_DIRECTION &dir, double shadowApprovedMultiplier = 3, double minimumPinBarRangeMultiplier = 4, bool forceDirection = false // ) { // bool result = false; // // Prepare ... CleanDirection(dir); // // Normalizing ... shadowApprovedMultiplier = NormalizeDouble(shadowApprovedMultiplier, 2, 5); minimumPinBarRangeMultiplier = NormalizeDouble(minimumPinBarRangeMultiplier, 2, 100); // // Validate ... result = bar.IsValid(); if (!result) { return result; } // // Calculate Requirements ... double body = bar.GetBody(); double lowShadow = bar.GetLowShadow(); double highShadow = bar.GetHighShadow(); // // Check Directions ... bool isBullish = lowShadow > body && lowShadow > highShadow && lowShadow >= (body * shadowApprovedMultiplier); bool isBearish = highShadow > body && highShadow > lowShadow && highShadow > (body * shadowApprovedMultiplier); result = isBullish || isBearish; if (!result) { return result; } // // Checking Force Bar Type ... if (forceDirection) { // result = isBullish ? bar.IsBullish() : bar.IsBearish(); } if (!result) { return result; } // // Check Range Validation ... double point = GetPoints(bar.symbol); double approvedRange = minimumPinBarRangeMultiplier * point; result = bar.GetRange() >= approvedRange; if (!result) { return result; } // // Setting Direction ... dir = isBullish ? X_DIRECTION_BULLISH : X_DIRECTION_BEARISH; // result = HasDirection(dir); // return result; } /** * Check Specified Bar has Star Pattern or not ... * Morning Star => Bullish * Evening Star => Bearish * * @param bar: XOHCL, Specified Bar ... * @param dir: ENUM_X_DIRECTION a reference for Direction ... * * @return ( bool ) */ bool IsStarPattern( XOHCL &bar, ENUM_X_DIRECTION &dir // ) { // bool result = false; // // Prepare ... CleanDirection(dir); // // Validate ... result = bar.IsValid(); if (!result) { return result; } // // Get Requirements ... XOHCL pBar, p2Bar; result = bar.GetPreviousBar(pBar); result = result && pBar.GetPreviousBar(p2Bar); if (!result) { // pBar.Clean(); p2Bar.Clean(); // return result; } // // Check Directions ... bool isBullish = bar.IsBullish() && p2Bar.IsBearish(); bool isBearish = bar.IsBearish() && p2Bar.IsBullish(); result = isBullish || isBearish; if (!result) { // pBar.Clean(); p2Bar.Clean(); // return result; } // // Checking Gap Exists Between Bars ... result = isBullish ? p2Bar.GetDown() > pBar.GetUp() && pBar.GetUp() < bar.GetDown() : p2Bar.GetUp() < pBar.GetDown() && pBar.GetDown() > bar.GetUp(); if (!result) { // pBar.Clean(); p2Bar.Clean(); // return result; } // // Check Bar Close Validation ... double barClosedApprovedPrice = p2Bar.GetDown() + ((p2Bar.GetUp() - p2Bar.GetDown()) / 2); result = isBullish ? bar.close > barClosedApprovedPrice : bar.close < barClosedApprovedPrice; if (!result) { // pBar.Clean(); p2Bar.Clean(); // return result; } // // Validating PBar Body and Shadow ... double body = pBar.GetBody(); double lowShadow = pBar.GetLowShadow(); double highShadow = pBar.GetHighShadow(); result = body < bar.GetBody() && body < p2Bar.GetBody() && (isBullish ? lowShadow > body && lowShadow > highShadow : highShadow > body && highShadow > lowShadow); if (!result) { // pBar.Clean(); p2Bar.Clean(); // return result; } // dir = bar.GetDirection(); // // Get Result ... result = HasDirection(dir); // // Cleanup Resources ... pBar.Clean(); p2Bar.Clean(); // return result; } /** * Check Specified Bar has Pirecing Pattern or not ... * Piercing => Bullish * Dark Cloud Cover => Bearish * * @param bar: XOHCL, Specified Bar ... * @param dir: ENUM_X_DIRECTION a reference for Direction ... * * @return ( bool ) */ bool IsPiercingPattern( XOHCL &bar, ENUM_X_DIRECTION &dir // ) { // bool result = false; // // Prepare ... CleanDirection(dir); // // Validate ... result = bar.IsValid(); if (!result) { return result; } // XOHCL pBar; result = bar.GetPreviousBar(pBar); if (!result) { // pBar.Clean(); return result; } // // Check Directions ... bool isBullish = bar.IsBullish() && pBar.IsBearish(); bool isBearish = bar.IsBearish() && pBar.IsBullish(); result = isBullish || isBearish; if (!result) { // pBar.Clean(); return result; } // // Check Bar Close ... double barCloseApprovedPrice = pBar.GetDown() + ((pBar.GetUp() - pBar.GetDown()) / 2); result = isBullish ? bar.close > barCloseApprovedPrice : bar.close < barCloseApprovedPrice; if (!result) { // pBar.Clean(); return result; } // dir = bar.GetDirection(); // // Get Result ... result = HasDirection(dir); // // Cleanup Resources ... pBar.Clean(); // return result; } /** * Check Specified Bar has Rising Pattern or not ... * * @param bar: XOHCL, Specified Bar ... * @param dir: ENUM_X_DIRECTION a reference for Direction ... * * @return ( bool ) */ bool IsRisingPattern( XOHCL &bar, ENUM_X_DIRECTION &dir // ) { // bool result = false; // // Prepare ... CleanDirection(dir); // // Validate ... result = bar.IsValid(); if (!result) { return result; } // // Reading Required Bars ... XOHCL iBar; XOHCL bars[]; bool has = false; int start = bar.Index(); int end = start + 5; for (int i = start; i < end; i++) { // // Initialized Bar ... has = iBar.Init( bar.symbol, bar.period, i // ); if (has) { // AddRef( iBar, bars // ); } // iBar.Clean(); } result = ArraySize(bars) == 5; if (!result) { // iBar.Clean(); SpecifiedClean(bars); // return result; } // // Check Directions ... bool isBullish = bars[0].IsBullish() && bars[4].IsBullish() && bars[1].IsBearish() && bars[2].IsBearish() && bars[3].IsBearish(); bool isBearish = bars[0].IsBearish() && bars[4].IsBearish() && bars[1].IsBullish() && bars[2].IsBullish() && bars[3].IsBullish(); result = isBullish || isBearish; if (!result) { // iBar.Clean(); SpecifiedClean(bars); // return result; } // // Check Range Validation ... double upper = bars[4].GetUp(); double lower = bars[4].GetDown(); // double max = MathMax(bars[1].GetUp(), bars[2].GetUp()); max = MathMax(max, bars[3].GetUp()); // double min = MathMin(bars[1].GetDown(), bars[2].GetDown()); min = MathMin(min, bars[3].GetDown()); // result = max < upper && min > lower && (isBullish ? bars[0].close > bars[4].GetUp() : bars[0].close < bars[4].GetDown()); if (!result) { // iBar.Clean(); SpecifiedClean(bars); // return result; } // dir = bar.GetDirection(); // // Get Result ... result = HasDirection(dir); // // Cleanup Resources ... iBar.Clean(); SpecifiedClean(bars); // return result; } /** * Check Specified Bar has Flag Pattern or not ... * * @param bar: XOHCL, Specified Bar ... * @param dir: ENUM_X_DIRECTION a reference for Direction ... * @param swingBar: XOHCL, Detected Swing Bar ... * @param minimumPullbackBars: int, Minimum Shoulders of Swing Bar ... * * @return ( bool ) */ bool IsFlagPattern( XOHCL &bar, ENUM_X_DIRECTION &dir, XOHCL &swingBar, int minimumPullbackBars = 3 // ) { // bool result = false; // // Prepare ... swingBar.Clean(); CleanDirection(dir); // // Normalizing ... minimumPullbackBars = NormalizeInt(minimumPullbackBars, 3, 10); // // Validate ... result = bar.IsValid(); if (!result) { return result; } // // Reading Previous Bar ... XOHCL pBar; result = bar.GetPreviousBar(pBar); if (!result) { // pBar.Clean(); return result; } // // Check Directions ... bool isBullish = bar.IsBullish() && bar.close > pBar.GetUp(); bool isBearish = bar.IsBearish() && bar.close < pBar.GetDown(); result = isBullish || isBearish; if (!result) { // pBar.Clean(); return result; } // // Detect Swing Bar ... ENUM_X_SWING_TYPE swingType = isBullish ? X_SWING_HIGH : X_SWING_LOW; result = result && IsXValid(swingType) && bar.FindNextSwingBar( swingType, swingBar, minimumPullbackBars // ) && (isBullish ? swingBar.IsBullish() && swingBar.high > pBar.high : swingBar.IsBearish() && swingBar.low < pBar.low); if (!result) { // pBar.Clean(); swingBar.Clean(); // return result; } // dir = bar.GetDirection(); // // Get Result ... result = HasDirection(dir); // // Cleanup Resources ... pBar.Clean(); if (!result) { swingBar.Clean(); } // return result; } /** * Check Specified Bar has SignalKey Bar Pattern or not ... * * @param bar: XOHCL, Specified Bar ... * @param dir: ENUM_X_DIRECTION a reference for Direction ... * @param shadowApprovedMultiplier: double, Shadow Size Approve Multiplier ... * @param minimumPinBarRangeMultiplier: doubble, Range Size Approve Multiplier in Point ... * @param forceDirection: bool, Apply Force Bar Type ... * * @return ( bool ) */ bool IsSignalKeyBarPattern( XOHCL &bar, ENUM_X_DIRECTION &dir, double shadowApprovedMultiplier = 3, double minimumPinBarRangeMultiplier = 4, bool forceDirection = false // ) { // bool result = false; // // Prepare ... CleanDirection(dir); // // Validate ... result = bar.IsValid(); if (!result) { return result; } // // Get Requirements ... XOHCL pBar; result = bar.GetPreviousBar(pBar); if (!result) { return result; } // // Chck Previous Bar must Pinned ... result = IsPinnedBar( pBar, dir, shadowApprovedMultiplier, minimumPinBarRangeMultiplier, forceDirection // ); if (!result) { // pBar.Clean(); return result; } // // Check Direction ... bool isBullish = bar.IsBullish() && IsSpecifiedBullish(dir) && bar.close > pBar.high; bool isBearish = bar.IsBearish() && IsSpecifiedBearish(dir) && bar.close < pBar.low; result = isBullish || isBearish; if (!result) { // pBar.Clean(); return result; } // dir = bar.GetDirection(); // result = HasDirection(dir); // // Cleanup Resources ... pBar.Clean(); // return result; } /** * Check Specified Bar has Pullback Bar Pattern or not ... * * @param bar: XOHCL, Specified Bar ... * @param zone: XBoxZone, refrence to hold detected zone ... * @param dir: ENUM_X_DIRECTION a reference for Direction ... * @param pullbackLength: int, min required indirectional bars to confirm pullback ... * @param forceBreak: bool, force pullback bar breaks peak or vale of Zone ... * * @return ( bool ) */ bool IsPullbackPattern( XOHCL &bar, XBoxZone &zone, ENUM_X_DIRECTION &dir, int pullbackLength = 2, bool forceBreak = false // ) { // bool result = false; // // Prepare ... zone.Clean(); CleanDirection(dir); // // Normalize ... pullbackLength = NormalizeInt(pullbackLength, 2); // // Validate ... result = bar.IsValid(); if (!result) { return result; } // // First Bar Direction ... dir = bar.GetDirection(); result = HasDirection(dir); if (!result) { return result; } // // Loop through Pullback Length ... XOHCL iBar; datetime from = NULL; double max = EMPTY_VALUE; double min = EMPTY_VALUE; int start = bar.Index() + 1; int end = start + pullbackLength; for (int i = start; i < end; i++) { // // Initialize Indexed Bar ... iBar.Clean(); result = bar.BarAt(i, iBar) && iBar.GetDirection() == Opposit(dir); if (!result) { break; } // // Calculate Max and Min ... max = !NotEmptyZero(max) ? iBar.high : MathMax(max, iBar.high); min = !NotEmptyZero(min) ? iBar.low : MathMin(min, iBar.low); from = iBar.time; } // // Apply Force Break ... if (result && forceBreak) { // result = result && NotEmptyZero(min) && NotEmptyZero(max) && (IsXBullish(dir) ? bar.close > max : bar.close < min); } // // Prepare Zone ... if (result) { // ToBox( bar, zone, dir, ToXString(X_BAR_PATTERN_PULLBACK) // ); zone.upper = max; zone.lower = min; zone.from = from; zone.at = bar.time; zone.to = bar.time; // result = zone.IsValid(); } // // Cleanup ... if (!result) { // zone.Clean(); CleanDirection(dir); } iBar.Clean(); // return result; } /** * Check Market Has Consolidation Pattern or not ... * * @param bar: XOHCL, reference to Specified Bar ... * @param zone: XBoxZone, refrence to hold detected zone ... * @param dir: ENUM_X_DIRECTION, reference to holds Detected Order Flow Direction ... * @param validationLength: int, Validation Length ... * @param breakPriceType: ENUM_X_PRICE, Specified Price Type to Breake Consolidation ... * @param upperPriceType: ENUM_X_PRICE, Specified Price Type to Detected Upper of Consolidation ... * @param lowerPriceType: ENUM_X_PRICE, Specified Price Type to Detected Lower of Consolidation ... * * @return ( bool ) */ bool IsConsolidationPattern( XOHCL &bar, XBoxZone &zone, ENUM_X_DIRECTION &dir, int validationLength = 5, ENUM_X_PRICE breakPriceType = X_PRICE_CLOSE, ENUM_X_PRICE upperPriceType = X_PRICE_HIGH, ENUM_X_PRICE lowerPriceType = X_PRICE_LOW // ) { // // Descriptions: // =============== // Consolidation Zones Happens by Highest High and Lowest Low // of Specified Range which Breakes From one Side ... // // bool result = false; // // Prepare ... zone.Clean(); CleanDirection(dir); // // Normalize ... validationLength = NormalizeInt(validationLength, 3); // // Validate ... result = bar.IsValid() && IsXValid(lowerPriceType) && IsXValid(upperPriceType) && IsXValid(breakPriceType); if (!result) { return result; } // // Define Requirements ... XOHCL iBar; bool has = false; datetime to = NULL; datetime from = NULL; double iLow = EMPTY_VALUE; bool hasLowShadow = false; double lower = EMPTY_VALUE; double upper = EMPTY_VALUE; double iHigh = EMPTY_VALUE; bool hasHighShadow = false; double iPrice = EMPTY_VALUE; bool isLowerBreaked = false; bool isUpperBreaked = false; // // Loop Through Bars ... int barIndex = bar.Index(); int idx = barIndex; bool canLookup = IsValidIndex(idx); while (canLookup) { // // Initialize Indexed Bar ... idx++; iBar.Clean(); result = bar.BarAt(idx, iBar); if (!result) { break; } // // Update Time ... if (idx == barIndex + 1) { to = iBar.time; } // // Extract Low and High Price ... iLow = iBar.GetPrice(lowerPriceType); iHigh = iBar.GetPrice(upperPriceType); result = NotEmptyZero(iLow) && NotEmptyZero(iHigh); if (!result) { break; } // // Check Bar Has Low/High Shadow ... hasLowShadow = iBar.GetLowShadow() > iBar.GetHighShadow(); hasHighShadow = iBar.GetHighShadow() > iBar.GetLowShadow(); // // Update Range Lower and Upper based on Shadows ... // // Lower ... if (hasLowShadow) { // // Check Can Update ... has = !NotEmptyZero(lower) ? true : iLow < lower; if (has) { lower = iLow; } } // // Upper ... if (hasHighShadow) { // // Check Can Update ... has = !NotEmptyZero(upper) ? true : iHigh > upper; if (has) { upper = iHigh; } } // // Check Price Breakes ... iPrice = iBar.GetPrice(breakPriceType); result = NotEmptyZero(iPrice); if (!result) { break; } // // Check Upper/Lower breakes ... isLowerBreaked = iPrice < lower; isUpperBreaked = iPrice > upper; // canLookup = (!isLowerBreaked && !isUpperBreaked); if (!canLookup) { break; } // from = iBar.time; } // // Validate Calculations ... result = // IsXValid(to) && IsXValid(from) && from < to && // NotEmptyZero(lower) && NotEmptyZero(upper) && upper > lower // ; // // Validate To Edge Breakes ... if (result) { // iPrice = bar.GetPrice(breakPriceType); result = NotEmptyZero(iPrice); // // Validate To Edge Breakes ... if (result) { // isUpperBreaked = iPrice > upper; isLowerBreaked = iPrice < lower; // // Validate To Break ... result = isUpperBreaked || isLowerBreaked; } // // Prepare Direction ... if (result) { // dir = isUpperBreaked ? X_DIRECTION_BULLISH : X_DIRECTION_BEARISH; } // // Validate Direction ... result = HasDirection(dir); } // // Prepare Zone ... if (result) { // zone.to = to; zone.dir = dir; zone.from = from; zone.at = bar.time; zone.upper = upper; zone.lower = lower; zone.symbol = bar.symbol; zone.period = bar.period; zone.type = ToXString(X_BAR_PATTERN_CONSOLIDATION); // // Validate Zone ... result = zone.IsValid(); // // Validate Zone Length ... if (result) { result = zone.FromIndex() - zone.ToIndex() >= validationLength; } } // // Cleanup ... if (!result) { // zone.Clean(); CleanDirection(dir); } iBar.Clean(); // return result; } bool HasCandlestickDirection( XOHCL &bar, ENUM_X_DIRECTION forDir, bool checkStarPattern = true, bool checkPinBarPattern = true, bool checkPiercingPattern = true, bool checkEngulfedPattern = true, bool checkMomentumPattern = true, bool checkSignalKeyBarPattern = true // ) { // bool result = false; // // Validate ... result = bar.IsValid() && HasDirection(forDir); if (!result) { return result; } // ENUM_X_DIRECTION tmpDir = X_DIRECTION_NONE; // // Star ... bool isStarPattern = false; if (checkStarPattern) { // isStarPattern = IsStarPattern(bar, tmpDir) && tmpDir == forDir; } // bool isPiercingPattern = false; if (checkPiercingPattern) { // isPiercingPattern = IsPiercingPattern(bar, tmpDir) && tmpDir == forDir; } // // Engulfed ... bool isEngulfedPattern = false; if (checkEngulfedPattern) { // isEngulfedPattern = IsEngulfedBar(bar, tmpDir) && tmpDir == forDir; } // // PinBar ... bool isPinBarPattern = true; if (checkPinBarPattern) { // isPinBarPattern = IsPinnedBar(bar, tmpDir) && tmpDir == forDir; } // // Signal Key Bar ... bool isSignalKeyBarPattern = false; if (checkSignalKeyBarPattern) { // isSignalKeyBarPattern = IsSignalKeyBarPattern(bar, tmpDir) && tmpDir == forDir; } // // Momentum Bar ... bool isMomentumBarPattern = false; if (checkMomentumPattern) { // isMomentumBarPattern = IsMomentumBar(bar, tmpDir) && tmpDir == forDir; } // result = isStarPattern || isPinBarPattern || isPiercingPattern || isEngulfedPattern || isMomentumBarPattern || isSignalKeyBarPattern; // return result; } /** * Detect Order Flow ... * * @param bar: XOHCL, reference to Specified Bar ... * @param dir: ENUM_X_DIRECTION, reference to holds Detected Order Flow Direction ... * @param orderFlow: XBoxZone, collection reference to holds Detected Order Flow ... * @param orderFlowValidation: int, number of sequential Zones for Validate Order Flow ... * @param containsOBs: bool, Specified to Use Order Blocks in Order Flow Detection ... * @param containsFVGs: bool, Specified to Use Fair Value Gaps in Order Flow Detection ... * @param containsSupportResistances: bool, Specified to Use Support and Resistances in Order Flow Detection ... * @param zonesLoopback: int, Zone Detection Loopback ... * @param zonesValidationLength: int, Zone Validation Length ... * @param loopback: int, Max Allowed Loopback Bars for Collecting ... * * @return ( bool ) */ bool HasOrderFlow( XOHCL &bar, ENUM_X_DIRECTION &dir, XBoxZone &orderFlow[], int orderFlowValidation = 2, bool containsOBs = false, bool containsFVGs = true, bool containsSupportResistances = false, int zonesLoopback = 5, int zonesValidationLength = 21, int loopback = 100 // ) { // bool result = false; // // Prepare ... XClean(orderFlow); CleanDirection(dir); int maxRequiredZone = 0; // // Normalize ... loopback = NormalizeInt(loopback, 10); zonesLoopback = NormalizeInt(zonesLoopback, 3); maxRequiredZone = NormalizeInt(maxRequiredZone, 0); orderFlowValidation = NormalizeInt(orderFlowValidation, 1); zonesValidationLength = NormalizeInt(zonesValidationLength, 3); // // Validate ... result = bar.IsValid(); if (!result) { return result; } // // Do ... // // Collectiong Zones ... XBoxZone tmp; XBoxZone tmps[]; XBoxZone _zones[]; XBoxZone bullishZones[]; XBoxZone bearishZones[]; int bullishZonesCount = 0; int bearishZonesCount = 0; // // Order Blocks ... if (containsOBs) { // XClean(tmps); CollectOBs(bar, tmps, zonesLoopback, maxRequiredZone, loopback); FillNotExists(_zones, tmps); } // // Fair Value Gaps ... if (containsFVGs) { // XClean(tmps); CollectFVGs(bar, tmps, zonesLoopback, maxRequiredZone, loopback); FillNotExists(_zones, tmps); } // // Support and Resistances ... if (containsSupportResistances) { // XClean(tmps); CollectZones(bar, tmps, zonesLoopback, maxRequiredZone, loopback); FillNotExists(_zones, tmps); } // // Validate Zones ... result = HasChild(_zones); // // Extract Only Validated Zones ... if (result) { // ValidateBoxes( _zones, bar.Index() // Bars Length ... ); // UpdateToTime(_zones, bar.time); RemoveBreakedZones(_zones, X_PRICE_CLOSE); // result = HasChild(_zones); } // // Separate Zones Direction ... if (result) { // bullishZonesCount = ExtractByDirection(bullishZones, _zones, X_DIRECTION_BULLISH); bearishZonesCount = ExtractByDirection(bearishZones, _zones, X_DIRECTION_BEARISH); // result = IsValidSize(bullishZonesCount) || IsValidSize(bearishZonesCount); } // // Looking for Sequences of Zones ... if (result) { // int idx = -1; bool has = false; XBoxZone bullOrderFlow[]; XBoxZone bearOrderFlow[]; // // Bullish OrderFlow ... // // Sorting ... Copy(bullishZones, bullOrderFlow); Sort( bullOrderFlow, X_SORT_BY_DATE, X_DIRECTION_BEARISH, orderFlowValidation + 1 // ); bool hasBullishOrderFlow = ArraySize(bullOrderFlow) >= orderFlowValidation; if (hasBullishOrderFlow) { // // Validate Order Flow ... Copy(bullOrderFlow, tmps); XClean(bullOrderFlow); while (HasChild(tmps)) { // tmp.Clean(); tmp = tmps[0]; ArrayRemove(tmps, 0, 1); // idx = GetHighest(tmps); has = !IsValidIndex(idx) ? true : tmps[idx].lower < tmp.lower; if (has) { AddIfNotExists(tmp, bullOrderFlow); } } // hasBullishOrderFlow = ArraySize(bullOrderFlow) >= orderFlowValidation; } // // Bearish OrderFlow ... // // Sorting ... Copy(bearishZones, bearOrderFlow); Sort( bearOrderFlow, X_SORT_BY_DATE, X_DIRECTION_BULLISH, orderFlowValidation + 1 // ); bool hasBearishOrderFlow = ArraySize(bearOrderFlow) >= orderFlowValidation; if (hasBearishOrderFlow) { // // Validate Order Flow ... Copy(bearOrderFlow, tmps); XClean(bearOrderFlow); while (HasChild(tmps)) { // tmp.Clean(); tmp = tmps[0]; ArrayRemove(tmps, 0, 1); // idx = GetLowest(tmps); has = !IsValidIndex(idx) ? true : tmps[idx].upper > tmp.upper; if (has) { AddIfNotExists(tmp, bearOrderFlow); } } // hasBearishOrderFlow = ArraySize(bearOrderFlow) >= orderFlowValidation; } // result = hasBullishOrderFlow || hasBearishOrderFlow; // // Validate Order Flows ... if (result) { // has = (hasBullishOrderFlow && !hasBearishOrderFlow) || (hasBearishOrderFlow && !hasBullishOrderFlow); // // When only Have One Direction ... if (has) { // if (hasBullishOrderFlow) { // dir = X_DIRECTION_BULLISH; Copy(bullOrderFlow, orderFlow); } else if (hasBearishOrderFlow) { // dir = X_DIRECTION_BEARISH; Copy(bearOrderFlow, orderFlow); } } // // When Two Direction Exists ... else { // // Retrieve Oldest Of Bullish / Bearish ... int oldestBullIDX = GetOldest(bullOrderFlow); int oldestBearIDX = GetOldest(bearOrderFlow); result = IsValidIndex(oldestBullIDX) && IsValidIndex(oldestBearIDX); if (result) { // dir = bullOrderFlow[oldestBullIDX].from > bearOrderFlow[oldestBearIDX].from ? X_DIRECTION_BULLISH : bearOrderFlow[oldestBearIDX].from > bullOrderFlow[oldestBullIDX].from ? X_DIRECTION_BEARISH : X_DIRECTION_NONE; } // result = HasDirection(dir); if (result) { // if (IsXBullish(dir)) { Copy(bullOrderFlow, orderFlow); } else if (IsXBearish(dir)) { Copy(bearOrderFlow, orderFlow); } } } } // XClean(bullOrderFlow); XClean(bearOrderFlow); // result = HasChild(orderFlow) && HasDirection(dir); } // // Validate Price ... if (result) { // int idx = -1; if (IsXBullish(dir)) { // idx = GetHighest(orderFlow); result = IsValidIndex(idx) && bar.low > orderFlow[idx].upper; } else { // idx = GetLowest(orderFlow); result = IsValidIndex(idx) && bar.high < orderFlow[idx].lower; } } // // Update To Time of Order Flow ... if (result) { UpdateToTime(orderFlow, bar.time); } // // Cleanup ... if (!result) { // XClean(orderFlow); CleanDirection(dir); } tmp.Clean(); XClean(tmps); XClean(_zones); XClean(bullishZones); XClean(bearishZones); // return result; } // // FVG ... /** * Check For FVG Exists in Specified Loopback Period ... * * @param bar: XOHCL, Specified Bar ... * @param dir: ENUM_X_DIRECTION a reference for Direction ... * @param fvg: XBoxZone, reference for Holding FVG ... * @param maxLoopback: int, Max Allowed Loopback to Lookup FVG ... * * @return ( bool ) */ bool HasFVG( XOHCL &bar, ENUM_X_DIRECTION &dir, XBoxZone &fvg, int maxLoopback = 5 // ) { // bool result = false; // // Prepare ... fvg.Clean(); CleanDirection(dir); // // Normalize ... maxLoopback = NormalizeInt(maxLoopback, 3); // // Validate ... result = bar.IsValid(); if (!result) { return result; } // XOHCL iBar; bool has = false; int start = bar.Index(); int end = start + maxLoopback; for (int i = start; i < end; i++) { // // Initialize iBar ... has = iBar.Init( bar.symbol, bar.period, i // ); if (!has) { continue; } // // Check iBar is FVG or not ... has = barAnalyser.IsFVG( iBar, fvg, true // Force Bar Type ... ); if (!has) { // fvg.Clean(); iBar.Clean(); CleanDirection(dir); // continue; } // iBar.Clean(); dir = fvg.dir; // break; } // // Check FVG Exists ... result = fvg.IsValid(); // // Check Direction Exists ... result = result && HasDirection(dir); // // Cleanup Resources ... if (!result) { // fvg.Clean(); CleanDirection(dir); } iBar.Clean(); // return result; } // // OB ... /** * Check For OB Exists in Specified Loopback Period ... * * @param bar: XOHCL, Specified Bar ... * @param dir: ENUM_X_DIRECTION a reference for Direction ... * @param ob: XBoxZone, reference for Holding OB ... * @param maxLoopback: int, Max Allowed Loopback to Lookup OB ... * * @return ( bool ) */ bool HasOB( XOHCL &bar, ENUM_X_DIRECTION &dir, XBoxZone &ob, int maxLoopback = 5 // ) { // bool result = false; // // Prepare ... ob.Clean(); CleanDirection(dir); // // Normalize ... maxLoopback = NormalizeInt(maxLoopback, 3); // // Validate ... result = bar.IsValid(); if (!result) { return result; } // XOHCL iBar; bool has = false; int start = bar.Index(); int end = start + maxLoopback; for (int i = start; i < end; i++) { // // Initialize iBar ... has = iBar.Init( bar.symbol, bar.period, i // ); if (!has) { continue; } // // Check iBar is OB or not ... has = barAnalyser.IsOB( iBar, ob, true, // Force FVG Bar Type ... true // Force OB First Two Bar InDirection ... ); if (!has) { // ob.Clean(); iBar.Clean(); CleanDirection(dir); // continue; } // iBar.Clean(); dir = ob.dir; // break; } // // Check OB Exists ... result = ob.IsValid(); // // Check Direction Exists ... result = result && HasDirection(dir); // // Cleanup Resources ... if (!result) { // ob.Clean(); CleanDirection(dir); } iBar.Clean(); // return result; } // // Complex ... /** * Check Double Pinned Bar ... * * @param bar: XOHCL, reference to Specified Bar ... * @param dir: ENUM_X_DIRECTION, reference to holds Pattern Direction ... * @param shadowApprovedMultiplier: double, Shadow Size Approve Multiplier ... * @param minimumPinBarRangeMultiplier: doubble, Range Size Approve Multiplier in Point ... * @param forceDirection: bool, Apply Force Bar Type ... * @param loopback: int, Max Allowed Detecting Loopback lenght ... * * @return ( bool ) */ bool IsDoublePinned( XOHCL &bar, ENUM_X_DIRECTION &dir, double shadowApprovedMultiplier = 3, double minimumPinBarRangeMultiplier = 4, bool forceDirection = false, int loopback = 5 // ) { // bool result = false; // // Prepare ... CleanDirection(dir); // // Normalize ... loopback = NormalizeInt(loopback, 1); shadowApprovedMultiplier = NormalizeDouble(shadowApprovedMultiplier, 2, 5); minimumPinBarRangeMultiplier = NormalizeDouble(minimumPinBarRangeMultiplier, 2, 100); // // Validate ... result = bar.IsValid(); if (!result) { return result; } // // Do ... // // Current Bar Must be a Pinned Bar ... result = IsPinnedBar( bar, dir, shadowApprovedMultiplier, minimumPinBarRangeMultiplier, forceDirection // ); if (!result) { // CleanDirection(dir); // return result; } // XOHCL iBar; ENUM_X_DIRECTION iDir; int start = bar.Index() + 1; int end = start + loopback; for (int i = start; i < end; i++) { // iBar.Clean(); result = bar.BarAt(i, iBar); result = result && IsPinnedBar( iBar, iDir, shadowApprovedMultiplier, minimumPinBarRangeMultiplier, forceDirection // ); result = result && iDir == dir; if (result) { break; } } // // Cleanup ... if (!result) { CleanDirection(dir); } iBar.Clean(); CleanDirection(iDir); // return result; } /** * Check Double Engulfed Bar ... * * @param bar: XOHCL, reference to Specified Bar ... * @param dir: ENUM_X_DIRECTION, reference to holds Pattern Direction ... * @param loopback: int, Max Allowed Detecting Loopback lenght ... * * @return ( bool ) */ bool IsDoubleEngulfed( XOHCL &bar, ENUM_X_DIRECTION &dir, int loopback = 5 // ) { // bool result = false; // // Prepare ... CleanDirection(dir); // // Normalize ... loopback = NormalizeInt(loopback, 1); // // Validate ... result = bar.IsValid(); if (!result) { return result; } // // Do ... // // Current Bar Must be a Pinned Bar ... result = IsEngulfedBar( bar, dir // ); if (!result) { // CleanDirection(dir); // return result; } // XOHCL iBar; ENUM_X_DIRECTION iDir; int start = bar.Index() + 1; int end = start + loopback; for (int i = start; i < end; i++) { // iBar.Clean(); result = bar.BarAt(i, iBar); result = result && IsEngulfedBar( iBar, iDir // ); result = result && iDir == dir; if (result) { break; } } // // Cleanup ... if (!result) { CleanDirection(dir); } iBar.Clean(); CleanDirection(iDir); // return result; } /** * Check Double Momentum Bar ... * * @param bar: XOHCL, reference to Specified Bar ... * @param dir: ENUM_X_DIRECTION, reference to holds Pattern Direction ... * @param requiredBars: int, bar range for approve Momentum ... * @param approvedMultiplier: double, a Multipler for approve Momentum ... * @param loopback: int, Max Allowed Detecting Loopback lenght ... * * @return ( bool ) */ bool IsDoubleMomentum( XOHCL &bar, ENUM_X_DIRECTION &dir, int requiredBars = 3, double approvedMultiplier = 2, int loopback = 5 // ) { // bool result = false; // // Prepare ... CleanDirection(dir); // // Normalize ... loopback = NormalizeInt(loopback, 1); requiredBars = NormalizeInt(requiredBars, 3, 10); approvedMultiplier = NormalizeDouble(approvedMultiplier, 2, 5); // // Validate ... result = bar.IsValid(); if (!result) { return result; } // // Do ... // // Current Bar Must be a Pinned Bar ... result = IsMomentumBar( bar, dir, requiredBars, approvedMultiplier // ); if (!result) { // CleanDirection(dir); // return result; } // XOHCL iBar; ENUM_X_DIRECTION iDir; int start = bar.Index() + 1; int end = start + loopback; for (int i = start; i < end; i++) { // iBar.Clean(); result = bar.BarAt(i, iBar); result = result && IsMomentumBar( iBar, iDir, requiredBars, approvedMultiplier // ); result = result && iDir == dir; if (result) { break; } } // // Cleanup ... if (!result) { CleanDirection(dir); } iBar.Clean(); CleanDirection(iDir); // return result; } /** * Check Has Double Patterns ... * * @param bar: XOHCL, reference to Specified Bar ... * @param dir: ENUM_X_DIRECTION, reference to holds Specified Patterns ... * @param barPatterns: XPatternAnalysis, reference to Provides Bar's Pattern Analysis ... * @param pBarPatterns: XPatternAnalysis, reference to Provides Previous Bar's Pattern Analysis ... * @param allowedPatterns: ENUM_X_BAR_PATTERN, collection to Provide Allowed Bar Patterns for Detection ... * @param config: XPatternAnalysisConfig, Provides Patterns Detection Config ... * @param loopback: int, Max Allowed Loopback for Detection ... * @param forDir: ENUM_X_DIRECTION, Specified Patterns Detection Direction ... * * @return ( bool ) */ bool HasDoublePatterns( XOHCL &bar, ENUM_X_DIRECTION &dir, XPatternAnalysis &barPatterns, XPatternAnalysis &pBarPatterns, ENUM_X_BAR_PATTERN &allowedPatterns[], XPatternAnalysisConfig &config, int loopback = 5, ENUM_X_DIRECTION forDir = X_DIRECTION_NONE // ) { // bool result = false; // // Prepare ... barPatterns.Clean(); CleanDirection(dir); pBarPatterns.Clean(); XPatternAnalysisConfig iConfig = config; // // Normalize ... loopback = NormalizeInt(loopback, 2); // // Validate ... result = bar.IsValid() && HasChild(allowedPatterns); if (!result) { return result; } // // Prepare Config ... iConfig.CleanPatterns(); if (HasChild(allowedPatterns)) { // for (int i = 0; i < ArraySize(allowedPatterns); i++) { iConfig.AddPattern(allowedPatterns[i]); } } // // Detect Bar Patterns ... result = AnalyseBarPatterns(bar, barPatterns, config); if (!result) { // CleanDirection(dir); barPatterns.Clean(); pBarPatterns.Clean(); // return result; } // // Check Direction ... int bullishCount = barPatterns.Count(X_DIRECTION_BULLISH); int bearishCount = barPatterns.Count(X_DIRECTION_BEARISH); dir = bullishCount > bearishCount ? X_DIRECTION_BULLISH : bearishCount > bullishCount ? X_DIRECTION_BEARISH : X_DIRECTION_NONE; result = HasDirection(dir); // // Check for Dir ... if (HasDirection(forDir)) { // result = result && dir == forDir; } // // Looping Back ... if (result) { // XOHCL iBar; ENUM_X_DIRECTION iDir; int start = bar.Index() + 1; int end = start + loopback; for (int i = start; i < end; i++) { // iBar.Clean(); pBarPatterns.Clean(); result = bar.BarAt(i, iBar); result = result && AnalyseBarPatterns(iBar, pBarPatterns, iConfig); if (!result) { continue; } // bullishCount = pBarPatterns.Count(X_DIRECTION_BULLISH); bearishCount = pBarPatterns.Count(X_DIRECTION_BEARISH); iDir = bullishCount > bearishCount ? X_DIRECTION_BULLISH : bearishCount > bullishCount ? X_DIRECTION_BEARISH : X_DIRECTION_NONE; result = HasDirection(iDir); result = result && dir == iDir; if (result) { break; } } // iBar.Clean(); CleanDirection(iDir); } // // Cleanup ... if (!result) { // CleanDirection(dir); barPatterns.Clean(); pBarPatterns.Clean(); } iConfig.Clean(); // return result; } /** * Count Same Bars ... * * @param bar: XOHCL, Specified Bar ... * @param sameBars: XOHCL, collection reference to holds same Bars ... * @param dir: ENUM_X_DIRECTION, refrence to Founded Bars Direction holding ... * @param forDir: ENUM_X_DIRECTION, Specified Looking Bar ... * * @return ( int ) */ int CountSameBars( XOHCL &bar, XOHCL &sameBars[], ENUM_X_DIRECTION &dir, ENUM_X_DIRECTION forDir // ) { // int result = 0; // // Prepare ... XClean(sameBars); // // Validate ... bool has = bar.IsValid(); if (!has) { return result; } // XOHCL tmpBar; ENUM_X_DIRECTION tmpDir = forDir; int idx = bar.Index(); while (has) { // idx++; tmpBar.Clean(); has = bar.BarAt(idx, tmpBar); if (has && !HasDirection(tmpDir)) { tmpDir = tmpBar.GetDirection(); } has = has && tmpBar.GetDirection() == tmpDir; if (!has) { break; } // AddIfNotExists(tmpBar, sameBars); } // result = ArraySize(sameBars); if (IsValidSize(result)) { dir = tmpDir; } // // Cleanup ... tmpBar.Clean(); // return result; } // // Trending ... /** * Check Trend Exists Based on Swings ... * * @param bar: XOHCL, Specified Bar ... * @param dir: ENUM_X_DIRECTION a reference for Direction ... * @param swings: XOHCL Array, Holds Swings ... * @param numberOfSwings: int, Number of Swing Points for Detect Trend ... * @param swingShoulders: int, Swing Shoulders Approvement Length ... * * @return ( bool ) */ bool HasSwingTrend( XOHCL &bar, ENUM_X_DIRECTION &dir, XOHCL &swings[], int numberOfSwings = 3, int swingShoulders = 7 // ) { // bool result = false; // // Prepare ... CleanDirection(dir); SpecifiedClean(swings); // // Normalizing ... numberOfSwings = NormalizeInt(numberOfSwings, 3, 10); swingShoulders = NormalizeInt(swingShoulders, 3); // // Validate ... result = bar.IsValid(); if (!result) { return result; } // // Check Trend Direction ... XOHCL iSwing; int idx = -1; bool has = false; XOHCL swingLows[]; XOHCL swingHighs[]; int lastSwingLowIndex = bar.Index(); int lastSwingHighIndex = bar.Index(); while (ArraySize(swingLows) < numberOfSwings || ArraySize(swingHighs) < numberOfSwings) { // bool canLookupSwingLow = ArraySize(swingLows) < numberOfSwings; bool canLookupSwingHigh = ArraySize(swingHighs) < numberOfSwings; if (!canLookupSwingLow && !canLookupSwingHigh) { break; } // // Handle Swing Lows ... if (canLookupSwingLow) { // iSwing.Clean(); idx = FindXSwing( X_SWING_LOW, bar.symbol, bar.period, lastSwingLowIndex + 1, swingShoulders // ); has = IsValidIndex(idx); if (has) { // has = iSwing.Init( bar.symbol, bar.period, idx // ); if (has) { // AddRef( iSwing, swingLows // ); // lastSwingLowIndex = idx; } } } // // Handle Swing Highs ... if (canLookupSwingHigh) { // iSwing.Clean(); idx = FindXSwing( X_SWING_HIGH, bar.symbol, bar.period, lastSwingHighIndex + 1, swingShoulders // ); has = IsValidIndex(idx); if (has) { // has = iSwing.Init( bar.symbol, bar.period, idx // ); if (has) { // AddRef( iSwing, swingHighs // ); // lastSwingHighIndex = idx; } } } } // // Check Trend Based On Swings ... // // Check Directions ... // bool isBullish = false; bool isBearish = false; // datetime oldestSwingLow = NULL; datetime oldestSwingHigh = NULL; // // Checking Bullish Trend based on Swing Lows ... int count = ArraySize(swingLows); for (int i = 0; i < count - 1; i++) { // has = swingLows[i].low > swingLows[i + 1].low; isBullish = !isBullish ? has : isBullish && has; if (!isBullish) { break; } // datetime oldeTime = MathMin(swingLows[i].time, swingLows[i + 1].time); oldestSwingLow = !IsSpecifiedValid(oldestSwingLow) ? oldeTime : MathMin(oldestSwingLow, oldeTime); } // // Checking Bearish Trend based on Swing Highs ... count = ArraySize(swingHighs); for (int i = 0; i < count - 1; i++) { // has = swingHighs[i].high < swingHighs[i + 1].high; isBearish = !isBearish ? has : isBearish && has; if (!isBearish) { break; } // datetime oldeTime = MathMin(swingHighs[i].time, swingHighs[i + 1].time); oldestSwingHigh = !IsSpecifiedValid(oldestSwingHigh) ? oldeTime : MathMin(oldestSwingHigh, oldeTime); } // result = isBullish || isBearish; if (!result) { // iSwing.Clean(); SpecifiedClean(swingLows); SpecifiedClean(swingHighs); // return result; } // if (isBullish && isBearish && IsSpecifiedValid(oldestSwingLow) && IsSpecifiedValid(oldestSwingHigh)) { // // Here we Have to Detect Newest Trend or Oldest Trend ... isBullish = oldestSwingLow < oldestSwingHigh; isBearish = oldestSwingHigh < oldestSwingLow; } // result = (isBullish && !isBearish) || (isBearish && !isBullish); if (!result) { // iSwing.Clean(); SpecifiedClean(swingLows); SpecifiedClean(swingHighs); // return result; } // if (isBullish) { // Copy( swingLows, swings // ); // dir = X_DIRECTION_BULLISH; } else { // Copy( swingHighs, swings // ); // dir = X_DIRECTION_BEARISH; } // iSwing.Clean(); SpecifiedClean(swingLows); SpecifiedClean(swingHighs); // return result; } /** * Check Specified Bar Has Support or not ... * * @param bar: XOHCL, Specified Bar ... * @param support: XOHCL, Supported Bar ... * @param validationLength: int, Validation Length ... * @param maxAllowedLoopback: int, Max Allowed Loopback to Detection ... * * @return ( bool ) */ bool HasSupport( XOHCL &bar, XOHCL &support, int validationLength = 21, int maxAllowedLoopback = 1500 // ) { // bool result = false; // // Prepare ... support.Clean(); // // Normalizing ... validationLength = NormalizeInt(validationLength, 7); maxAllowedLoopback = NormalizeInt(maxAllowedLoopback, 21, 1500); // // Validate ... result = bar.IsValid(); if (!result) { return result; } // // Find Support Swing ... int idx = -1; bool has = false; int lookupIDX = bar.Index(); while (!IsValidIndex(idx) && lookupIDX < maxAllowedLoopback) { // // Detect Swing ... idx = FindXSwing( X_SWING_LOW, bar.symbol, bar.period, lookupIDX, validationLength // ); has = IsValidIndex(idx); if (!has) { // lookupIDX++; continue; } // // Retrieve Swing Bar ... has = support.Init( bar.symbol, bar.period, idx // ); if (!has) { // idx = -1; lookupIDX++; support.Clean(); continue; } // // Check Suppor Low Shadow ... has = support.GetDown() < bar.low; if (!has) { // idx = -1; lookupIDX++; support.Clean(); continue; } // if (IsValidIndex(idx)) { break; } } // result = support.IsValid(); // return result; } /** * Check Specified Bar Has Resistance or not ... * * @param bar: XOHCL, Specified Bar ... * @param resistence: XOHCL, Resistanced Bar ... * @param validationLength: int, Validation Length ... * @param maxAllowedLoopback: int, Max Allowed Loopback to Detection ... * * @return ( bool ) */ bool HasResistance( XOHCL &bar, XOHCL &resistence, int validationLength = 21, int maxAllowedLoopback = 1500 // ) { // bool result = false; // // Prepare ... resistence.Clean(); // // Normalizing ... validationLength = NormalizeInt(validationLength, 7); maxAllowedLoopback = NormalizeInt(maxAllowedLoopback, 21, 1500); // // Validate ... result = bar.IsValid(); if (!result) { return result; } // // Find Support Swing ... int idx = -1; bool has = false; int lookupIDX = bar.Index(); while (!IsValidIndex(idx) && lookupIDX < maxAllowedLoopback) { // // Detect Swing ... idx = FindXSwing( X_SWING_HIGH, bar.symbol, bar.period, lookupIDX, validationLength // ); has = IsValidIndex(idx); if (!has) { // lookupIDX++; continue; } // // Retrieve Swing Bar ... has = resistence.Init( bar.symbol, bar.period, idx // ); if (!has) { // idx = -1; lookupIDX++; resistence.Clean(); continue; } // // Check Resistance High Shadow ... has = resistence.GetUp() > bar.high; if (!has) { // idx = -1; lookupIDX++; resistence.Clean(); continue; } // if (IsValidIndex(idx)) { break; } } // result = resistence.IsValid(); // 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 ... /** * Analyse Specified Bar ... * * @param bar: XOHCL, reference to Specified Bar ... * @param analysis: XPatternAnalysis, reference to holds Analysis result ... * @param config: XPatternAnalysisConfig, reference to Provides Detector Configs ... * * @return ( bool ) */ bool AnalyseBarPatterns( XOHCL &bar, XPatternAnalysis &analysis, XPatternAnalysisConfig &config // ) { // bool result = false; // // Prepare ... analysis.Clean(); // // Validate ... result = bar.IsValid(); if (!result) { return result; } // analysis.bar = bar; analysis.time = TimeCurrent(); // XOHCL iSwing; XBoxZone iZone; ENUM_X_DIRECTION iDir; ENUM_X_BAR_PATTERN iPattern; // bool has; bool isBullish; bool isBearish; // bool canDetect; bool canDetectBullish; bool canDetectBearish; // // Bars Detectors ... // // XPV High Low Detection ... canDetect = config.CanDetect(X_BAR_PATTERN_HIGH) || config.CanDetect(X_BAR_PATTERN_LOW); if (canDetect) { // has = IsPV( bar, iDir, config.pvValidationLength, config.peakPriceType, config.valePriceType // ); // canDetectBullish = config.CanDetect(X_BAR_PATTERN_LOW); canDetectBearish = config.CanDetect(X_BAR_PATTERN_HIGH); // isBullish = has && IsXBullish(iDir) && canDetectBullish; // isBearish = has && IsXBearish(iDir) && canDetectBearish; // canDetect = isBullish || isBearish; if (canDetect) { // iPattern = isBearish ? X_BAR_PATTERN_HIGH : X_BAR_PATTERN_LOW; // analysis.AddPattern( iPattern, iDir // ); } } // // Momentum ... iPattern = X_BAR_PATTERN_MOMENTUM; canDetect = config.CanDetect(iPattern); if (canDetect) { // has = IsMomentumBar( bar, iDir, config.momentumBarValidationLength, config.momentumBarApprovedMultiplier // ); // canDetectBullish = config.CanDetect( iPattern, X_DIRECTION_BULLISH // ); canDetectBearish = config.CanDetect( iPattern, X_DIRECTION_BEARISH // ); // isBullish = has && IsXBullish(iDir) && canDetectBullish; isBearish = has && IsXBearish(iDir) && canDetectBearish; // canDetect = isBullish || isBearish; if (canDetect) { // analysis.AddPattern( iPattern, iDir // ); } } // // Engulfed ... iPattern = X_BAR_PATTERN_ENGULFED; canDetect = config.CanDetect(iPattern); if (canDetect) { // has = IsEngulfedBar( bar, iDir // ); // canDetectBullish = config.CanDetect( iPattern, X_DIRECTION_BULLISH // ); canDetectBearish = config.CanDetect( iPattern, X_DIRECTION_BEARISH // ); // isBullish = has && IsXBullish(iDir) && canDetectBullish; isBearish = has && IsXBearish(iDir) && canDetectBearish; // canDetect = isBullish || isBearish; if (canDetect) { // analysis.AddPattern( iPattern, iDir // ); } } // // TrueGap ... iPattern = X_BAR_PATTERN_TRUE_GAPED; canDetect = config.CanDetect(iPattern); if (canDetect) { // has = IsTrueGapedBar( bar, iDir, config.trueGapApprovedStrength // ); // canDetectBullish = config.CanDetect( iPattern, X_DIRECTION_BULLISH // ); canDetectBearish = config.CanDetect( iPattern, X_DIRECTION_BEARISH // ); // isBullish = has && IsXBullish(iDir) && canDetectBullish; isBearish = has && IsXBearish(iDir) && canDetectBearish; // canDetect = isBullish || isBearish; if (canDetect) { // analysis.AddPattern( iPattern, iDir // ); } } // // Pinned ... iPattern = X_BAR_PATTERN_PINNED; canDetect = config.CanDetect(iPattern); if (canDetect) { // has = IsPinnedBar( bar, iDir, config.pinBarShadowApprovedMultiplier, config.pinBarRangeMultiplier, config.pinBarForceDirection // ); // canDetectBullish = config.CanDetect( iPattern, X_DIRECTION_BULLISH // ); canDetectBearish = config.CanDetect( iPattern, X_DIRECTION_BEARISH // ); // isBullish = has && IsXBullish(iDir) && canDetectBullish; isBearish = has && IsXBearish(iDir) && canDetectBearish; // canDetect = isBullish || isBearish; if (canDetect) { // analysis.AddPattern( iPattern, iDir // ); } } // // Pattern Detectors ... // // Star ... iPattern = X_BAR_PATTERN_STAR; canDetect = config.CanDetect(iPattern); if (canDetect) { // has = IsStarPattern( bar, iDir // ); // canDetectBullish = config.CanDetect( iPattern, X_DIRECTION_BULLISH // ); canDetectBearish = config.CanDetect( iPattern, X_DIRECTION_BEARISH // ); // isBullish = has && IsXBullish(iDir) && canDetectBullish; isBearish = has && IsXBearish(iDir) && canDetectBearish; // canDetect = isBullish || isBearish; if (canDetect) { // analysis.AddPattern( iPattern, iDir // ); } } // // Piercing ... iPattern = X_BAR_PATTERN_PIERCING; canDetect = config.CanDetect(iPattern); if (canDetect) { // has = IsPiercingPattern( bar, iDir // ); // canDetectBullish = config.CanDetect( iPattern, X_DIRECTION_BULLISH // ); canDetectBearish = config.CanDetect( iPattern, X_DIRECTION_BEARISH // ); // isBullish = has && IsXBullish(iDir) && canDetectBullish; isBearish = has && IsXBearish(iDir) && canDetectBearish; // canDetect = isBullish || isBearish; if (canDetect) { // analysis.AddPattern( iPattern, iDir // ); } } // // Rising ... iPattern = X_BAR_PATTERN_RISING; canDetect = config.CanDetect(iPattern); if (canDetect) { // has = IsRisingPattern( bar, iDir // ); // canDetectBullish = config.CanDetect( iPattern, X_DIRECTION_BULLISH // ); canDetectBearish = config.CanDetect( iPattern, X_DIRECTION_BEARISH // ); // isBullish = has && IsXBullish(iDir) && canDetectBullish; isBearish = has && IsXBearish(iDir) && canDetectBearish; // canDetect = isBullish || isBearish; if (canDetect) { // analysis.AddPattern( iPattern, iDir // ); } } // // Flag ... iPattern = X_BAR_PATTERN_FLAG; canDetect = config.CanDetect(iPattern); if (canDetect) { // has = IsFlagPattern( bar, iDir, iSwing, config.flagPatternPullbackLength // ); // canDetectBullish = config.CanDetect( iPattern, X_DIRECTION_BULLISH // ); canDetectBearish = config.CanDetect( iPattern, X_DIRECTION_BEARISH // ); // isBullish = has && IsXBullish(iDir) && canDetectBullish; isBearish = has && IsXBearish(iDir) && canDetectBearish; // canDetect = isBullish || isBearish; if (canDetect) { // analysis.AddPattern( iPattern, iDir // ); // analysis.flagSwing = iSwing; } } // // SignalKey ... iPattern = X_BAR_PATTERN_SIGNALKEY; canDetect = config.CanDetect(iPattern); if (canDetect) { // has = IsSignalKeyBarPattern( bar, iDir, config.pinBarShadowApprovedMultiplier, config.pinBarRangeMultiplier, config.pinBarForceDirection // ); // canDetectBullish = config.CanDetect( iPattern, X_DIRECTION_BULLISH // ); canDetectBearish = config.CanDetect( iPattern, X_DIRECTION_BEARISH // ); // isBullish = has && IsXBullish(iDir) && canDetectBullish; isBearish = has && IsXBearish(iDir) && canDetectBearish; // canDetect = isBullish || isBearish; if (canDetect) { // analysis.AddPattern( iPattern, iDir // ); } } // // Zone Detectors ... // // OB ... iPattern = X_BAR_PATTERN_OB; canDetect = config.CanDetect(iPattern); if (canDetect) { // has = barAnalyser.IsOB( bar, iZone, config.fvgForceType, config.obForceTwoBar // ); // canDetectBullish = config.CanDetect( iPattern, X_DIRECTION_BULLISH // ); canDetectBearish = config.CanDetect( iPattern, X_DIRECTION_BEARISH // ); // isBullish = has && iZone.IsBullish() && canDetectBullish; isBearish = has && iZone.IsBearish() && canDetectBearish; // canDetect = isBullish || isBearish; if (canDetect) { // analysis.AddPattern( iPattern, iZone.dir // ); // analysis.ob = iZone; } } // // FVG ... iPattern = X_BAR_PATTERN_FVG; canDetect = config.CanDetect(iPattern); if (canDetect) { // has = barAnalyser.IsFVG( bar, iZone, config.fvgForceType // ); // canDetectBullish = config.CanDetect( iPattern, X_DIRECTION_BULLISH // ); canDetectBearish = config.CanDetect( iPattern, X_DIRECTION_BEARISH // ); // isBullish = has && iZone.IsBullish() && canDetectBullish; isBearish = has && iZone.IsBearish() && canDetectBearish; // canDetect = isBullish || isBearish; if (canDetect) { // analysis.AddPattern( iPattern, iZone.dir // ); // analysis.fvg = iZone; } } // // Support ... iPattern = X_BAR_PATTERN_SUPPORT; canDetect = config.CanDetect(iPattern); if (canDetect) { // has = HasSupport( bar, iSwing, config.supportAndResistanceValidationLength, config.supportAndResistanceLoopbackLength // ); if (has) { // has = ToSupportBox( iSwing, iZone, bar.time, config.supportAndResistanceValidationLength // ); if (has) { // analysis.AddPattern( iPattern, iZone.dir // ); // analysis.support = iZone; } } } // // Resistance ... iPattern = X_BAR_PATTERN_RESISTANCE; canDetect = config.CanDetect(iPattern); if (canDetect) { // has = HasResistance( bar, iSwing, config.supportAndResistanceValidationLength, config.supportAndResistanceLoopbackLength // ); if (has) { // has = ToResistanceBox( iSwing, iZone, bar.time, config.supportAndResistanceValidationLength // ); if (has) { // analysis.AddPattern( iPattern, iZone.dir // ); // analysis.resistance = iZone; } } } // // Validate Analysis ... result = analysis.IsValid(); // // Cleanup Resources ... iZone.Clean(); iSwing.Clean(); CleanDirection(iDir); // return result; } /** * Collect Required Order Blocks ... * * @param bar: XOHCL, reference to Specified Bar ... * @param dest: XBoxZone, collection reference to holds detected zones ... * @param zonesLoopback: int, zones detection loopback ... * @param maxRequiredZone: int, number of required zones ... * @param loopback: int, max allowed loopback lenght for zone Detection ... * * @return ( int ) */ 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; } /** * Collect Required Fair Value Gaps ... * * @param bar: XOHCL, reference to Specified Bar ... * @param dest: XBoxZone, collection reference to holds detected zones ... * @param zonesLoopback: int, zones detection loopback ... * @param maxRequiredZone: int, number of required zones ... * @param loopback: int, max allowed loopback lenght for zone Detection ... * * @return ( int ) */ 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; } /** * Collect Required Support and Resistance Zones ... * * @param bar: XOHCL, reference to Specified Bar ... * @param dest: XBoxZone, collection reference to holds detected zones ... * @param zonesLoopback: int, zones detection loopback ... * @param zonesValidationLength: int, zones validation length ... * @param maxRequiredZone: int, number of required zones ... * @param loopback: int, max allowed loopback lenght for zone Detection ... * * @return ( int ) */ 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; } /** * Detect and Collect Required Zones ... * * @param bar: XOHCL, reference to Specified Bar ... * @param zones: XBoxZone, collection reference to holds detected zones ... * @param validateZones: bool, Specified to Detect only Valid Zones ... * @param containsOBs: bool, Flag to use Order Block Zones ... * @param containsFVGs: bool, Flag to use Fair Value Gap Zones ... * @param containsSupports: bool, Flag to use Support Zones ... * @param containsResistancess: bool, Flag to use Resistance Zones ... * @param forDir: ENUM_X_DIRECTION, Specified Zones Direction for Detecting ... * @param sortby: ENUM_X_SORT_BY, Specified Zones Sorting Factor ... * @param sortDir: ENUM_X_DIRECTION, Specified Zones Sorting Direction ... * @param zonesRangeValidationFactor: double, Specified Zones Range Validation in Points ... * @param zonesLoopback: int, loop back for Zones Detection ... * @param zonesValidationLength: int, zones Validation Length ... * @param count: int, number of required Zones ... * @param loopback: int, max allowed looping back lenght for detection ... * * @return ( int ) */ int DetectZones( XOHCL &bar, XBoxZone &zones[], bool validateZones = true, bool containsOBs = true, bool containsFVGs = true, bool containsSupports = true, bool containsResistancess = true, int loopback = 500, ENUM_X_DIRECTION forDir = X_DIRECTION_NONE, ENUM_X_SORT_BY sortBy = X_SORT_BY_DATE, ENUM_X_DIRECTION sortDir = X_DIRECTION_BEARISH, double zonesRangeValidationFactor = 10, int zonesLoopback = 5, int zonesValidationLength = 5, int count = 0 // ) { // int result = 0; // // Prepare ... XClean(zones); // // Normalize ... count = NormalizeInt(count, 0); loopback = NormalizeInt(loopback, 50); zonesLoopback = NormalizeInt(zonesLoopback, 2); zonesValidationLength = NormalizeInt(zonesValidationLength, 3); // // Validate ... bool has = bar.IsValid() && IsXValid(sortDir) && IsXValid(sortBy) && (containsOBs || containsFVGs || containsSupports || containsResistancess); if (!has) { return result; } // XOHCL iBar; XOHCL tmpBar; XPivot tmpPivot; XBoxZone tmpZone; ENUM_X_DIRECTION tmpDir; int idx = bar.Index(); while (idx < bar.Index() + loopback) { // idx++; // iBar.Clean(); tmpBar.Clean(); tmpZone.Clean(); tmpPivot.Clean(); // has = bar.BarAt(idx, iBar); if (!has) { continue; } // // Collecting Zones ... // // Support ... if (containsSupports) { // if (!HasDirection(forDir) || IsXBullish(forDir)) { // has = HasSupport(iBar, tmpBar, zonesValidationLength, zonesLoopback); if (has) { // has = ToBox(tmpBar, tmpZone, X_DIRECTION_BULLISH, X_BAR_PATTERN_SUPPORT); if (has) { AddIfNotExists(tmpZone, zones); } } } } // // Resistance ... if (containsResistancess) { // if (!HasDirection(forDir) || IsXBearish(forDir)) { // has = HasResistance(iBar, tmpBar, zonesValidationLength, zonesLoopback); if (has) { // has = ToBox(tmpBar, tmpZone, X_DIRECTION_BEARISH, X_BAR_PATTERN_RESISTANCE); if (has) { AddIfNotExists(tmpZone, zones); } } } } // // Order Block ... if (containsOBs) { // has = HasOB(iBar, tmpDir, tmpZone, zonesLoopback); if (has && (!HasDirection(forDir) || tmpDir == forDir)) { AddIfNotExists(tmpZone, zones); } } // // Fair Value Gaps ... if (containsFVGs) { // has = HasFVG(iBar, tmpDir, tmpZone, zonesLoopback); if (has && (!HasDirection(forDir) || tmpDir == forDir)) { AddIfNotExists(tmpZone, zones); } } } // // Validate Zones Exists ... result = ArraySize(zones); has = IsValidSize(result); if (!has) { return result; } // // Update Zones Time ... UpdateToTime(zones, bar.time); // // Validate Zones ... if (validateZones) { // // Apply Zones Validation Here ... RemoveBreakedZones(zones, true); } // // Validate Zones Range ... if (zonesRangeValidationFactor > 0) { // double points = GetPoints(bar.symbol); double minAllowedRange = points * zonesRangeValidationFactor; ValidateZonesRange(zones, minAllowedRange); } // // Apply Sorting ... Sort(zones, sortBy, sortDir); // // Validate Zones Count ... if (count > 0) { CleanupArray(zones, count); } // result = ArraySize(zones); // // Cleanup ... iBar.Clean(); tmpBar.Clean(); tmpZone.Clean(); tmpPivot.Clean(); // return result; } /** * Filter Zones ... * * @param bar: XOHCL, reference to Specified Filtering Bar ... * @param source: XBoxZone, reference collection to hold's filtered zones ... * @param filterDir: ENUM_X_DIRECTION, specified Filter Direction ... * @param priceType: ENUM_X_PRICE, Specified Bar's Price type to Use for Filtering Zones ... * @param forDir: ENUM_X_DIRECTION, Specified Zone's Direction to Handle Filtering ... * * @return ( int ) */ 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: // // // Tools / Actions ... /** * 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 ... * @param sortDir: ENUM_X_DIRECTION, Sort Zones in Direction ... * @param maxAllowed: int, Specified Max Allowed Zones ... */ void CheckZones( XOHCL &forBar, XBoxZone &_zones[], ENUM_X_SORT_BY sortBy = X_SORT_BY_DATE, ENUM_X_DIRECTION sortDir = X_DIRECTION_BEARISH, int maxAllowed = 50 // ) { // // Normalize ... maxAllowed = NormalizeInt(maxAllowed, 0); // // Validate ... bool has = forBar.IsValid() && HasChild(_zones); if (!has) { return; } // // Looping Through Zones ... int count = ArraySize(_zones); for (int i = 0; i < count; i++) { // // Check Break ... has = IsXValid(_zones[i].breakAt); if (has) { continue; } // _zones[i].to = forBar.time; // // Check for Test ... has = IsTested( forBar, _zones[i] // ); if (has) { // Add( forBar.time, _zones[i].tests // ); } // // Check for Inside ... has = IsInside( forBar, _zones[i] // ); if (has) { // Add( forBar.time, _zones[i].insides // ); } // // Check for Break ... has = IsBreaked( forBar, _zones[i] // ); if (has) { // Add( forBar.time, _zones[i].breaks // ); } // // Check for Act ... has = IsActed( forBar, _zones[i] // ); if (has) { // Add( forBar.time, _zones[i].acteds // ); } // // Check for FakeBreakes ... has = IsFakeBreaked( forBar, _zones[i] // ); if (has) { // Add( forBar.time, _zones[i].fakeBreaks // ); } // // Check for Valid Breakes ... has = IsValidBreaked( forBar, _zones[i] // ); if (has) { _zones[i].breakAt = forBar.time; } } // // Apply Sort and Cleanup ... Sort( _zones, sortBy, sortDir, maxAllowed // ); } // // Private ... private: // // Props ... XCBarAnalyser *barAnalyser; // // Helpers ... /** * Clean Specified Referenced Direction ... * * @param dir: ENUM_X_DIRECTION */ void CleanDirection(ENUM_X_DIRECTION &dir) { dir = X_DIRECTION_NONE; } }; //