/////////////////////////////////////////////////////// // // 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-poi.lib.mq5" // // Definitions ... // // Implementation ... class XCMarketPatternDetector : public XCBase { // // Public ... public: // // Props ... // // Constructor ... XCMarketPatternDetector() { barAnalyser = new XCBarAnalyser(); } // // Deconstructor ... ~XCMarketPatternDetector() { // delete barAnalyser; ZeroMemory(barAnalyser); } // // Actions / Helpers ... /** * 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 IsStartPattern( 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 ... * @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; } // // 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; } // // Protected ... protected: // // // 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; } }; //