/////////////////////////////////////////////////////// // // 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" // // Definitions ... // // Implementation ... class XCMarketPatternDetector : public XCBase { // // Public ... public: // // Props ... // // Constructor ... XCMarketPatternDetector() { } // // Deconstructor ... ~XCMarketPatternDetector() { } // // 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: int, a Multipler for approve Momentum ... * * @return ( bool ) */ bool IsMomentumBar( XOHCL &bar, ENUM_X_DIRECTION &dir, int requiredBars = 3, int approvedMultiplier = 2 // ) { // bool result = false; // // Prepare ... CleanDirection(dir); // // Normalizing ... requiredBars = NormalizeInt(requiredBars, 3, 10); approvedMultiplier = NormalizeInt(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: int, 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, int shadowApprovedMultiplier = 3, double minimumPinBarRangeMultiplier = 4, bool forceDirection = false // ) { // bool result = false; // // Prepare ... CleanDirection(dir); // // Normalizing ... shadowApprovedMultiplier = NormalizeInt(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; } bool HasTrend( 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 ... // iSwing.Clean(); SpecifiedClean(swingLows); SpecifiedClean(swingHighs); // return result; } // // Protected ... protected: // // // Private ... private: // // // Helpers ... /** * Clean Specified Referenced Direction ... * * @param dir: ENUM_X_DIRECTION */ void CleanDirection(ENUM_X_DIRECTION &dir) { dir = X_DIRECTION_NONE; } }; //