diff --git a/Classes/x-saherelm.x-market.pattern.class.mq5 b/Classes/x-saherelm.x-market.pattern.class.mq5 index 14504453..50b57908 100644 --- a/Classes/x-saherelm.x-market.pattern.class.mq5 +++ b/Classes/x-saherelm.x-market.pattern.class.mq5 @@ -23,6 +23,7 @@ // Imports ... #include "../Classes/x-saherelm.base.class.mq5" #include "../Classes/x-saherelm.x-bar.analyser.class.mq5" +#include "../Libraries/x-saherelm.x-poi.extensions.lib.mq5" #include "../Libraries/x-saherelm.x-poi.lib.mq5" // @@ -57,6 +58,180 @@ class XCMarketPatternDetector : public XCBase // // Actions / Helpers ... + // + // 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 Momentum Bar or not ... * diff --git a/Experts/x-saherelm.xfima.backtester.ea.mq5 b/Experts/x-saherelm.xfima.backtester.ea.mq5 index 456a8c8c..c8487405 100644 --- a/Experts/x-saherelm.xfima.backtester.ea.mq5 +++ b/Experts/x-saherelm.xfima.backtester.ea.mq5 @@ -462,7 +462,7 @@ void OnTick() bool isInited = cBar.Init( _Symbol, _Period, - 1 // + 0 // ); // // Here We Apply Custom Detecting ... @@ -506,22 +506,164 @@ void OnTick() if (marketStructure.support.IsValid() || marketStructure.resistance.IsValid()) { // - // Check Conditions ... - datetime beforeTime = cBar.BeforeOn(); - bool hasSupport = - (marketStructure.support.IsValid() && - marketStructure.support.from == beforeTime); - bool hasResistance = - (marketStructure.resistance.IsValid() && - marketStructure.resistance.from == beforeTime); - bool has = - hasSupport || - hasResistance; + XOHCL pBar; + XOHCL p2Bar; + bool has = cBar.GetPreviousBar(pBar); + has = has && + pBar.GetPreviousBar(p2Bar); + if (!has) + { + // + pBar.Clean(); + p2Bar.Clean(); + return; + } + + // // + // bool isSupportTouched = marketStructure.isSupportTouched; + // bool isResistanceTouched = marketStructure.isResistanceTouched; + // has = + // isSupportTouched || + // isResistanceTouched; + // if (!has) + // { + // // + // pBar.Clean(); + // return; + // } + + // // + // // Here we Have to Detect Previous Support or Resistance ... + // XOHCL prevZoneBar; + // XBoxZone prevZoneBox; + + // // + // // Previous Support ... + // bool hasPrevSupport = isSupportTouched && + // fima2Signaller + // .poiDetector + // .HasSupport( + // pBar, + // prevZoneBar, + // detectorConfig.supportAndResistanceValidationLength, + // detectorConfig.supportAndResistanceMaxAllowedLoopback // + // ); + // if (hasPrevSupport) + // { + // hasPrevSupport = ToSupportBox(prevZoneBar, prevZoneBox, pBar.time); + // } + + // // + // // Previous Resistance ... + // bool hasPrevResistance = isResistanceTouched && + // fima2Signaller + // .poiDetector + // .HasSupport( + // pBar, + // prevZoneBar, + // detectorConfig.supportAndResistanceValidationLength, + // detectorConfig.supportAndResistanceMaxAllowedLoopback // + // ); + // if (hasPrevResistance) + // { + // hasPrevResistance = ToResistanceBox(prevZoneBar, prevZoneBox, pBar.time); + // } + + // // + // has = hasPrevSupport || + // hasPrevResistance; + // if (!has) + // { + // // + // pBar.Clean(); + // prevZoneBox.Clean(); + // prevZoneBar.Clean(); + // return; + // } + + // // + // // Select Youngest ... + // int idx = -1; + + // // + // if (hasPrevSupport) + // { + // // + // idx = GetYoungestBefore( + // marketStructure.support.from, + // fima2Signaller.poiDetector.supports // + // ); + // has = IsValidIndex(idx); + // if (has) + // { + // // + // prevZoneBox.to = pBar.time; + // prevZoneBox = fima2Signaller.poiDetector.supports[idx]; + // } + // } + + // // + // if (hasPrevResistance) + // { + // // + // idx = GetYoungestBefore( + // marketStructure.resistance.from, + // fima2Signaller.poiDetector.resistances // + // ); + // has = IsValidIndex(idx); + // if (has) + // { + // // + // prevZoneBox.to = pBar.time; + // prevZoneBox = fima2Signaller.poiDetector.resistances[idx]; + // } + // } + + // + // Draw Prev Zone ... + // XCBoxObject *iPrevZoneObj; + // prevZoneBox.to = pBar.time; + // has = fima2Signaller.poiDrawer.DrawBox( + // prevZoneBox, + // iPrevZoneObj // + // ); + // if (has) + // { + // // + // XPOIStyle style; + // fima2Signaller.poiDrawer.GetBoxStyle( + // style, + // prevZoneBox.dir // + // ); + // style.clr = clrYellow; + // fima2Signaller.poiDrawer.ApplyBoxStyle( + // iPrevZoneObj, + // style // + // ); + + // // + // style.Clean(); + // eaDraws.Add(iPrevZoneObj); + // } + + // + // Check Prev Zone is Breaked or not ... + // if (has) { Print("Detected ..."); } + + // + // Cleanup Resources ... + pBar.Clean(); + p2Bar.Clean(); + // prevZoneBox.Clean(); + // prevZoneBar.Clean(); } + + // + cBar.Clean(); } // diff --git a/Libraries/x-saherelm.x-poi.extensions.lib.mq5 b/Libraries/x-saherelm.x-poi.extensions.lib.mq5 index 00a4b681..b67160d0 100644 --- a/Libraries/x-saherelm.x-poi.extensions.lib.mq5 +++ b/Libraries/x-saherelm.x-poi.extensions.lib.mq5 @@ -26,7 +26,6 @@ // // Extensions ... - //+------------------------------------------------------------------+ //| Oldest Detection | //+------------------------------------------------------------------+ @@ -976,6 +975,498 @@ int GetLowest( } //+------------------------------------------------------------------+ +//+------------------------------------------------------------------+ +//| Box | +//+------------------------------------------------------------------+ +int GetOldestBefore( + datetime _time, + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + // Validate ... + bool has = + HasChild(source) && + IsSpecifiedValid(_time); + if (!has) + { + return result; + } + + // + int idx = -1; + XBoxZone tmps[]; + int count = ArraySize(source); + for (int i = 0; i < count; i++) + { + // + has = source[i].from < _time; + if (has) + { + // + AddIfNotExists( + source[i], + tmps // + ); + } + } + has = HasChild(tmps); + if (!has) + { + // + result = -1; + return result; + } + + // + idx = GetOldest(tmps); + has = + IsValidIndex(idx) && + FindIndex( + result, + tmps[idx], + source // + ); + + // + // Cleanup Resources ... + SpecifiedClean(tmps); + + // + return result; +} + +int GetOldestAfter( + datetime _time, + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + // Validate ... + bool has = + HasChild(source) && + IsSpecifiedValid(_time); + if (!has) + { + return result; + } + + // + int idx = -1; + XBoxZone tmps[]; + int count = ArraySize(source); + for (int i = 0; i < count; i++) + { + // + has = source[i].from > _time; + if (has) + { + // + AddIfNotExists( + source[i], + tmps // + ); + } + } + has = HasChild(tmps); + if (!has) + { + // + result = -1; + return result; + } + + // + idx = GetOldest(tmps); + has = + IsValidIndex(idx) && + FindIndex( + result, + tmps[idx], + source // + ); + + // + // Cleanup Resources ... + SpecifiedClean(tmps); + + // + return result; +} + +int GetYoungestBefore( + datetime _time, + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + // Validate ... + bool has = + HasChild(source) && + IsSpecifiedValid(_time); + if (!has) + { + return result; + } + + // + int idx = -1; + XBoxZone tmps[]; + int count = ArraySize(source); + for (int i = 0; i < count; i++) + { + // + has = source[i].from < _time; + if (has) + { + // + AddIfNotExists( + source[i], + tmps // + ); + } + } + has = HasChild(tmps); + if (!has) + { + // + result = -1; + return result; + } + + // + idx = GetYoungest(tmps); + has = + IsValidIndex(idx) && + FindIndex( + result, + tmps[idx], + source // + ); + + // + // Cleanup Resources ... + SpecifiedClean(tmps); + + // + return result; +} + +int GetYoungestAfter( + datetime _time, + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + // Validate ... + bool has = + HasChild(source) && + IsSpecifiedValid(_time); + if (!has) + { + return result; + } + + // + int idx = -1; + XBoxZone tmps[]; + int count = ArraySize(source); + for (int i = 0; i < count; i++) + { + // + has = source[i].from > _time; + if (has) + { + // + AddIfNotExists( + source[i], + tmps // + ); + } + } + has = HasChild(tmps); + if (!has) + { + // + result = -1; + return result; + } + + // + idx = GetYoungest(tmps); + has = + IsValidIndex(idx) && + FindIndex( + result, + tmps[idx], + source // + ); + + // + // Cleanup Resources ... + SpecifiedClean(tmps); + + // + return result; +} + +int GetHighestAbove( + double _value, + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + // Validate ... + bool has = + HasChild(source) && + NotEmptyZero(_value); + if (!has) + { + return result; + } + + // + int idx = -1; + XBoxZone tmps[]; + int count = ArraySize(source); + for (int i = 0; i < count; i++) + { + // + has = source[i].upper > _value; + if (has) + { + // + AddIfNotExists( + source[i], + tmps // + ); + } + } + has = HasChild(tmps); + if (!has) + { + // + result = -1; + return result; + } + + // + idx = GetHighest(tmps); + has = + IsValidIndex(idx) && + FindIndex( + result, + tmps[idx], + source // + ); + + // + // Cleanup Resources ... + SpecifiedClean(tmps); + + // + return result; +} + +int GetHighestBelow( + double _value, + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + // Validate ... + bool has = + HasChild(source) && + NotEmptyZero(_value); + if (!has) + { + return result; + } + + // + int idx = -1; + XBoxZone tmps[]; + int count = ArraySize(source); + for (int i = 0; i < count; i++) + { + // + has = source[i].upper < _value; + if (has) + { + // + AddIfNotExists( + source[i], + tmps // + ); + } + } + has = HasChild(tmps); + if (!has) + { + // + result = -1; + return result; + } + + // + idx = GetHighest(tmps); + has = + IsValidIndex(idx) && + FindIndex( + result, + tmps[idx], + source // + ); + + // + // Cleanup Resources ... + SpecifiedClean(tmps); + + // + return result; +} + +int GetLowestAbove( + double _value, + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + // Validate ... + bool has = + HasChild(source) && + NotEmptyZero(_value); + if (!has) + { + return result; + } + + // + int idx = -1; + XBoxZone tmps[]; + int count = ArraySize(source); + for (int i = 0; i < count; i++) + { + // + has = source[i].lower > _value; + if (has) + { + // + AddIfNotExists( + source[i], + tmps // + ); + } + } + has = HasChild(tmps); + if (!has) + { + // + result = -1; + return result; + } + + // + idx = GetLowest(tmps); + has = + IsValidIndex(idx) && + FindIndex( + result, + tmps[idx], + source // + ); + + // + // Cleanup Resources ... + SpecifiedClean(tmps); + + // + return result; +} + +int GetLowestBelow( + double _value, + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + // Validate ... + bool has = + HasChild(source) && + NotEmptyZero(_value); + if (!has) + { + return result; + } + + // + int idx = -1; + XBoxZone tmps[]; + int count = ArraySize(source); + for (int i = 0; i < count; i++) + { + // + has = source[i].lower < _value; + if (has) + { + // + AddIfNotExists( + source[i], + tmps // + ); + } + } + has = HasChild(tmps); + if (!has) + { + // + result = -1; + return result; + } + + // + idx = GetLowest(tmps); + has = + IsValidIndex(idx) && + FindIndex( + result, + tmps[idx], + source // + ); + + // + // Cleanup Resources ... + SpecifiedClean(tmps); + + // + return result; +} +//+------------------------------------------------------------------+ + //+------------------------------------------------------------------+ //| Sort | //+------------------------------------------------------------------+ diff --git a/XFIMAEA/Classes/x-saherelm.xfima.x-poi.detector.class.mq5 b/XFIMAEA/Classes/x-saherelm.xfima.x-poi.detector.class.mq5 index 68c35803..daa987b5 100644 --- a/XFIMAEA/Classes/x-saherelm.xfima.x-poi.detector.class.mq5 +++ b/XFIMAEA/Classes/x-saherelm.xfima.x-poi.detector.class.mq5 @@ -39,6 +39,12 @@ class XCXFIMAPOIDetector : public XCMarketPatternDetector XCBarAnalyser *barAnalyser; // Bar Analyser ... XCXFIMAHelper *fimaHelper; // XFIMA Helper ... + // + XBoxZone obs[]; + XBoxZone fvgs[]; + XBoxZone supports[]; + XBoxZone resistances[]; + // // Constructor ... XCXFIMAPOIDetector( @@ -475,6 +481,12 @@ class XCXFIMAPOIDetector : public XCMarketPatternDetector */ void Destroy() { + // + SpecifiedClean(obs); + SpecifiedClean(fvgs); + SpecifiedClean(supports); + SpecifiedClean(resistances); + // delete barAnalyser; ZeroMemory(barAnalyser); @@ -515,6 +527,7 @@ class XCXFIMAPOIDetector : public XCMarketPatternDetector // bool has = false; + int maxAllowedCollecting = 50; ENUM_X_DIRECTION iDir = X_DIRECTION_NONE; // @@ -539,6 +552,33 @@ class XCXFIMAPOIDetector : public XCMarketPatternDetector { structure.ob.Clean(); } + + // + // Detect Touches ... + if (isOB) + { + // + AddIfNotExists( + structure.ob, + obs, + maxAllowedCollecting // + ); + + // + XOHCL pBar; + bool has = forBar.GetPreviousBar(pBar); + if (has) + { + // + structure.isOBTouched = + isBullishOB + ? pBar.low < structure.ob.upper + : pBar.high > structure.ob.lower; + } + + // + pBar.Clean(); + } } // @@ -552,14 +592,41 @@ class XCXFIMAPOIDetector : public XCMarketPatternDetector structure.fvg, config.fvgLoopback // ); - bool isBullishOB = isFVG && - IsSpecifiedBullish(iDir); - bool isBearishOB = isFVG && - IsSpecifiedBearish(iDir); + bool isBullishFVG = isFVG && + IsSpecifiedBullish(iDir); + bool isBearishFVG = isFVG && + IsSpecifiedBearish(iDir); if (!isFVG) { structure.fvg.Clean(); } + + // + // Detect Touches ... + if (isFVG) + { + // + AddIfNotExists( + structure.fvg, + fvgs, + maxAllowedCollecting // + ); + + // + XOHCL pBar; + bool has = forBar.GetPreviousBar(pBar); + if (has) + { + // + structure.isFVGTouched = + isBullishFVG + ? pBar.low < structure.fvg.upper + : pBar.high > structure.fvg.lower; + } + + // + pBar.Clean(); + } } // @@ -796,10 +863,29 @@ class XCXFIMAPOIDetector : public XCMarketPatternDetector has = ToSupportBox(support, supportBox); if (has) { + // + AddIfNotExists( + supportBox, + supports, + maxAllowedCollecting // + ); + + // structure.support = supportBox; } // + // Check for Support Touches ... + XOHCL pBar; + has = has && + forBar.GetPreviousBar(pBar); + if (has) + { + structure.isSupportTouched = pBar.low < supportBox.upper; + } + + // + pBar.Clean(); supportBox.Clean(); } support.Clean(); @@ -824,10 +910,29 @@ class XCXFIMAPOIDetector : public XCMarketPatternDetector has = ToResistanceBox(resistance, resistanceBox); if (has) { + // + AddIfNotExists( + resistanceBox, + resistances, + maxAllowedCollecting // + ); + + // structure.resistance = resistanceBox; } // + // Check for Resistance Touches ... + XOHCL pBar; + has = has && + forBar.GetPreviousBar(pBar); + if (has) + { + structure.isResistanceTouched = pBar.high > resistanceBox.upper; + } + + // + pBar.Clean(); resistanceBox.Clean(); } resistance.Clean(); diff --git a/XFIMAEA/Libraries/x-saherelm.xfima.lib.mq5 b/XFIMAEA/Libraries/x-saherelm.xfima.lib.mq5 index 796d883a..d03ec4fe 100644 --- a/XFIMAEA/Libraries/x-saherelm.xfima.lib.mq5 +++ b/XFIMAEA/Libraries/x-saherelm.xfima.lib.mq5 @@ -360,6 +360,12 @@ struct XFIMAMarketStructure XBoxZone support; XBoxZone resistance; + // + bool isOBTouched; + bool isFVGTouched; + bool isSupportTouched; + bool isResistanceTouched; + // // Analysis ... XPivotAnalysis pvAnalysis; @@ -408,6 +414,12 @@ struct XFIMAMarketStructure support.Clean(); resistance.Clean(); + // + isOBTouched = false; + isFVGTouched = false; + isSupportTouched = false; + isResistanceTouched = false; + // bar.Clean(); flagSwing.Clean();