/////////////////////////////////////////////////////// // // SaherElm IT Center MQL5 Indicator // ------------------------------------------------- // Name: XCXCAEAPOIDetector ... // Description: Class for XCAEA POI Detector ... // // // Maintainer: // ------------ // Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) // ////////////////////////////////////////////////////// // // Global Properties ... #property library #property copyright "Copyright 2023, SaherElm IT Center" #property link "https://saherelm.ir" #property version "1.00" #property description "SaherElm Class for XCAEA POI Detector" #property strict // // Imports ... #include "../../Classes/x-saherelm.x-bar.analyser.class.mq5" #include "../../Classes/x-saherelm.x-poi.drawer.class.mq5" #include "../Helpers/xcaea.helper.mq5" // // Definitions ... // enum ENUM_XCA_PIVOTS { XCA_NONE, // None XCA_LL, // LowestLow XCA_HH, // HighestHigh XCA_KI, // KI XCA_SWL, // SWL XCA_SWH, // SWH XCA_VALE, // VALE XCA_PEAK, // PEAK XCA_FVG_BULL, // FVGBull XCA_FVG_BEAR, // FVGBear XCA_RSI_COOS, // RSICOOS XCA_RSI_CUOB, // RSICUOB XCA_RSI_PEAK, // RSIPeak XCA_RSI_VALE, // RSIVale XCA_CCI_COOS, // CCICOOS XCA_CCI_CUOB, // CCICUOB XCA_CCI_PEAK, // CCIPeak XCA_CCI_VALE, // CCIVale XCA_KI_BULL, // KIBull XCA_KI_BEAR, // KIBear XCA_TKI_BULL, // TKIBull XCA_TKI_BEAR, // TKIBear XCA_PEAKSWHRES, // PeakSWHRes XCA_VALESWLSUP, // ValeSWLSup XCA_TREND_BULL, // TrendBull XCA_TREND_BEAR, // TrendBear XCA_TKITRND_BULL, // TKITRNDBull XCA_TKITRND_BEAR, // TKITRNDBear }; // bool IsValid(ENUM_XCA_PIVOTS value) { // bool result = false; // result = value != XCA_NONE; // return result; } // string ToString(ENUM_XCA_PIVOTS value) { // string result = NULL; // result = EnumToString(value); // return result; } // struct XCAPivot { // // Props ... datetime to; double value; string symbol; datetime from; double reserve; ENUM_XCA_PIVOTS type; ENUM_TIMEFRAMES period; // double values[]; // // Constructor ... XCAPivot() { Clean(); } // // Tools ... /** * Cleanup ... */ void Clean() { // value = 0; to = NULL; reserve = 0; from = NULL; symbol = NULL; period = NULL; type = XCA_NONE; // Clean(values); // ZeroMemory(this); } /** * Validate ... * * @return ( bool ) */ bool IsValid() { // bool result = false; // result = from < to && value != 0 && IsValid(to) && IsValid(from) && IsValid(type) && IsValid(symbol) && IsValid(period); // return result; } /** * Check a Model is Same as this or not ... * * @param pivot: XCAPivot ... * * @return ( bool ) */ bool IsSameAs(XCAPivot &pivot) { // bool result = false; // result = IsValid() && pivot.IsValid(); if (!result) { return result; } // result = to == pivot.to && from == pivot.from && type == pivot.type && value == pivot.value && symbol == pivot.symbol && period == pivot.period; // return result; } /** * Retrieve To Index ... * * @param forPeriod: ENUM_TIMEFRAMES, Specified Period ... * * @return ( int ) */ int ToIndex( ENUM_TIMEFRAMES forPeriod = NULL // ) { // int result = -1; // if (!IsValid()) { return result; } // if (!IsValid(forPeriod)) { forPeriod = period; } // result = GetBarIndex( symbol, forPeriod, to // ); // return result; } /** * Retrieve From Index ... * * @param forPeriod: ENUM_TIMEFRAMES, Specified Period ... * * @return ( int ) */ int FromIndex( ENUM_TIMEFRAMES forPeriod = NULL // ) { // int result = -1; // if (!IsValid()) { return result; } // if (!IsValid(forPeriod)) { forPeriod = period; } // result = GetBarIndex( symbol, forPeriod, from // ); // return result; } /** * Retrieve Age of Pivot ... * * @param forPeriod: ENUM_TIMEFRAMES, Specified Period ... * * @return ( int ) */ int GetAge( ENUM_TIMEFRAMES forPeriod = NULL // ) { // int result = 0; // if (!IsValid()) { return result; } // if (!IsValid(forPeriod)) { forPeriod = period; } // int toIDX = ToIndex(forPeriod); int fromIDX = FromIndex(forPeriod); // result = fromIDX - toIDX; // return result; } /** * Converts Pivot to Box ... * * @param box: XBoxZone instance reference ... * * @return ( bool ) */ bool AsBox( XBoxZone &box // ) { // bool result = false; // box.Clean(); // result = IsValid(); if (!result) { return result; } // ENUM_X_DIRECTION iDir = X_DIRECTION_NONE; switch (type) { // case XCA_LL: case XCA_SWL: case XCA_VALE: case XCA_KI_BULL: case XCA_FVG_BULL: case XCA_RSI_COOS: case XCA_RSI_VALE: case XCA_CCI_COOS: case XCA_CCI_VALE: case XCA_TKI_BULL: case XCA_TREND_BULL: case XCA_VALESWLSUP: case XCA_TKITRND_BULL: iDir = X_DIRECTION_BULLISH; break; // case XCA_HH: case XCA_SWH: case XCA_PEAK: case XCA_KI_BEAR: case XCA_FVG_BEAR: case XCA_RSI_CUOB: case XCA_RSI_PEAK: case XCA_CCI_CUOB: case XCA_CCI_PEAK: case XCA_TKI_BEAR: case XCA_TREND_BEAR: case XCA_PEAKSWHRES: case XCA_TKITRND_BEAR: iDir = X_DIRECTION_BEARISH; break; } // result = HasDirection(iDir); if (!result) { return result; } // bool isBullish = IsBullish(iDir) && value < reserve; // bool isBearish = IsBearish(iDir) && value > reserve; // result = isBullish || isBearish; if (!result) { return result; } // box.to = to; box.dir = iDir; box.from = from; box.symbol = symbol; box.period = period; // string typeStr = ToString(type); if (type == XCA_KI_BULL || type == XCA_KI_BEAR) { // typeStr = "XCA_KI"; } else if (type == XCA_FVG_BULL || type == XCA_FVG_BEAR) { // typeStr = "XCA_FVG"; } else if (type == XCA_RSI_COOS || type == XCA_RSI_CUOB) { // typeStr = "XCA_RSI"; } else if (type == XCA_CCI_COOS || type == XCA_CCI_CUOB) { // typeStr = "XCA_CCI"; } else if (type == XCA_TKI_BULL || type == XCA_TKI_BEAR) { // typeStr = "XCA_TKI"; } else if (type == XCA_TREND_BULL || type == XCA_TREND_BEAR) { // typeStr = "XCA_TREND"; } else if (type == XCA_TKITRND_BULL || type == XCA_TKITRND_BEAR) { // typeStr = "XCA_TKITRND"; } box.type = typeStr; // box.upper = isBullish ? reserve : value; box.lower = isBullish ? value : reserve; // result = box.IsValid(); if (!result) { box.Clean(); } // return result; } // }; // // Implementations ... class XCXCAEAPOIDetector : public XCBase { // // Public ... public: // // Props ... // // Pivot Verifications and Max Allowed Holding Items ... int pivotVerifications; // Pivots Verifications ... int maxAllowedPivots; // Max Allowed Holding Pibots ... // // VALE Pivot Support Swing Low ... // XCAPivot valeSupSWLPivot; bool detectValeSupSWLPivots; XBoxZone valeSupSWLPivots[]; bool newValeSupSWLPivotDetected; // // PEAK Pivot Resistance Swing High ... // XCAPivot peakResSWHPivot; bool detectPeakResSWHPivots; XBoxZone peakResSWHPivots[]; bool newPeakResSWHPivotDetected; // // FVG Bullish Pivots ... // bool detectFVGBullishPivots; XBoxZone fvgBullishPivots[]; bool newFVGBullishPivotDetected; // // FVG Bearish Pivots ... // bool detectFVGBearishPivots; XBoxZone fvgBearishPivots[]; bool newFVGBearishPivotDetected; // // RSI Peak Pivot ... // XCAPivot rsiPeakPivot; bool detectRSIPeakPivots; XBoxZone rsiPeakPivots[]; bool newRSIPeakPivotDetected; // // RSI Vale Pivot ... // XCAPivot rsiValePivot; bool detectRSIValePivots; XBoxZone rsiValePivots[]; bool newRSIValePivotDetected; // // CCI Peak Pivot ... // XCAPivot cciPeakPivot; bool detectCCIPeakPivots; XBoxZone cciPeakPivots[]; bool newCCIPeakPivotDetected; // // CCI Vale Pivot ... // XCAPivot cciValePivot; bool detectCCIValePivots; XBoxZone cciValePivots[]; bool newCCIValePivotDetected; // // Detector Pivots State Properties ... // // Constructors ... XCXCAEAPOIDetector( XCXCAEAHelper *_helper // ) { // helper = _helper; drawer = new XCPOIDrawer(); barAnalyser = new XCBarAnalyser(); // Default(); } // // De Constructors ... ~XCXCAEAPOIDetector() { // rsiPeakPivot.Clean(); rsiValePivot.Clean(); cciPeakPivot.Clean(); cciValePivot.Clean(); valeSupSWLPivot.Clean(); peakResSWHPivot.Clean(); // Clean(rsiPeakPivots); Clean(rsiValePivots); Clean(cciPeakPivots); Clean(cciValePivots); Clean(fvgBullishPivots); Clean(fvgBearishPivots); Clean(valeSupSWLPivots); Clean(peakResSWHPivots); // ZeroMemory(helper); ZeroMemory(drawer); ZeroMemory(barAnalyser); } // // Properties ... // // Tools ... // virtual void Default() { // maxAllowedPivots = 50; pivotVerifications = 5; // detectRSIPeakPivots = true; detectRSIValePivots = true; detectCCIPeakPivots = true; detectCCIValePivots = true; detectFVGBullishPivots = true; detectFVGBearishPivots = true; detectValeSupSWLPivots = true; detectPeakResSWHPivots = true; // } // void Update( int barIndex = 0, int loopback = 400 // ) { // if (barIndex < 0) { barIndex = 0; } // loopback = NormalizeInt(loopback, 400); // int count = 0; bool has = false; // newRSIPeakPivotDetected = false; newRSIValePivotDetected = false; newCCIPeakPivotDetected = false; newCCIValePivotDetected = false; newFVGBullishPivotDetected = false; newFVGBearishPivotDetected = false; newValeSupSWLPivotDetected = false; newPeakResSWHPivotDetected = false; // int zIDX = 0; int cIDX = zIDX + 1; int pIDX = cIDX + 1; int p2IDX = pIDX + 1; int p3IDX = p2IDX + 1; // int index = barIndex; int start = index; int end = index + loopback; while (start < end) { // // Retrieve Conditions ... XCAEAConditions conditions; has = helper.GetConditions( conditions, start, 5 // ); // // Retrieve Bars ... XOHCL zBar; XOHCL cBar; XOHCL pBar; XOHCL p2Bar; has = zBar.Init( conditions.symbol, conditions.period, start // ); has = has && zBar.GetPreviousBar(cBar); has = has && cBar.GetPreviousBar(pBar); has = has && pBar.GetPreviousBar(p2Bar); if (!has) { // zBar.Clean(); cBar.Clean(); pBar.Clean(); p2Bar.Clean(); conditions.Clean(); // continue; } // XBoxZone fvgBox; bool isFVG = barAnalyser.IsFVG( cBar, fvgBox // ); // bool isBullishFVG = isFVG && fvgBox.IsBullish(); // bool isBearishFVG = isFVG && fvgBox.IsBearish(); // // Provide Some Conditions ... // double points = GetPoints(zBar.symbol); // // Reading Values from Conditions and // Create Customized Conditions if required ... // // Checking Pivots ... // // VALE Pivot Support Swing Low ... if (detectValeSupSWLPivots) { // if (conditions.isValeFinishedFromPivot) { // valeSupSWLPivot.Clean(); // valeSupSWLPivot.type = XCA_VALESWLSUP; valeSupSWLPivot.symbol = conditions.symbol; valeSupSWLPivot.period = conditions.period; // valeSupSWLPivot.to = pBar.time; valeSupSWLPivot.from = pBar.time; valeSupSWLPivot.value = conditions.valeBuffer[pIDX]; valeSupSWLPivot.reserve = conditions.valeGoldenBuffer[pIDX]; } // if (conditions.isValeIsPivot) { // valeSupSWLPivot.from = pBar.time; // valeSupSWLPivot.reserve = valeSupSWLPivot.reserve == 0 ? conditions.valeGoldenBuffer[cIDX] : MathMin(valeSupSWLPivot.reserve, conditions.valeGoldenBuffer[cIDX]); } // if (conditions.isValeSwitchedToPivot) { // has = valeSupSWLPivot.IsValid() && valeSupSWLPivot.GetAge() >= pivotVerifications; if (has) { // XBoxZone iBox; newValeSupSWLPivotDetected = valeSupSWLPivot.AsBox(iBox); if (newValeSupSWLPivotDetected) { // AddBox( iBox, valeSupSWLPivots, maxAllowedPivots // ); } // iBox.Clean(); } // valeSupSWLPivot.Clean(); } } // // PEAK Pivot Resistance Swing High ... if (detectPeakResSWHPivots) { } // // FVG Bullish ... if (detectFVGBullishPivots) { } // // FVG Bearish ... if (detectFVGBearishPivots) { } // // RSI Peak Pivot ... if (detectRSIPeakPivots) { } // // RSI Vale Pivot ... if (detectRSIValePivots) { } // // CCI Peak Pivot ... if (detectCCIPeakPivots) { } // // CCI Vale Pivot ... if (detectCCIValePivots) { } // start++; // zBar.Clean(); cBar.Clean(); pBar.Clean(); p2Bar.Clean(); fvgBox.Clean(); conditions.Clean(); } // } // void Validate( XBoxZone &unAvailableBoxes[], int barIndex = 0 // ) { // // Do All Pivots Validation ... // if (barIndex < 0) { barIndex = 0; } // XBoxZone tmp[]; bool has = false; // int zIDX = 0; int cIDX = zIDX + 1; int pIDX = cIDX + 1; int p2IDX = pIDX + 1; // // Implement Validation Senarios ... // // VALE Pivot Support Swing Low ... // has = HasValeSupSWLPivots(); if (has) { // // Copy Items and Cleanup Collection ... Copy( valeSupSWLPivots, tmp // ); Clean(valeSupSWLPivots); // // Do Validation ... while (HasChild(tmp)) { // XBoxZone iBox = tmp[0]; ArrayRemove( tmp, 0, 1 // ); // has = ValidateBox( iBox, unAvailableBoxes, barIndex // ); if (has) { // AddRef( iBox, valeSupSWLPivots // ); } // iBox.Clean(); } // Clean(tmp); } // // PEAK Pivot Resistance Swing High ... // has = HasPeakResSWHPivots(); if (has) { // // Copy Items and Cleanup Collection ... Copy( peakResSWHPivots, tmp // ); Clean(peakResSWHPivots); // // Do Validation ... while (HasChild(tmp)) { // XBoxZone iBox = tmp[0]; ArrayRemove( tmp, 0, 1 // ); // has = ValidateBox( iBox, unAvailableBoxes, barIndex // ); if (has) { // AddRef( iBox, peakResSWHPivots // ); } // iBox.Clean(); } // Clean(tmp); } // // FVG Bullish ... // has = HasFVGBullishPivots(); if (has) { // // Copy Items and Cleanup Collection ... Copy( fvgBullishPivots, tmp // ); Clean(fvgBullishPivots); // // Do Validation ... while (HasChild(tmp)) { // XBoxZone iBox = tmp[0]; ArrayRemove( tmp, 0, 1 // ); // has = ValidateBox( iBox, unAvailableBoxes, barIndex // ); if (has) { // AddRef( iBox, fvgBullishPivots // ); } // iBox.Clean(); } // Clean(tmp); } // // FVG Bearish ... // has = HasFVGBearishPivots(); if (has) { // // Copy Items and Cleanup Collection ... Copy( fvgBearishPivots, tmp // ); Clean(fvgBearishPivots); // // Do Validation ... while (HasChild(tmp)) { // XBoxZone iBox = tmp[0]; ArrayRemove( tmp, 0, 1 // ); // has = ValidateBox( iBox, unAvailableBoxes, barIndex // ); if (has) { // AddRef( iBox, fvgBearishPivots // ); } // iBox.Clean(); } // Clean(tmp); } // // RSI Peak Pivot ... // has = HasRSIPeakPivots(); if (has) { // // Copy Items and Cleanup Collection ... Copy( rsiPeakPivots, tmp // ); Clean(rsiPeakPivots); // // Do Validation ... while (HasChild(tmp)) { // XBoxZone iBox = tmp[0]; ArrayRemove( tmp, 0, 1 // ); // has = ValidateBox( iBox, unAvailableBoxes, barIndex // ); if (has) { // AddRef( iBox, rsiPeakPivots // ); } // iBox.Clean(); } // Clean(tmp); } // // RSI Vale Pivot ... // has = HasRSIValePivots(); if (has) { // // Copy Items and Cleanup Collection ... Copy( rsiValePivots, tmp // ); Clean(rsiValePivots); // // Do Validation ... while (HasChild(tmp)) { // XBoxZone iBox = tmp[0]; ArrayRemove( tmp, 0, 1 // ); // has = ValidateBox( iBox, unAvailableBoxes, barIndex // ); if (has) { // AddRef( iBox, rsiValePivots // ); } // iBox.Clean(); } // Clean(tmp); } // // CCI Peak Pivot ... // has = HasCCIPeakPivots(); if (has) { // // Copy Items and Cleanup Collection ... Copy( cciPeakPivots, tmp // ); Clean(cciPeakPivots); // // Do Validation ... while (HasChild(tmp)) { // XBoxZone iBox = tmp[0]; ArrayRemove( tmp, 0, 1 // ); // has = ValidateBox( iBox, unAvailableBoxes, barIndex // ); if (has) { // AddRef( iBox, cciPeakPivots // ); } // iBox.Clean(); } // Clean(tmp); } // // CCI Vale Pivot ... // has = HasCCIValePivots(); if (has) { // // Copy Items and Cleanup Collection ... Copy( cciValePivots, tmp // ); Clean(cciValePivots); // // Do Validation ... while (HasChild(tmp)) { // XBoxZone iBox = tmp[0]; ArrayRemove( tmp, 0, 1 // ); // has = ValidateBox( iBox, unAvailableBoxes, barIndex // ); if (has) { // AddRef( iBox, cciValePivots // ); } // iBox.Clean(); } // Clean(tmp); } // Clean(tmp); // } // // Counters ... // // VALE Pivot Support Swing Low ... // bool HasValeSupSWLPivots() { return HasChild(valeSupSWLPivots); } // int CountValeSupSWLPivots() { return ArraySize(valeSupSWLPivots); } // // PEAK Pivot Resistance Swing High ... // bool HasPeakResSWHPivots() { return HasChild(peakResSWHPivots); } // int CountPeakResSWHPivots() { return ArraySize(peakResSWHPivots); } // // FVG Bullish ... // bool HasFVGBullishPivots() { return HasChild(fvgBullishPivots); } // int CountFVGBullishPivots() { return ArraySize(fvgBullishPivots); } // // FVG Bearish ... // bool HasFVGBearishPivots() { return HasChild(fvgBearishPivots); } // int CountFVGBearishPivots() { return ArraySize(fvgBearishPivots); } // // RSI Peak Pivot ... // bool HasRSIPeakPivots() { return HasChild(rsiPeakPivots); } // int CountRSIPeakPivots() { return ArraySize(rsiPeakPivots); } // // RSI Vale Pivot ... // bool HasRSIValePivots() { return HasChild(rsiValePivots); } // int CountRSIValePivots() { return ArraySize(rsiValePivots); } // // CCI Peak Pivot ... // bool HasCCIPeakPivots() { return HasChild(cciPeakPivots); } // int CountCCIPeakPivots() { return ArraySize(cciPeakPivots); } // // CCI Vale Pivot ... // bool HasCCIValePivots() { return HasChild(cciValePivots); } // int CountCCIValePivots() { return ArraySize(cciValePivots); } // // Protected ... protected: // // Props ... // // Prrivate ... private: // // Props ... // XCPOIDrawer *drawer; XCXCAEAHelper *helper; XCBarAnalyser *barAnalyser; // bool AddBox( XBoxZone &box, XBoxZone &boxes[], int maxAllowedPivots // ) { // bool result = false; // result = box.IsValid(); if (!result) { return result; } // int idx = -1; bool isExists = FindBoxIndex( idx, box, boxes // ); result = !isExists; if (!result) { return result; } // int before = ArraySize(boxes); if (IsValidSize(before)) { ArrayReverse(boxes); } // AddRef( box, boxes // ); int after = ArraySize(boxes); // result = after > before; if (result) { // ArrayReverse(boxes); // CleanupArray( boxes, maxAllowedPivots // ); } // return result; } // bool ValidateBox( XBoxZone &box, XBoxZone &unAvailableBoxes[], int barIndex = 0 // ) { // bool result = false; // // Normalize Bar Index ... barIndex = NormalizeInt(barIndex, 0); // // Ceck Input Box is Valid ... result = box.IsValid(); if (!result) { return result; } // // Check Input Box is Available ... bool canCheckUnAvailableBoxes = HasChild(unAvailableBoxes); if (canCheckUnAvailableBoxes) { // int idx = -1; bool isUnAvailable = FindBoxIndex( idx, box, unAvailableBoxes // ); result = isUnAvailable; if (!result) { return !result; } } // // Check Input Box is Breaked or not ... // // Check Bar Index must after Box To Index ... int toIDX = box.ToIndex(); int fromIDX = box.FromIndex(); result = toIDX > barIndex && fromIDX > barIndex && fromIDX > toIDX; if (!result) { return result; } // // Detect Box Applied Boundary Price ... // For Checking Break of Box ... bool isBullish = box.IsBullish(); double boundary = isBullish ? box.lower : box.upper; // // for validating Box Break we have to wait At Least 3 Bars Close // out of Box Boundary ... int barsLength = 3; // // Calculate Start Checking Bar Index ... int startCheckBreaktionBarIndex = toIDX - barsLength; bool isBarIndexValid = startCheckBreaktionBarIndex > 0 && barIndex < startCheckBreaktionBarIndex; result = isBarIndexValid; if (!result) { // // Assume Box is Valid if Bar Index not Valid for Checking ... result = true; return result; } // // Try to Check Box Validation if Everything is OK ... XOHCL cBar; XOHCL pBar; XOHCL p2Bar; bool isValid = false; bool isBreaked = false; for (int i = barIndex; i < startCheckBreaktionBarIndex; i++) { // // Initialize Bars ... isValid = cBar.Init( box.symbol, box.period, i + 1 // ); isValid = result && cBar.GetPreviousBar(pBar); isValid = result && pBar.GetPreviousBar(p2Bar); if (!isValid) { // cBar.Clean(); pBar.Clean(); p2Bar.Clean(); // result = false; // break; } // // Preparing Conditions ... // bool isBullishBreaked = isBullish && cBar.close < boundary && pBar.close < boundary && p2Bar.close < boundary; // bool isBearishBreaked = !isBullish && cBar.close > boundary && pBar.close > boundary && p2Bar.close > boundary; // // Calculate Result ... isBreaked = isBullishBreaked || isBearishBreaked; if (isBreaked) { // cBar.Clean(); pBar.Clean(); p2Bar.Clean(); // result = false; // break; } // cBar.Clean(); pBar.Clean(); p2Bar.Clean(); } // result = isValid && !isBreaked; // // Cleanup Resource ... // cBar.Clean(); pBar.Clean(); p2Bar.Clean(); // return result; } // }; //