diff --git a/Classes/x-saherelm.x-market.pattern.class.mq5 b/Classes/x-saherelm.x-market.pattern.class.mq5 index d68a45d3..597f2c76 100644 --- a/Classes/x-saherelm.x-market.pattern.class.mq5 +++ b/Classes/x-saherelm.x-market.pattern.class.mq5 @@ -38,13 +38,17 @@ enum ENUM_X_DETECTOR_ZONE_ACTION X_DETECTOR_ZONE_ACTION_MAJOR_SUPPORT_DETECTED = 1, X_DETECTOR_ZONE_ACTION_MAJOR_SUPPORT_BREAKED = 2, X_DETECTOR_ZONE_ACTION_MINOR_SUPPORT_DETECTED = 3, - X_DETECTOR_ZONE_ACTION_MINOR_SUPPORT_BREAKED = 4, + X_DETECTOR_ZONE_ACTION_MINOR_SUPPORT_REFINED = 4, + X_DETECTOR_ZONE_ACTION_MINOR_SUPPORT_BREAKED = 5, + X_DETECTOR_ZONE_ACTION_MINOR_SUPPORT_RETESTED = 6, // // Resistance ... - X_DETECTOR_ZONE_ACTION_MAJOR_RESISTANCE_DETECTED = 5, - X_DETECTOR_ZONE_ACTION_MAJOR_RESISTANCE_BREAKED = 6, - X_DETECTOR_ZONE_ACTION_MINOR_RESISTANCE_DETECTED = 7, - X_DETECTOR_ZONE_ACTION_MINOR_RESISTANCE_BREAKED = 8, + X_DETECTOR_ZONE_ACTION_MAJOR_RESISTANCE_DETECTED = 7, + X_DETECTOR_ZONE_ACTION_MAJOR_RESISTANCE_BREAKED = 8, + X_DETECTOR_ZONE_ACTION_MINOR_RESISTANCE_DETECTED = 9, + X_DETECTOR_ZONE_ACTION_MINOR_RESISTANCE_REFINED = 10, + X_DETECTOR_ZONE_ACTION_MINOR_RESISTANCE_BREAKED = 11, + X_DETECTOR_ZONE_ACTION_MINOR_RESISTANCE_RETESTED = 12, }; bool IsXValid(ENUM_X_DETECTOR_ZONE_ACTION value) @@ -83,10 +87,18 @@ string ToXString(ENUM_X_DETECTOR_ZONE_ACTION value) result = "MINOR_SUPPORT_DETECTED"; break; // + case X_DETECTOR_ZONE_ACTION_MINOR_SUPPORT_REFINED: + result = "MINOR_SUPPORT_REFINED"; + break; + // case X_DETECTOR_ZONE_ACTION_MINOR_SUPPORT_BREAKED: result = "MINOR_SUPPORT_BREAKED"; break; // + case X_DETECTOR_ZONE_ACTION_MINOR_SUPPORT_RETESTED: + result = "MINOR_SUPPORT_RETESTED"; + break; + // case X_DETECTOR_ZONE_ACTION_MAJOR_RESISTANCE_DETECTED: result = "MAJOR_RESISTANCE_DETECTED"; break; @@ -99,9 +111,89 @@ string ToXString(ENUM_X_DETECTOR_ZONE_ACTION value) result = "MINOR_RESISTANCE_DETECTED"; break; // + case X_DETECTOR_ZONE_ACTION_MINOR_RESISTANCE_REFINED: + result = "MINOR_RESISTANCE_REFINED"; + break; + // case X_DETECTOR_ZONE_ACTION_MINOR_RESISTANCE_BREAKED: result = "MINOR_RESISTANCE_BREAKED"; break; + // + case X_DETECTOR_ZONE_ACTION_MINOR_RESISTANCE_RETESTED: + result = "MINOR_RESISTANCE_RETESTED"; + break; + } + + // + return result; +} + +int XExtractValids( + ENUM_X_DETECTOR_ZONE_ACTION &source[], + ENUM_X_DETECTOR_ZONE_ACTION &dest[] // +) +{ + // + int result = 0; + + // + // Prepare ... + XClean(dest); + + // + // Validate ... + bool has = HasChild(source); + if (!has) + { + return result; + } + + // + // Calculations ... + int count = ArraySize(source); + for (int i = 0; i < count; i++) + { + // + has = IsXValid(source[i]); + if (has) + { + // + Add( + source[i], + dest // + ); + } + } + + // + // Check Size ... + result = ArraySize(dest); + + // + return result; +} + +bool HasXValid(ENUM_X_DETECTOR_ZONE_ACTION &source[]) +{ + // + bool result = false; + + // + result = HasChild(source); + if (!result) + { + return result; + } + + // + for (int i = 0; i < ArraySize(source); i++) + { + // + result = IsXValid(source[i]); + if (result) + { + break; + } } // @@ -144,6 +236,28 @@ class XCMarketPatternDetector : public XCBase // // 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 ... @@ -2746,9 +2860,22 @@ class XCMarketPatternDetector : public XCBase 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 // ) { @@ -2762,7 +2889,9 @@ class XCMarketPatternDetector : public XCBase // // Normalize ... loopback = NormalizeInt(loopback, 100); - + requiredZones = NormalizeInt(requiredZones, 5); + validationLength = NormalizeInt(validationLength, 2); + // // Validate ... bool has = bar.IsValid(); @@ -2775,23 +2904,161 @@ class XCMarketPatternDetector : public XCBase int barIndex = bar.Index(); // - // Collect Zones ... + // Collect or Manage Zones ... + XOHCL zoneBar; + XBoxZone iZone; bool hasZone = HasChild(zones); - if (!hasZone) { + 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++) { + for (int i = start; i < end; i++) + { // - // Extract Validated Zones ... + // 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) @@ -2799,30 +3066,69 @@ class XCMarketPatternDetector : public XCBase // minorSupport.Clean(); hasMinorSupport = false; - } - // - // For Looking up Minor Support, we - // have to Ensure Major Support Exists ... - if (hasMajorSupport) - { // - // Look for Minor Support ... - if (!hasMinorSupport) - { - } - // - // Refine exists Minor Support ... - else + // 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) @@ -2830,26 +3136,501 @@ class XCMarketPatternDetector : public XCBase // 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 // + ); + } + } } // - // For Looking up Minor Resistance, we - // have to Ensure Major Resistance Exists ... - if (hasMajorResistance) + // Check Majors Exixsts ... + has = hasMajorSupport && + hasMajorResistance; + if (has) { // - // Look for Minor Resistance ... - if (!hasMinorResistance) - { - } + double quarter = CalculateQuarter(); + // - // Refine exists Minor Resistance ... - else + // 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 // + ); + Print("Quarter: ", quarter); + } + + // + // 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 // + ); + Print("Quarter: ", quarter); + } + + // + // 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 // + ); + } + + // + // Preparing Actions ... if (!HasChild(actions)) { // @@ -2860,6 +3641,11 @@ class XCMarketPatternDetector : public XCBase } result = ArraySize(actions); + // + // Cleanup ... + iZone.Clean(); + zoneBar.Clean(); + // return result; } @@ -2876,14 +3662,14 @@ class XCMarketPatternDetector : public XCBase * Check Zones and Manage them ... * * @param forBar: XOHCL, reference to Specified Bar ... - * @param zones: XBoxZone, reference to Specified Zone Collection ... + * @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[], + XBoxZone &_zones[], ENUM_X_SORT_BY sortBy = X_SORT_BY_DATE, ENUM_X_DIRECTION sortDir = X_DIRECTION_BEARISH, int maxAllowed = 50 // @@ -2896,7 +3682,7 @@ class XCMarketPatternDetector : public XCBase // // Validate ... bool has = forBar.IsValid() && - HasChild(zones); + HasChild(_zones); if (!has) { return; @@ -2904,32 +3690,32 @@ class XCMarketPatternDetector : public XCBase // // Looping Through Zones ... - int count = ArraySize(zones); + int count = ArraySize(_zones); for (int i = 0; i < count; i++) { // // Check Break ... - has = IsXValid(zones[i].breakAt); + has = IsXValid(_zones[i].breakAt); if (has) { continue; } // - zones[i].to = forBar.time; + _zones[i].to = forBar.time; // // Check for Test ... has = IsTested( forBar, - zones[i] // + _zones[i] // ); if (has) { // Add( forBar.time, - zones[i].tests // + _zones[i].tests // ); } @@ -2937,14 +3723,14 @@ class XCMarketPatternDetector : public XCBase // Check for Inside ... has = IsInside( forBar, - zones[i] // + _zones[i] // ); if (has) { // Add( forBar.time, - zones[i].insides // + _zones[i].insides // ); } @@ -2952,14 +3738,14 @@ class XCMarketPatternDetector : public XCBase // Check for Break ... has = IsBreaked( forBar, - zones[i] // + _zones[i] // ); if (has) { // Add( forBar.time, - zones[i].breaks // + _zones[i].breaks // ); } @@ -2967,14 +3753,14 @@ class XCMarketPatternDetector : public XCBase // Check for Act ... has = IsActed( forBar, - zones[i] // + _zones[i] // ); if (has) { // Add( forBar.time, - zones[i].acteds // + _zones[i].acteds // ); } @@ -2982,14 +3768,14 @@ class XCMarketPatternDetector : public XCBase // Check for FakeBreakes ... has = IsFakeBreaked( forBar, - zones[i] // + _zones[i] // ); if (has) { // Add( forBar.time, - zones[i].fakeBreaks // + _zones[i].fakeBreaks // ); } @@ -2997,18 +3783,18 @@ class XCMarketPatternDetector : public XCBase // Check for Valid Breakes ... has = IsValidBreaked( forBar, - zones[i] // + _zones[i] // ); if (has) { - zones[i].breakAt = forBar.time; + _zones[i].breakAt = forBar.time; } } // // Apply Sort and Cleanup ... Sort( - zones, + _zones, sortBy, sortDir, maxAllowed // diff --git a/Libraries/x-saherelm.x-poi.extensions.lib.mq5 b/Libraries/x-saherelm.x-poi.extensions.lib.mq5 index e742ef33..a8947f70 100644 --- a/Libraries/x-saherelm.x-poi.extensions.lib.mq5 +++ b/Libraries/x-saherelm.x-poi.extensions.lib.mq5 @@ -74,6 +74,56 @@ int GetOldest( return result; } +/** + * Get Oldest Index of Specified Collection ... + * + * @param source: Specified Collection ... + * @param forDir: ENUM_X_DIRECTION, Specified Direction ... + * + * @return ( int ) + */ +int GetOldestByDir( + XBoxZone &source[], + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE // +) +{ + // + int result = -1; + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XBoxZone selected; + for (int i = 0; i < count; i++) + { + // + bool canSet = + (!HasDirection(forDir) + ? true + : forDir == source[i].dir) && + (!selected.IsValid() + ? true + : selected.from > source[i].from); + if (canSet) + { + // + result = i; + selected = source[i]; + } + } + + // + selected.Clean(); + + // + return result; +} + /** * Get Oldest Index of Specified Collection ... * @@ -253,6 +303,56 @@ int GetYoungest( return result; } +/** + * Get Youngest Index of Specified Collection ... + * + * @param source: Specified Collection ... + * @param forDir: ENUM_X_DIRECTION, Specified Direction ... + * + * @return ( int ) + */ +int GetYoungestByDir( + XBoxZone &source[], + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE // +) +{ + // + int result = -1; + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XBoxZone selected; + for (int i = 0; i < count; i++) + { + // + bool canSet = + (!HasDirection(forDir) + ? true + : forDir == source[i].dir) && + (!selected.IsValid() + ? true + : selected.from < source[i].from); + if (canSet) + { + // + result = i; + selected = source[i]; + } + } + + // + selected.Clean(); + + // + return result; +} + /** * Get Youngest Index of Specified Collection ... * @@ -432,6 +532,56 @@ int GetHighest( return result; } +/** + * Get Highest Index of Specified Collection ... + * + * @param source: Specified Collection ... + * @param forDir: ENUM_X_DIRECTION, Specified Direction ... + * + * @return ( int ) + */ +int GetHighestByDir( + XBoxZone &source[], + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE // +) +{ + // + int result = -1; + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XBoxZone selected; + for (int i = 0; i < count; i++) + { + // + bool canSet = + (!HasDirection(forDir) + ? true + : forDir == source[i].dir) && + (!selected.IsValid() + ? true + : selected.upper < source[i].upper); + if (canSet) + { + // + result = i; + selected = source[i]; + } + } + + // + selected.Clean(); + + // + return result; +} + /** * Get Highest Index of Specified Collection ... * @@ -627,6 +777,62 @@ int GetLowest( return result; } +/** + * Get Lowest Index of Specified Collection ... + * + * @param source: Specified Collection ... + * @param forDir: ENUM_X_DIRECTION, Specified Direction ... + * + * @return ( int ) + */ +int GetLowestByDir( + XBoxZone &source[], + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE // +) +{ + // + int result = -1; + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XBoxZone selected; + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox = source[i]; + + // + bool canSet = + (!HasDirection(forDir) + ? true + : forDir == source[i].dir) && + (!selected.IsValid() + ? true + : selected.lower > iBox.lower); + if (canSet) + { + // + result = i; + selected = iBox; + } + + // + iBox.Clean(); + } + + // + selected.Clean(); + + // + return result; +} + /** * Get Lowest Index of Specified Collection ... * @@ -4566,6 +4772,59 @@ bool ToResistanceBox( return result; } +/** + * Remove Breaked Zones from a Collection ... + * + * @param source: XBoxZone, reference to Specified Collection ... + * + * @return ( int ) + */ +int RemoveBreakedZones(XBoxZone &source[]) +{ + // + int result = 0; + + // + // Validate ... + bool has = HasChild(source); + if (!has) + { + return result; + } + + // + XBoxZone iZone; + XBoxZone tmps[]; + Copy( + source, + tmps // + ); + XClean(source); + while (HasChild(tmps)) + { + // + iZone.Clean(); + iZone = tmps[0]; + ArrayRemove(tmps, 0, 1); + has = iZone.IsValid() && + !IsXValid(iZone.breakAt); + if (has) + { + // + AddIfNotExists( + iZone, + source // + ); + } + } + + // + result = ArraySize(source); + + // + return result; +} + /** * Check Specified Zone is Breaked by Specified Bar or not ... * @@ -4957,12 +5216,12 @@ bool HasInside( /** * Extract Affected Zones for Specified Bar ... - * + * * @param bar: XOHCL, reference to Specified Bar ... * @param source: XBoxZone, reference collection to Provide Data Source ... * @param dest: XBoxZone, reference collection to holds result ... * @param forDir: ENUM_X_DIRECTION, Specified Zones Direction to Lookup ... - * + * * @return ( int ) */ int ExtractAffectedZones( diff --git a/Libraries/x-saherelm.x-poi.lib.mq5 b/Libraries/x-saherelm.x-poi.lib.mq5 index 3261e114..507d387a 100644 --- a/Libraries/x-saherelm.x-poi.lib.mq5 +++ b/Libraries/x-saherelm.x-poi.lib.mq5 @@ -804,6 +804,7 @@ struct XBoxZone datetime acteds[]; datetime breaks[]; datetime insides[]; + datetime refines[]; datetime fakeBreaks[]; // @@ -849,6 +850,7 @@ struct XBoxZone XClean(acteds); XClean(breaks); XClean(insides); + XClean(refines); XClean(fakeBreaks); } diff --git a/XFIMAEA/Classes/x-saherelm.xfima.signaller.class.mq5 b/XFIMAEA/Classes/x-saherelm.xfima.signaller.class.mq5 index 3ada567c..fd280c67 100644 --- a/XFIMAEA/Classes/x-saherelm.xfima.signaller.class.mq5 +++ b/XFIMAEA/Classes/x-saherelm.xfima.signaller.class.mq5 @@ -348,6 +348,187 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller return; } + // + // Manage Zones of Pattern Detector ... + ENUM_X_DETECTOR_ZONE_ACTION zoneActions[]; + int zoneActionsCount = poiDetector.UpdateZones( + iBar, + zoneActions, + 3, // Validation Length ... + 20, // Required Zones ... + 1500 // Loopback ... + ); + has = IsValidSize(zoneActionsCount); + if (has) + { + // + } + + // + // Sample Draws ... + + // + // Support ... + if (poiDetector.majorSupport.IsValid()) + { + // + XPOIDrawConfig iConfig = structureDrawConfig.drawConfig; + iConfig.zonesWidth = 3; + + // + poiDrawer.DrawZone( + poiDetector.majorSupport, + iConfig // + ); + } + if (poiDetector.minorSupport.IsValid()) + { + // + XPOIDrawConfig iConfig = structureDrawConfig.drawConfig; + iConfig.zonesStyle = STYLE_DASH; + + // + poiDrawer.DrawZone( + poiDetector.minorSupport, + iConfig // + ); + } + + // + // Resistance ... + if (poiDetector.majorResistance.IsValid()) + { + // + XPOIDrawConfig iConfig = structureDrawConfig.drawConfig; + iConfig.zonesWidth = 3; + + // + poiDrawer.DrawZone( + poiDetector.majorResistance, + iConfig // + ); + } + if (poiDetector.minorResistance.IsValid()) + { + // + XPOIDrawConfig iConfig = structureDrawConfig.drawConfig; + iConfig.zonesStyle = STYLE_DASH; + + // + poiDrawer.DrawZone( + poiDetector.minorResistance, + iConfig // + ); + } + + // + // Quarter Line ... + if (poiDetector.majorSupport.IsValid() && + poiDetector.majorResistance.IsValid()) + { + // + double quarter = poiDetector.CalculateQuarter(); + + // + datetime quarterFrom = MathMin(poiDetector.majorResistance.from, + poiDetector.majorSupport.from); + datetime quarterTo = MathMax(poiDetector.majorResistance.to, + poiDetector.majorSupport.to); + string quarterName = "XQuarter_" + ToXString(quarter) + "_" + ToXString(TimeToSeconds(quarterFrom)); + + // + CChartObjectTrend *iObj; + has = poiDrawer.DrawTrendLine( + quarter, + quarterFrom, + quarter, + quarterTo, + iObj, + quarterName, + false, // Ray Right ... + false // Ray Left ... + ); + if (has) { + // + iObj.Width(2); + iObj.Color(clrYellow); + + // + poiDrawer.drawnObjects.Add(iObj); + } + } + + // + // Check Actions for Debugging ... + has = HasXValid(zoneActions) && + (Contains( + X_DETECTOR_ZONE_ACTION_MINOR_SUPPORT_RETESTED, + zoneActions) || + Contains( + X_DETECTOR_ZONE_ACTION_MINOR_RESISTANCE_RETESTED, + zoneActions)); + if (has) + { + // + // Draw Bar Arrow Based On Action ... + XPivot msPivot; + XPivot mrPivot; + + // + // Support ReTest ... + has = Contains( + X_DETECTOR_ZONE_ACTION_MINOR_SUPPORT_RETESTED, + zoneActions // + ); + has = + has && + ToPivot( + iBar, + msPivot, + X_DIRECTION_BULLISH, + X_BAR_PATTERN_SUPPORT // + ); + if (has) + { + // + poiDrawer.DrawPivot( + msPivot, + structureDrawConfig.drawConfig // + ); + } + + // + // Resistance ReTest ... + has = Contains( + X_DETECTOR_ZONE_ACTION_MINOR_RESISTANCE_RETESTED, + zoneActions // + ); + has = + has && + ToPivot( + iBar, + mrPivot, + X_DIRECTION_BEARISH, + X_BAR_PATTERN_RESISTANCE // + ); + if (has) + { + // + poiDrawer.DrawPivot( + mrPivot, + structureDrawConfig.drawConfig // + ); + } + + // + // Cleanup Pivots ... + msPivot.Clean(); + mrPivot.Clean(); + + // + Print("Hot Zone Actions ..."); + } + // // Retrieve Conditions ... has = fimaHelper.GetConditions(