/////////////////////////////////////////////////////// // // 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 ... // XBoxZone zones[]; XBoxZone majorSupport; XBoxZone minorSupport; XBoxZone majorResistance; XBoxZone minorResistance; // // Constructor ... XCMarketPatternDetector() { barAnalyser = new XCBarAnalyser(); } // // Deconstructor ... ~XCMarketPatternDetector() { // delete barAnalyser; ZeroMemory(barAnalyser); } // // Actions / Helpers ... // double CalculateQuarter() { // double result = -1; // // Validate ... bool has = majorSupport.IsValid() && majorResistance.IsValid(); if (!has) { return result; } // result = majorSupport.upper + ((majorResistance.lower - majorSupport.upper) / 2); // return result; } // // 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; } // // 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 pullback 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; } bool IsContinuationPullbackPattern( XOHCL &bar, XBoxZone &zone, XBoxZone &continuationalZones[], ENUM_X_DIRECTION &dir, XOHCL &continuationalBar, int continuationLength = 3, bool forceContinuationHasZone = true, bool forceContinuationHasPattern = true, int pullbackLength = 2, bool forcePullbackBreak = false, int zonesLoopback = 5, int zonesValidationLength = 5 // ) { // bool result = false; // // Prepare ... zone.Clean(); CleanDirection(dir); continuationalBar.Clean(); XClean(continuationalZones); // // Normalize ... zonesLoopback = NormalizeInt(zonesLoopback, 3); pullbackLength = NormalizeInt(pullbackLength, 2); continuationLength = NormalizeInt(continuationLength, 2); zonesValidationLength = NormalizeInt(zonesValidationLength, 3); // // Validate ... result = bar.IsValid(); if (!result) { return result; } // // First we Have to Detect a Pullback ... result = IsPullbackPattern(bar, zone, dir, pullbackLength, forcePullbackBreak); // // Select PullBack Start Bar ... XOHCL startBar; result = result && zone.FromBar(startBar); // // Check Continuation Direction ... XOHCL iBar; int start = startBar.Index() + 1; int end = start + continuationLength; for (int i = start; i < end && result; i++) { // // Initialize Indexed Bar ... iBar.Clean(); result = result && bar.BarAt(i, iBar); // // Check Direction Same ... result = result && dir == iBar.GetDirection(); // if (!result) { break; } } // // Setting Continuational Bar ... if (result) { continuationalBar = iBar; } // // Apply Zone Force ... if (result && forceContinuationHasZone) { // XBoxZone tmps[]; // // Collectiong Support and Resistances ... CollectZones(startBar, tmps, zonesLoopback, zonesValidationLength, 0, zonesLoopback * 2); Copy(tmps, continuationalZones, false); // // Collecting Order Blocks ... // CollectOBs(startBar, tmps, zonesLoopback, 0, zonesLoopback * 2); // Copy(tmps, continuationalZones, false); // // Collectiong Fair Value Gaps ... CollectFVGs(startBar, tmps, zonesLoopback, 0, zonesLoopback * 2); Copy(tmps, continuationalZones, false); // // Extract Directional Zones ... XClean(tmps); ExtractByDirection(tmps, continuationalZones, zone.dir); Copy(tmps, continuationalZones); // // Validate Result ... result = result && HasChild(continuationalZones); // XClean(tmps); } // // Apply Pattern Force ... if (result && forceContinuationHasPattern) { // bool has = false; int pattersCount = 0; ENUM_X_DIRECTION iPatternDir; for (int i = start; i < end; i++) { // iBar.Clean(); CleanDirection(iPatternDir); // has = bar.BarAt(i, iBar); if (!has) { break; } // // Checking Required Patterns ... // // Pin Bar ... has = IsPinnedBar(iBar, iPatternDir); has = has && iPatternDir == zone.dir; if (has) { pattersCount++; } // // Engulfed Bar ... has = IsEngulfedBar(iBar, iPatternDir); has = has && iPatternDir == zone.dir; if (has) { pattersCount++; } // // Momentum Bar ... has = IsMomentumBar(iBar, iPatternDir); has = has && iPatternDir == zone.dir; if (has) { pattersCount++; } // // Piercing ... has = IsPiercingPattern(iBar, iPatternDir); has = has && iPatternDir == zone.dir; if (has) { pattersCount++; } // // SignalKey ... has = IsSignalKeyBarPattern(iBar, iPatternDir); has = has && iPatternDir == zone.dir; if (has) { pattersCount++; } } // result = result && IsValidSize(pattersCount); } // // Cleanup ... if (!result) { // zone.Clean(); CleanDirection(dir); continuationalBar.Clean(); XClean(continuationalZones); } iBar.Clean(); startBar.Clean(); // return result; } 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 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 maxRequiredZone = 0, int loopback = 100 // ) { // bool result = false; // // Prepare ... XClean(orderFlow); CleanDirection(dir); // // 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() // ); // 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; } // // 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; } // // 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(); // // Update Quarter ... if (result) { // // Retrieve Previous Bar ... XOHCL pBar; has = bar.GetPreviousBar(pBar); if (has) { // // Update Quarter ... UpdateZones( bar, analysis.quarterActions, config.quarterZonesValidationLength, // Zones Validation Length ... config.quarterZonesRequiredToStart, // Zones Count to Start Processing ... config.quarterZoneDetectionLoopback // Zones Detection Loopback ... ); // // Fill Quarter Props ... analysis.majorSupport = majorSupport; analysis.minorSupport = minorSupport; analysis.quarter = CalculateQuarter(); analysis.majorResistance = majorResistance; analysis.minorResistance = minorResistance; // // Update To Times ... if (analysis.majorSupport.IsValid()) { analysis.majorSupport.to = bar.time; } if (analysis.minorSupport.IsValid()) { analysis.minorSupport.to = bar.time; } if (analysis.majorResistance.IsValid()) { analysis.majorResistance.to = bar.time; } if (analysis.minorResistance.IsValid()) { analysis.minorResistance.to = bar.time; } } } // // Cleanup Resources ... iZone.Clean(); iSwing.Clean(); CleanDirection(iDir); // return result; } /** * Update and Manage Support and Resistance Zones ... * * @param bar: XOHCL, reference to Specified Bar ... * @param actions: ENUM_X_DETECTOR_ZONE_ACTION, refernce collection to Notify happens actions ... * @param validationLength: int, Validation Length for Zones ... * @param requiredZones: int, Number of required Zones to collecting ... * @param loopback: int, Max Allowed Loopback Bars for Collecting ... * * @return ( int ) */ int UpdateZones( XOHCL &bar, ENUM_X_DETECTOR_ZONE_ACTION &actions[], int validationLength = 3, int requiredZones = 10, int loopback = 1500 // ) { // int result = 0; // // Prepare ... XClean(actions); // // Normalize ... loopback = NormalizeInt(loopback, 100); requiredZones = NormalizeInt(requiredZones, 5); validationLength = NormalizeInt(validationLength, 2); // // Validate ... bool has = bar.IsValid(); if (!has) { return result; } // int barIndex = bar.Index(); // // Collect or Manage Zones ... XOHCL zoneBar; XBoxZone iZone; bool hasZone = HasChild(zones); int zonesCount = ArraySize(zones); int zoneDetectionLoopback = (validationLength * 2); if (!hasZone) { // XOHCL iBar; int start = barIndex; int end = barIndex + loopback; for (int i = start; i < end; i++) { // // Extract Detected Zones ... iBar.Clean(); has = bar.BarAt(i, iBar); if (!has) { continue; } // // Check Support ... iZone.Clean(); zoneBar.Clean(); has = HasSupport( iBar, zoneBar, validationLength, // Zone Validation Length ... zoneDetectionLoopback // Zone Detection Loopback ... ); has = has && ToSupportBox(zoneBar, iZone, bar.time); if (has) { // AddIfNotExists( iZone, zones // ); } // // Check Resistance ... iZone.Clean(); zoneBar.Clean(); has = HasResistance( iBar, zoneBar, validationLength, // Zone Validation Length ... zoneDetectionLoopback // Zone Detection Loopback ... ); has = has && ToResistanceBox(zoneBar, iZone, bar.time); if (has) { // AddIfNotExists( iZone, zones // ); } // // Validate Number of Zones ... zonesCount = ArraySize(zones); if (zonesCount >= requiredZones) { break; } } // iBar.Clean(); iZone.Clean(); zoneBar.Clean(); // // Update Has Zones ... hasZone = HasChild(zones); zonesCount = ArraySize(zones); } // // Manage Exists Zones ... if (hasZone) { // // Update Zones To Time ... UpdateToTime(zones, bar.time); // // Validate Zones ... CheckZones(bar, zones); // // Remove Breaked Zones ... RemoveBreakedZones(zones); // hasZone = HasChild(zones); zonesCount = ArraySize(zones); } // // Minimum Exists Zones for Detecting majors ... int minNumberOfZonesForMajors = 5; bool canLookupMajor = hasZone && zonesCount >= minNumberOfZonesForMajors; // // Supports ... // // Check Zones Existances ... bool hasMajorSupport = majorSupport.IsValid(); bool hasMinorSupport = minorSupport.IsValid(); // // Check Major Support State ... if (hasMajorSupport) { // XOHCL pBar; has = bar.GetPreviousBar(pBar); if (has) { // bool isBreaked = pBar.close < majorSupport.lower; if (isBreaked) { // int idx = -1; has = FindIndex(idx, majorSupport, zones); if (has) { zones[idx].breakAt = pBar.time; } majorSupport.Clean(); minorSupport.Clean(); hasMajorSupport = false; hasMinorSupport = false; Add( X_DETECTOR_ZONE_ACTION_MAJOR_SUPPORT_BREAKED, actions // ); } } // pBar.Clean(); } // // Look For Major Support ... if (!hasMajorSupport) { // minorSupport.Clean(); hasMinorSupport = false; // // Lookup Major ... if (canLookupMajor) { // int idx = GetLowestByDir(zones, X_DIRECTION_BULLISH); hasMajorSupport = IsValidIndex(idx) && !IsXValid(zones[idx].breakAt); if (hasMajorSupport) { // majorSupport = zones[idx]; Add( X_DETECTOR_ZONE_ACTION_MAJOR_SUPPORT_DETECTED, actions // ); } } } // // Resistances ... // // Check Zones Existances ... bool hasMajorResistance = majorResistance.IsValid(); bool hasMinorResistance = minorResistance.IsValid(); // // Check Major Resistance State ... if (hasMajorResistance) { // XOHCL pBar; has = bar.GetPreviousBar(pBar); if (has) { // bool isBreaked = pBar.close > majorResistance.upper; if (isBreaked) { // int idx = -1; has = FindIndex(idx, majorResistance, zones); if (has) { zones[idx].breakAt = pBar.time; } majorResistance.Clean(); minorResistance.Clean(); hasMajorResistance = false; hasMinorResistance = false; Add( X_DETECTOR_ZONE_ACTION_MAJOR_RESISTANCE_BREAKED, actions // ); } } // pBar.Clean(); } // // Look For Major Resistance ... if (!hasMajorResistance) { // minorResistance.Clean(); hasMinorResistance = false; // // Lookup Major ... if (canLookupMajor) { // int idx = GetHighestByDir(zones, X_DIRECTION_BEARISH); hasMajorResistance = IsValidIndex(idx); if (hasMajorResistance) { // majorResistance = zones[idx]; Add( X_DETECTOR_ZONE_ACTION_MAJOR_RESISTANCE_DETECTED, actions // ); } } } // // Check Majors Exixsts ... has = hasMajorSupport && hasMajorResistance; if (has) { // double quarter = CalculateQuarter(); // // For Looking up Minor Support, we // have to Ensure Major Support Exists ... if (hasMajorSupport) { // majorSupport.to = bar.time; // // Look for Minor Support ... if (!hasMinorSupport) { // XBoxZone _supports[]; int _supportsCount = ExtractByDirection( _supports, zones, X_DIRECTION_BULLISH // ); _supportsCount = RemoveBreakedZones(_supports); has = IsValidSize(_supportsCount); if (has) { // // Remove Major ... Remove( majorSupport, _supports // ); // // Count Remain Zones ... _supportsCount = ArraySize(_supports); has = IsValidSize(_supportsCount); if (has) { // // Minors Selected by Youngest ... int idx = quarter > 0 ? GetYoungestBelow(quarter, _supports) : GetYoungest(_supports); hasMinorSupport = IsValidIndex(idx) && !IsXValid(_supports[idx].breakAt); if (hasMinorSupport) { // minorSupport = _supports[idx]; minorSupport.to = bar.time; minorSupport.from = minorSupport.at; Add( X_DETECTOR_ZONE_ACTION_MINOR_SUPPORT_DETECTED, actions // ); } } } // XClean(_supports); } // // Validate Minor Support Place ... if (quarter > 0 && hasMinorSupport) { // hasMinorSupport = minorSupport.upper < quarter; if (!hasMinorSupport) { // int idx = -1; has = FindIndex( idx, minorSupport, zones // ); if (has) { zones[idx].breakAt = bar.time; } minorSupport.Clean(); } } // // Refine exists Minor Support ... if (hasMinorSupport) { // minorSupport.to = bar.time; // XOHCL pBar; has = bar.GetPreviousBar(pBar); if (has) { // // Check Break ... bool isBreaked = pBar.close < minorSupport.lower; if (isBreaked) { // minorSupport.Clean(); Add( X_DETECTOR_ZONE_ACTION_MINOR_SUPPORT_BREAKED, actions // ); } // // Check Test ... bool isTested = !isBreaked && pBar.low < minorSupport.upper && pBar.low > minorSupport.lower && bar.close > minorSupport.lower && bar.open > minorSupport.lower; if (isTested) { // Add( X_DETECTOR_ZONE_ACTION_MINOR_SUPPORT_RETESTED, actions // ); } // // Check Refine ... bool canRefine = !isBreaked && pBar.low < minorSupport.lower && pBar.close > minorSupport.lower; if (canRefine) { // minorSupport.upper = minorSupport.lower; minorSupport.lower = pBar.low; Add( pBar.time, minorSupport.refines // ); Add( X_DETECTOR_ZONE_ACTION_MINOR_SUPPORT_REFINED, actions // ); } // // Check New Minor Support ... has = !isTested && !canRefine; if (has) { // // Check Above Minor Support has Support ... XBoxZone _supports[]; int _supportsCount = ExtractByDirection( _supports, zones, X_DIRECTION_BULLISH // ); Remove(majorSupport, _supports); Remove(minorSupport, _supports); RemoveBreakedZones(_supports); _supportsCount = ArraySize(_supports); has = IsValidSize(_supportsCount); if (has) { // int idx = GetLowestAfter(minorSupport.from, _supports); hasMinorSupport = IsValidIndex(idx) && (quarter <= 0 ? true : _supports[idx].upper < quarter); if (hasMinorSupport) { // minorSupport = _supports[idx]; minorSupport.to = bar.time; minorSupport.from = minorSupport.at; Add( X_DETECTOR_ZONE_ACTION_MINOR_SUPPORT_DETECTED, actions // ); } } } } // pBar.Clean(); } } // // For Looking up Minor Resistance, we // have to Ensure Major Resistance Exists ... if (hasMajorResistance) { // majorResistance.to = bar.time; // // Look for Minor Resistance ... if (!hasMinorResistance) { // XBoxZone _resistances[]; int _resistancesCount = ExtractByDirection( _resistances, zones, X_DIRECTION_BEARISH // ); _resistancesCount = RemoveBreakedZones(_resistances); has = IsValidSize(_resistancesCount); if (has) { // // Remove Major ... Remove( majorResistance, _resistances // ); // // Count Remain Zones ... _resistancesCount = ArraySize(_resistances); has = IsValidSize(_resistancesCount); if (has) { // // Minors Selected Youngest ... int idx = GetYoungestAbove(quarter, _resistances); hasMinorResistance = IsValidIndex(idx); if (hasMinorResistance) { // minorResistance = _resistances[idx]; minorResistance.to = bar.time; minorResistance.from = minorResistance.at; Add( X_DETECTOR_ZONE_ACTION_MINOR_RESISTANCE_DETECTED, actions // ); } } } // XClean(_resistances); } // // Validate Minor Support Place ... if (quarter > 0 && hasMinorResistance) { // hasMinorResistance = minorResistance.lower > quarter; if (!hasMinorResistance) { // int idx = -1; has = FindIndex( idx, minorResistance, zones // ); if (has) { zones[idx].breakAt = bar.time; } minorResistance.Clean(); } } // // Refine exists Minor Resistance ... if (hasMinorResistance) { // minorResistance.to = bar.time; // // Check Retesting ... XOHCL pBar; has = bar.GetPreviousBar(pBar); if (has) { // // Check Break ... bool isBreaked = pBar.close > minorResistance.upper; if (isBreaked) { // minorResistance.Clean(); Add( X_DETECTOR_ZONE_ACTION_MINOR_RESISTANCE_BREAKED, actions // ); } // // Check Test ... bool isTested = !isBreaked && pBar.high > minorResistance.lower && pBar.high < minorResistance.upper && bar.close < minorResistance.upper && bar.open < minorResistance.upper; if (isTested) { // Add( X_DETECTOR_ZONE_ACTION_MINOR_RESISTANCE_RETESTED, actions // ); } // // Check Refine ... bool canRefine = !isBreaked && pBar.high > minorResistance.upper && pBar.close < minorResistance.upper; if (canRefine) { // minorResistance.lower = minorResistance.upper; minorResistance.upper = pBar.high; Add( pBar.time, minorResistance.refines // ); Add( X_DETECTOR_ZONE_ACTION_MINOR_RESISTANCE_REFINED, actions // ); } // // Check New Minor Resistace ... has = !isTested && !canRefine; if (has) { // // Check Above Minor Resistance has Resistance ... XBoxZone _resistances[]; int _resistancesCount = ExtractByDirection( _resistances, zones, X_DIRECTION_BEARISH // ); Remove(majorResistance, _resistances); Remove(minorResistance, _resistances); RemoveBreakedZones(_resistances); _resistancesCount = ArraySize(_resistances); has = IsValidSize(_resistancesCount); if (has) { // int idx = GetHighestAfter(minorResistance.from, _resistances); hasMinorResistance = IsValidIndex(idx) && (quarter <= 0 ? true : _resistances[idx].lower > quarter); if (hasMinorResistance) { // minorResistance = _resistances[idx]; minorResistance.to = bar.time; minorResistance.from = minorResistance.at; Add( X_DETECTOR_ZONE_ACTION_MINOR_RESISTANCE_DETECTED, actions // ); } } } } // pBar.Clean(); } } } else { // int idx = -1; // has = minorSupport.IsValid() && FindIndex( idx, minorSupport, zones // ); if (has) { zones[idx].breakAt = bar.time; } minorSupport.Clean(); hasMinorSupport = false; // has = minorResistance.IsValid() && FindIndex( idx, minorResistance, zones // ); if (has) { zones[idx].breakAt = bar.time; } minorResistance.Clean(); hasMinorResistance = false; } // // Check Bar Zones to Update Zones ... // // Check Support ... iZone.Clean(); zoneBar.Clean(); has = HasSupport( bar, zoneBar, validationLength, // Zone Validation Length ... zoneDetectionLoopback // Zone Detection Loopback ... ); has = has && ToSupportBox(zoneBar, iZone, bar.time); if (has) { // AddIfNotExists( iZone, zones // ); } // // Check Resistance ... iZone.Clean(); zoneBar.Clean(); has = HasResistance( bar, zoneBar, validationLength, // Zone Validation Length ... zoneDetectionLoopback // Zone Detection Loopback ... ); has = has && ToResistanceBox(zoneBar, iZone, bar.time); if (has) { // AddIfNotExists( iZone, zones // ); } // // Actions Counting ... result = ArraySize(actions); // // Cleanup ... iZone.Clean(); zoneBar.Clean(); // 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; } /** * 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; } }; //