From 8f317a3b1d8efbcf2797f6ca5b88ca22b31bf675 Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Sun, 26 Oct 2025 19:13:04 +0330 Subject: [PATCH] Complete Strategy 4 Signals ... --- Classes/x-saherelm.x-market.pattern.class.mq5 | 6 +- .../x-saherelm.xfima.signaller.class.mq5 | 2621 +++++++++++++++++ Libraries/x-saherelm.x-poi.extensions.lib.mq5 | 192 +- .../x-saherelm.xfima.signaller.class.mq5 | 315 +- 4 files changed, 3071 insertions(+), 63 deletions(-) create mode 100644 Documents/BKP/XFIMA Signals/x-saherelm.xfima.signaller.class.mq5 diff --git a/Classes/x-saherelm.x-market.pattern.class.mq5 b/Classes/x-saherelm.x-market.pattern.class.mq5 index 9e008f46..60ace05c 100644 --- a/Classes/x-saherelm.x-market.pattern.class.mq5 +++ b/Classes/x-saherelm.x-market.pattern.class.mq5 @@ -2190,9 +2190,13 @@ class XCMarketPatternDetector : public XCBase // ValidateBoxes( _zones, - bar.Index() // + bar.Index() // Bars Length ... ); + // + UpdateToTime(_zones, bar.time); + RemoveBreakedZones(_zones, X_PRICE_CLOSE); + // result = HasChild(_zones); } diff --git a/Documents/BKP/XFIMA Signals/x-saherelm.xfima.signaller.class.mq5 b/Documents/BKP/XFIMA Signals/x-saherelm.xfima.signaller.class.mq5 new file mode 100644 index 00000000..5d1c13bb --- /dev/null +++ b/Documents/BKP/XFIMA Signals/x-saherelm.xfima.signaller.class.mq5 @@ -0,0 +1,2621 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class +// ------------------------------------------------- +// Name: XCXFIMASignaller ... +// Description: XFIMA Signaller Class ... +// +// +// 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 XFIMA Signaller Class" +#property strict + +// +// Imports ... +#include "../../Classes/x-saherelm.x-signaller.class.mq5" +#include "../../Helpers/x-saherelm.xfima.helper.mq5" +#include "../Classes/x-saherelm.xfima.parser.class.mq5" +#include "../Classes/x-saherelm.xfima.x-poi.detector.class.mq5" +#include "../Classes/x-saherelm.xfima.x-poi.drawer.class.mq5" + +// +// Implementation ... + +// +// Base XFIMA base Signaller ... +class XCXFIMABaseSignaller : public XCBaseSignaller +{ + // + // Public ... + public: + // + // Props ... + + // + CArrayObj drawnObjects; // Drawing Objects Holder ... + XFIMAInputs fimaInputs; // XFIMA Inputs ... + XCXFIMAHelper *fimaHelper; // XFIMA Indicator Helper ... + XCXFIMAPOIDrawer *poiDrawer; // XFIMA POI Drawer ... + XCXFIMAHelperParser *fimaParser; // XFIMA Helper Parser ... + XCXFIMAPOIDetector *poiDetector; // XFIMA POI Detector ... + XFIMAMarketStructureConfig structureConfig; // XFIMA Market Structure Detector Config ... + XFIMAMarketStructureDrawerConfig structureDrawConfig; // XFIMA Market Structure Draw Config ... + + // + // Constructor ... + XCXFIMABaseSignaller( + string _name, // Name ... + string _symbol, // Symbol ... + ENUM_TIMEFRAMES _period, // Period ... + XFIMAInputs &_fimaInputs, // XFIMAInputs ... + bool _processAllTicks = false, // Process All Ticks ... + double _defaultSignalR2R = 1.5, // Default Signal Risk To Reward Ratio ... + double _defaultSignalRiskInPoint = 50, // Default Signal Risk In Point ... + double _defaultSignalVolume = 0.01 // Default Signal Volume ... + ) : XCBaseSignaller(_name, + _symbol, + _period, + _processAllTicks, + _defaultSignalR2R, + _defaultSignalRiskInPoint, + _defaultSignalVolume // + ) + { + // + // Instantiating XFIMA Indicator Helper Class ... + if (_fimaInputs.IsValid()) + { + // + fimaHelper = new XCXFIMAHelper(); + bool isInited = fimaHelper.Init( + _symbol, + _period, + _fimaInputs // + ); + if (isInited) + { + fimaInputs = _fimaInputs; + } + else + { + // + delete fimaHelper; + ZeroMemory(fimaHelper); + } + } + + // + // Instantiate XFIMA Helper Parser ... + fimaParser = new XCXFIMAHelperParser(fimaHelper); + + // + poiDrawer = new XCXFIMAPOIDrawer(); + poiDetector = new XCXFIMAPOIDetector(fimaHelper, fimaParser); + + // + // Configure ... + structureConfig.Default(); + structureDrawConfig.Default(); + } + + // + // Deconstructor ... + ~XCXFIMABaseSignaller() + { + Destroy(); + } + + // + // Overrides ... + + // + // Actions ... + + /** + * Destroy ... + */ + void Destroy() + { + // + BeforeDestroy(); + + // + fimaInputs.Clean(); + + // + delete fimaHelper; + ZeroMemory(fimaHelper); + + // + delete poiDrawer; + ZeroMemory(poiDrawer); + + // + delete poiDetector; + ZeroMemory(poiDetector); + + // + structureConfig.Clean(); + structureDrawConfig.Clean(); + } + + // + // Virtuals ... + + /** + * Before Destroy ... + */ + void virtual BeforeDestroy() + { + } + + /** + * Processing Tick ... + * + * @param barIndex: int, Specified Bar Index ... + */ + virtual void ProcessTick(int barIndex = 0) + { + } + + /** + * Processing New Bar ... + * + * @param barIndex: int, Specified Bar Index ... + */ + virtual void ProcessNewBar(int barIndex = 0) + { + } + + /** + * Check Guards Based on MarketConditions ... + * + * @param guards: XGuard, reference collection to holds result ... + * @param positions: XPosition, reference collection to provides positions ... + * @param barIndex: int + * + * @return ( int ) + */ + int virtual CheckForGuard( + XGuard &guards[], + XPosition &positions[], + int barIndex = 0 // + ) + { + // + int result = 0; + + // + SpecifiedClean(guards); + + // + result = ArraySize(guards); + + // + return result; + } + + /** + * Check Additional Validations on Childs Instances ... + * + * @return ( bool virtual ) + */ + bool virtual CheckAdditionslSignallerValidations() + { + // + bool result = false; + + // + // Validate Fima Helper Requirements ... + result = fimaInputs.IsValid() && + fimaHelper != NULL && + poiDetector != NULL; + if (!result) + { + return result; + } + + // + return result; + } + + /** + * Normalizing Signal by Signaller Custom Props ... + * + * @param signal: XSignal ... + */ + void virtual NormalizeSignal(XSignal &signal) + { + } + + // + // Protected ... + protected: + // + + // + // Protected Actions ... + + // + // Private ... + private: + // +}; + +// +// XFIMA Strategy 2 Signaller Class ... +class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructor ... + XCXFIMAStrategy1Signaller( + string _symbol, // Symbol ... + ENUM_TIMEFRAMES _period, // Period ... + XFIMAInputs &_fimaInputs, // XFIMAInputs ... + bool _processAllTicks = false, // Process All Ticks ... + double _defaultSignalR2R = 1.5, // Default Signal Risk To Reward Ratio ... + double _defaultSignalRiskInPoint = 50, // Default Signal Risk In Point ... + double _defaultSignalVolume = 0.01 // Default Signal Volume ... + ) : XCXFIMABaseSignaller("XFIMA1", + _symbol, + _period, + _fimaInputs, + _processAllTicks, + _defaultSignalR2R, + _defaultSignalRiskInPoint, + _defaultSignalVolume // + ) + { + // + // Configure ... + drawLeg = true; + drawOrderFlow = true; + structureConfig.Default(); + structureDrawConfig.Default(); + } + + // + // Deconstructor ... + ~XCXFIMAStrategy1Signaller() + { + // + Destroy(); + } + + // + // Overrides ... + + /** + * Processing Tick ... + * + * @param barIndex: int, Specified Bar Index ... + */ + virtual void ProcessTick(int barIndex = 0) + { + } + + /** + * Processing New Bar ... + * + * @param barIndex: int, Specified Bar Index ... + */ + virtual void ProcessNewBar(int barIndex = 0) + { + // + // Normalize ... + barIndex = NormalizeInt(barIndex, 0); + + // + XOHCL iBar; + XBoxZone iZone; + XSignal iSignal; + bool has = false; + XTarget iTargets[]; + bool isBullish = false; + bool isBearish = false; + ENUM_X_DIRECTION iDir = X_DIRECTION_NONE; + + // + // Initialize Bar as CBar ... + has = iBar.Init( + symbol, + period, + barIndex // + ); + if (!has) + { + // + iBar.Clean(); + return; + } + + // + // Manage ... + Manage(iBar); + + // + // Strategy X ... + has = HasSignal( + iBar, + iZone, + iTargets, + iDir // + ); + + // + // Handle Resting Signals ... + has = HasDirection(iDir) && + iZone.IsValid(); + + // + // Prepare Signal ... + if (has) + { + // + isBullish = IsXBullish(iDir); + isBearish = IsXBearish(iDir); + + // + // Provided SL ... + double points = GetPoints(symbol); + double spread = GetSpread(symbol); + double entry = GetEntry(symbol, iDir); + + // + // Calculate SL Addition ... + double slAddition = + slAdditionDistance <= 0 + ? 0 + : slAdditionDistance * points; + + // + // Calculate SL Price ... + double sl = + isBullish + ? iZone.lower - slAddition + : iZone.upper + slAddition; + + // + // Prepare Signal ... + has = PrepareSignal( + iSignal, + iDir, + iTargets, + 0, // Use Default R2R ... + sl, // Provided Price for SL ... + 0 // Specified Risk in Point .... + ); + } + + // + // Notify On Signal Event ... + if (has) + { + NotifySignalEventListeners(iSignal); + } + + // + // Cleanup ... + iBar.Clean(); + iZone.Clean(); + iSignal.Clean(); + XClean(iTargets); + } + + /** + * Check Guards Based on MarketConditions ... + * + * @param guards: XGuard, reference collection to holds result ... + * @param positions: XPosition, reference collection to provides positions ... + * @param barIndex: int + * + * @return ( int ) + */ + int virtual CheckForGuard( + XGuard &guards[], + XPosition &positions[], + int barIndex = 0 // + ) + { + // + int result = 0; + + // + XClean(guards); + + // + int positionsCount = ArraySize(positions); + if (!IsValidSize(positionsCount)) + { + return result; + } + + // + // Requirements ... + XGuard iGuard; + bool has = false; + + // + // Force Hedging ... + // bool forceHedging = (positionsCount >= 2); + // if (forceHedging) + // { + // // + // // Minimum Required Reward ... + // double minRequiredReward = 1.5; + + // // + // // Summarizing Risk and Reward of Collections ... + // // double risk = 0; + // // double volume = 0; + // // double reward = 0; + // // for (int i = 0; i < positionsCount; i++) + // // { + // // // + // // risk += positions[i].GetRisk() + positions[i].commission + (-1 * positions[i].swap); + // // reward += positions[i].profit; + // // volume += positions[i].volume; + // // } + + // // // + // // risk *= volume; + // // reward *= volume; + + // // // + // // // Calculating Can Hedge rops ... + // // has = reward >= (risk * minRequiredReward); + // // if (has) + // // { + // // // + // // iGuard.Clean(); + // // iGuard.force = true; + // // iGuard.symbol = symbol; + // // iGuard.period = period; + // // iGuard.provider = name; + // // iGuard.time = TimeCurrent(); + // // iGuard.action = X_GUARD_ACTION_HEDGE; + + // // // + // // // Validate Guard ... + // // has = iGuard.IsValid(); + // // if (has) + // // { + // // // + // // AddRef( + // // iGuard, + // // guards // + // // ); + // // } + // // } + // } + + // + result = ArraySize(guards); + + // + // Cleanup ... + iGuard.Clean(); + + // + return result; + } + + // + // Protected ... + protected: + // + + // + void Manage(XOHCL &bar) + { + // + bool has = bar.IsValid(); + if (!has) + { + return; + } + + // + XOHCL pBar; + XOHCL p2Bar; + XOHCL p3Bar; + has = bar.GetPreviousBar(pBar); + has = has && + pBar.GetPreviousBar(p2Bar); + has = has && + p2Bar.GetPreviousBar(p3Bar); + if (!has) + { + // + pBar.Clean(); + p2Bar.Clean(); + p3Bar.Clean(); + } + + // + ManageLeg(bar); + ManageOrderFlow(p3Bar); + + // + // Cleanup ... + pBar.Clean(); + p2Bar.Clean(); + p3Bar.Clean(); + } + + // + // Private ... + private: + // + // Props ... + + // + // Leg ... + + XLeg leg; // Exists Leg ... + bool drawLeg; // Draw Leg ... + + // + bool HasLeg() + { + return leg.IsValid(); + } + + // + bool ValidateLeg(XOHCL &bar) + { + // + bool result = false; + + // + result = HasLeg() && + bar.IsValid(); + if (!result) + { + return result; + } + + // + result = + leg.IsBullish() + ? bar.low > leg.lower + : leg.IsBearish() + ? bar.high < leg.upper + : false; + + // + return result; + } + + // + void DrawLeg() + { + // + if (!drawLeg) + { + return; + } + + // + if (!HasLeg()) + { + return; + } + + // + // Update to Times ... + leg.UpdateTimes(); + + // + // Draw Leg Box ... + XBoxZone legZone; + leg.ToBox(legZone); + if (legZone.IsValid()) + { + // + legZone.to = TimeCurrent(); + poiDrawer.DrawZone(legZone, structureDrawConfig.drawConfig); + } + + // + // Draw Legs Other Stufs ... + return; + + // + // FVGs ... + poiDrawer.DrawZones(leg.bullishFVGs, structureDrawConfig.drawConfig); + poiDrawer.DrawZones(leg.bearishFVGs, structureDrawConfig.drawConfig); + + // + // Support and Resistances ... + poiDrawer.DrawZones(leg.supports, structureDrawConfig.drawConfig); + poiDrawer.DrawZones(leg.resistances, structureDrawConfig.drawConfig); + + // + // Patterns ... + poiDrawer.DrawPatternAnalysises(leg.patterns, structureDrawConfig.barAnalysisDrawConfig); + } + + // + void ManageLeg(XOHCL &bar) + { + // + // Validate Exists ... + if (HasLeg()) + { + // + if (!ValidateLeg(bar)) + { + // + // Invalidate XLeg ... + leg.Clean(); + } + } + + // + // Detect New ... + if (!HasLeg()) + { + poiDetector.IsLegPattern(bar, leg); + } + + // + // Update Exists ... + if (HasLeg()) + { + // + // Update to Times ... + leg.UpdateTimes(); + + // + DrawLeg(); + } + } + + // + // Order Flow ... + + // + bool drawOrderFlow; + XBoxZone orderFlow[]; + ENUM_X_DIRECTION orderFlowDir; + + // + bool HasOrderFlow() + { + // + return HasChild(orderFlow) && + HasDirection(orderFlowDir); + } + + bool HasBullishOrderFlow() + { + return HasOrderFlow() && + IsXBullish(orderFlowDir); + } + + bool HasBearishOrderFlow() + { + return HasOrderFlow() && + IsXBearish(orderFlowDir); + } + + bool GetOrderFlowBoundary( + double &upper, + double &lower // + ) + { + // + bool result = false; + + // + // Prepare ... + upper = EMPTY_VALUE; + lower = EMPTY_VALUE; + + // + // Validate ... + result = HasOrderFlow(); + if (!result) + { + return result; + } + + // + int idx = -1; + + // + // Upper ... + idx = GetHighest(orderFlow); + if (IsValidIndex(idx)) + { + upper = orderFlow[idx].upper; + } + + // + // Lower ... + idx = GetLowest(orderFlow); + if (IsValidIndex(idx)) + { + lower = orderFlow[idx].lower; + } + + // + result = NotEmptyZero(upper) && + NotEmptyZero(lower) && + upper > lower; + + // + // Cleanup ... + if (!result) + { + // + upper = EMPTY_VALUE; + lower = EMPTY_VALUE; + } + + // + return result; + } + + bool ValidateOrderFlow(XOHCL &bar) + { + // + bool result = false; + + // + // Validate ... + result = bar.IsValid() && + HasOrderFlow(); + if (!result) + { + return result; + } + + // + double upper = EMPTY_VALUE; + double lower = EMPTY_VALUE; + result = GetOrderFlowBoundary(upper, lower); + result = result && + HasBullishOrderFlow() + ? bar.low > lower + : bar.high < upper; + + // + return result; + } + + void DrawOrderFlow() + { + // + if (!drawOrderFlow || !HasOrderFlow()) + { + return; + } + + // + poiDrawer.DrawZones(orderFlow, structureDrawConfig.drawConfig); + } + + void ManageOrderFlow(XOHCL &bar) + { + // + // Validate Exists ... + if (HasOrderFlow()) + { + // + if (!ValidateOrderFlow(bar)) + { + // + // Invalidate OrderFlow ... + XClean(orderFlow); + orderFlowDir = X_DIRECTION_NONE; + } + } + + // + // Detect New ... + if (!HasOrderFlow()) + { + // + XPatternAnalysisConfig patternConfig = structureConfig.barsAnalysisConfig; + // patternConfig.Default(); + // patternConfig.supportAndResistanceLoopbackLength = 21; + // patternConfig.supportAndResistanceValidationLength = 7; + + // + poiDetector.HasOrderFlow( + bar, + orderFlowDir, + orderFlow, + structureConfig.orderFlowValidation, + structureConfig.orderFlowUseOB, + structureConfig.orderFlowUseFVG, + structureConfig.orderFlowUseSupportAndResistance, + patternConfig.supportAndResistanceLoopbackLength, + patternConfig.supportAndResistanceValidationLength, + structureConfig.loopback // + ); + } + + // + // Update Exists ... + if (HasOrderFlow()) + { + // + // Update to Times ... + UpdateToTime(orderFlow, TimeCurrent()); + + // + DrawOrderFlow(); + } + } + + // + // Implementing Strategies ... + + /** + * Check Bar Has Signal Based on Strategy X ... + * + * @param bar: XOHCL, reference to Bar ... + * @param zone: XBoxZone, reference to holds affected zone ... + * @param targets: XTarget, reference to detected Signal's Targets collections ... + * @param dir: ENUM_X_DIRECTION, detected Signal's direction ... + * + * @return ( bool ) + */ + bool HasSignal( + XOHCL &bar, + XBoxZone &zone, + XTarget &targets[], + ENUM_X_DIRECTION &dir // + ) + { + // + bool result = false; + + // + // Configuration Flags ... + + // + // Signaller Flags ... + bool useSignaller1 = false; + bool useSignaller2 = false; + bool useSignaller3 = false; + bool useSignaller4 = true; + + // + // Validator Flags ... + string provider = NULL; + bool validateByOrderFlow = false; + + // + // Target Flags ... + bool hasPartialCloseOnTp1 = false; + + // + bool doRFOnEntryOnTP1 = false; + + // + // Draw Flags ... + bool draw = true; + bool drawZone = true; + bool drawMarketStructurePivots = true; + bool drawMarketStructureAnalysis = true; + bool drawMarketStructureOrderFlow = true; + XPOIDrawConfig iDrawConfig; + + // + drawLeg = false; + drawOrderFlow = false; + + // + // Signal Checking ... + + // + // Analyse Market Strucutre ... + XFIMAMarketStructure marketStructure; + + // + // Check Market ... + // result = HasLeg() && + // HasOrderFlow() && + // orderFlowDir == leg.dir; + // result = HasBearishOrderFlow(); + // if (result) + // { + // // + // result = false; + // DebugBreak(); + // } + + // + // Signaller 1 ... + if (!result && useSignaller1) + { + // + result = Strategy1HasSignal( + bar, + zone, + targets, + dir // + ); + + // + if (result) + { + provider = "1"; + } + } + + // + // Signaller 2 ... + if (!result && useSignaller2) + { + // + result = Strategy2HasSignal( + bar, + zone, + targets, + dir // + ); + + // + if (result) + { + provider = "2"; + } + } + + // + // Signaller 3 ... + if (!result && useSignaller3) + { + // + result = Strategy3HasSignal( + bar, + zone, + targets, + dir // + ); + + // + if (result) + { + provider = "3"; + } + } + + // + // Signaller 4 ... + if (!result && useSignaller4) + { + // + result = Strategy4HasSignal( + bar, + zone, + targets, + dir // + ); + + // + if (result) + { + provider = "4"; + } + } + + // + // Signal Validating ... + + // + // Validate Signals by Order Flow ... + if (result && validateByOrderFlow) + { + // + // Analyse Market Structure if Required ... + if (!marketStructure.IsValid()) + { + // + poiDetector.AnalyseMarket( + marketStructure, + structureConfig, + bar.Index() // + ); + } + + // + bool isBullish = IsXBullish(dir) && + marketStructure.HasBullishOrderFlow(); + + // + bool isBearish = IsXBearish(dir) && + marketStructure.HasBearishOrderFlow(); + + // + // Summarizing result ... + result = isBullish || + isBearish; + } + + // + // Targets, Restrictions and Risk Management ... + if (result) + { + // + // Requirements ... + XTarget iTarget; + + // + // Checking Direction of Signal ... + bool isBullish = IsXBullish(dir); + bool isBearish = IsXBearish(dir); + + // + // Provided SL ... + double points = GetPoints(symbol); + double spread = GetSpread(symbol); + double entry = GetEntry(symbol, dir); + + // + // Calculate SL Addition ... + double slAddition = + slAdditionDistance <= 0 + ? 0 + : slAdditionDistance * points; + + // + // Calculate SL Price ... + double sl = + isBullish + ? zone.lower - slAddition + : zone.upper + slAddition; + + // + // Calculate Risk ... + double risk = MathAbs(entry - sl); + + // + // Calculate Reward ... + double reward = defaultSignalR2R * risk; + + // + // Calculate TP1 ... + double tp1 = isBullish + ? entry + risk + : entry - risk; + double tp2 = isBullish + ? entry + (2 * risk) + : entry - (2 * risk); + + // + // Calculate TP ... + double tp = isBullish + ? entry + reward + : entry - reward; + + // + // Check Max Allowed Risk ... + bool hasTooMuchRisk = maxAllowedRiskDistance <= 0 + ? false + : risk >= (maxAllowedRiskDistance * points); + if (hasTooMuchRisk) + { + // + // Clean Signal if Too much Risk ... + zone.Clean(); + dir = X_DIRECTION_NONE; + } + + // + // Common Targets ... + + // + // Partial Close on TP 1 ... + if (hasPartialCloseOnTp1) + { + // + iTarget.Clean(); + iTarget.target = tp1; + iTarget.actingDistance = 5; + iTarget.volumeMultiplier = 0.8; + iTarget.doRFOnEntry = doRFOnEntryOnTP1; + + // + AddRef(iTarget, targets); + } + + // + // Custom Signaller Targets ... + + // + // Restrictions Handling ... + if (risk > 0 && HasRestrictions()) + { + // + // Reset Restricitons if necessary ... + ResetRestrictions(); + + // + // Handle Custom Restrictions Senario ... + } + + // + // Ignore Targets ... + if (ignoreTargets) + { + XClean(targets); + } + + // + // Summarize Result ... + result = zone.IsValid() && + HasDirection(dir); + + // + // Cleanup ... + iTarget.Clean(); + } + + // + // Draws ... + if (result && draw) + { + // + // Prepare Draw Config ... + iDrawConfig = structureDrawConfig.drawConfig; + iDrawConfig.zonesWidth = 3; + iDrawConfig.zonesStyle = STYLE_DASH; + iDrawConfig.bullishColor = clrYellow; + iDrawConfig.bearishColor = clrDarkOrange; + + // + // Draw Zone ... + if (drawZone) + { + poiDrawer.DrawZone(zone, iDrawConfig); + } + + // + // Draw Market Structure ... + // + // Analyse Market Structure if Required ... + if (!marketStructure.IsValid()) + { + // + poiDetector.AnalyseMarket( + marketStructure, + structureConfig, + bar.Index() // + ); + } + if (marketStructure.IsValid()) + { + // + // Order Flow ... + if (drawMarketStructureOrderFlow && marketStructure.HasOrderFlow()) + { + poiDrawer.DrawZones(marketStructure.orderFlow, iDrawConfig); + } + + // + // Pivots ... + if (drawMarketStructurePivots) + { + // + XPivot pivots[]; + int pivotsCount = marketStructure.CollectPivots( + pivots, + true // Contains Patterns ... + ); + if (IsValidSize(pivotsCount)) + { + poiDrawer.DrawPivots(pivots, iDrawConfig); + } + + // + XClean(pivots); + } + + // + // Analysis ... + if (drawMarketStructureAnalysis) + { + // + } + } + + // + // Other Drawing Materials ... + } + + // + // Cleanup ... + if (!result) + { + // + zone.Clean(); + XClean(targets); + dir = X_DIRECTION_NONE; + } + + // + // Debug Breake ... + if (result) + { + DebugBreak(); + } + + // + // Cleanup ... + iDrawConfig.Clean(); + marketStructure.Clean(); + + // + return result; + } + + /** + * Check Bar Has Signal Based on Strategy 3 ... + * + * @param bar: XOHCL, reference to Bar ... + * @param zone: XBoxZone, reference to holds affected zone ... + * @param targets: XTarget, reference to detected Signal's Targets collections ... + * @param dir: ENUM_X_DIRECTION, detected Signal's direction ... + * + * @return ( bool ) + */ + bool Strategy1HasSignal( + XOHCL &bar, + XBoxZone &zone, + XTarget &targets[], + ENUM_X_DIRECTION &dir // + ) + { + // + bool result = false; + + // + // Prepare ... + zone.Clean(); + XClean(targets); + dir = X_DIRECTION_NONE; + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + // Define Requirements ... + + // + XOHCL pBar; + bool isBullish = false; + bool isBearish = false; + + // + // Read PBar ... + result = bar.GetPreviousBar(pBar); + if (!result) + { + // + pBar.Clean(); + return result; + } + + // + // Reading Conditions ... + int pullBackStartBar = -1; + bool isPullBack = result && + poiDetector.IsPullbackPattern( + pBar, + zone, + dir, + 2, + false // Force Break ... + ); + bool isPullbackBullish = isPullBack && + IsXBullish(dir); + bool isPullbackBearish = isPullBack && + IsXBearish(dir); + if (isPullBack) + { + pullBackStartBar = zone.FromIndex(); + } + + // + // Reading HK Band ... + + // + double pHKBandUpper = fimaHelper.GetHKBandUpper(pBar.Index()); + double pHKBandLower = fimaHelper.GetHKBandLower(pBar.Index()); + int overHKBandUpperCount = fimaParser.CountOverHKBandUpper(pullBackStartBar, X_PRICE_LOW); + int underHKBandLowerCount = fimaParser.CountUnderHKBandLower(pullBackStartBar, X_PRICE_HIGH); + + // + // Reading PV Requirements ... + + // + int lastPeakOverLastIDX = -1; + int lastValeUnderLastIDX = -1; + double pPeak = fimaHelper.GetPeak(pBar.Index()); + double pVale = fimaHelper.GetVale(pBar.Index()); + int samePeaks = fimaParser.CountSamePeaks(pBar.Index()); + int sameVales = fimaParser.CountSameVales(pBar.Index()); + fimaParser.FindLastPeakOverLast(lastPeakOverLastIDX, pBar.Index()); + fimaParser.FindLastValeUnderLast(lastValeUnderLastIDX, pBar.Index()); + + // + // Reading pBar Patterns ... + XPatternAnalysis pBarAnalysis; + poiDetector.AnalyseBarPatterns( + pBar, + pBarAnalysis, + structureConfig.barsAnalysisConfig // + ); + + // + // Check Bar Patterns ... + bool isPBarHasBullishPatterns = + (bar.close > pBar.low || + bar.open > pBar.low) && + ( + // + pBarAnalysis.IsPinned(X_DIRECTION_BULLISH) || + pBarAnalysis.IsEngulfed(X_DIRECTION_BULLISH) || + pBarAnalysis.IsMomentum(X_DIRECTION_BULLISH) || + pBarAnalysis.IsPiercing(X_DIRECTION_BULLISH) || + pBarAnalysis.IsSignalKey(X_DIRECTION_BULLISH) + // + ); + bool isPBarHasBearishPatterns = + (bar.close < pBar.high || + bar.open < pBar.high) && + ( + // + pBarAnalysis.IsPinned(X_DIRECTION_BEARISH) || + pBarAnalysis.IsEngulfed(X_DIRECTION_BEARISH) || + pBarAnalysis.IsMomentum(X_DIRECTION_BEARISH) || + pBarAnalysis.IsPiercing(X_DIRECTION_BEARISH) || + pBarAnalysis.IsSignalKey(X_DIRECTION_BEARISH) + // + ); + + // + // Check PBar Close Over Under Fast Ma ... + bool isPBarCloseOverFast = pBar.close > fimaHelper.GetMAFast(pBar.Index()); + bool isPBarCloseUnderFast = pBar.close < fimaHelper.GetMAFast(pBar.Index()); + + // + // Try To Find Affected Zone ... + + // + // Collecting Zones ... + XBoxZone zones[]; + XBoxZone affectedZones[]; + XBoxZone affectedZonesBullish[]; + XBoxZone affectedZonesBearish[]; + int zonesCount = poiDetector.CollectZones( + pBar, + zones, // + 5, // Zones Loopback ... + 3 // Zones Validation Length ... + // Required Zones ... + // Loopback ... + ); + int affectedZonesCount = ExtractAffectedZones( + pBar, + zones, + affectedZones // + ); + int affectedZonesBullishCount = ExtractByDirection( + affectedZonesBullish, + affectedZones, + X_DIRECTION_BULLISH // + ); + int affectedZonesBearishCount = ExtractByDirection( + affectedZonesBearish, + affectedZones, + X_DIRECTION_BEARISH // + ); + + // + int insideBullishIDX = -1; + int insideBearishIDX = -1; + bool hasBullishInside = + pBar.IsBullish() && + HasInside( + insideBullishIDX, + pBar, + affectedZonesBullish // + ); + bool hasBearishInside = + pBar.IsBearish() && + HasInside( + insideBearishIDX, + pBar, + affectedZonesBearish // + ); + + // + // Do ... + + // + isBullish = + // + hasBullishInside && + isPullbackBullish && + isPBarHasBullishPatterns && + fimaParser.IsSARBullish(pBar.Index()) && + (pVale >= affectedZonesBullish[insideBullishIDX].lower && + pVale <= affectedZonesBullish[insideBullishIDX].upper) + // + ; + + // + isBearish = + // + hasBearishInside && + isPullbackBearish && + isPBarHasBearishPatterns && + fimaParser.IsSARBearish(pBar.Index()) && + (pPeak >= affectedZonesBearish[insideBearishIDX].lower && + pPeak <= affectedZonesBearish[insideBearishIDX].upper) + // + ; + + // + // Validate ... + result = isBullish || + isBearish; + if (result) + { + // + dir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + result = HasDirection(dir); + } + + // + // Prepare Zone ... + if (result) + { + // + zone.Clean(); + if (isBullish) + { + zone = affectedZonesBullish[insideBullishIDX]; + } + else + { + zone = affectedZonesBearish[insideBearishIDX]; + } + + // + result = zone.IsValid(); + } + + // + // Prepare Targets ... + if (result) + { + } + + // + // Cleanup ... + if (!result) + { + // + zone.Clean(); + XClean(targets); + dir = X_DIRECTION_NONE; + } + pBar.Clean(); + XClean(zones); + pBarAnalysis.Clean(); + XClean(affectedZones); + XClean(affectedZonesBullish); + XClean(affectedZonesBearish); + + // + return result; + } + + /** + * Check Bar Has Signal Based on Strategy 3 ... + * + * @param bar: XOHCL, reference to Bar ... + * @param zone: XBoxZone, reference to holds affected zone ... + * @param targets: XTarget, reference to detected Signal's Targets collections ... + * @param dir: ENUM_X_DIRECTION, detected Signal's direction ... + * + * @return ( bool ) + */ + bool Strategy2HasSignal( + XOHCL &bar, + XBoxZone &zone, + XTarget &targets[], + ENUM_X_DIRECTION &dir // + ) + { + // + bool result = false; + + // + // Prepare ... + zone.Clean(); + XClean(targets); + dir = X_DIRECTION_NONE; + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + // Define Requirements ... + + // + XOHCL pBar; + XOHCL p2Bar; + bool isBullish = false; + bool isBearish = false; + + // + // Read PBar ... + result = bar.GetPreviousBar(pBar); + result = result && + pBar.GetPreviousBar(p2Bar); + if (!result) + { + // + pBar.Clean(); + p2Bar.Clean(); + + // + return result; + } + + // + // Reading pBar Patterns ... + XPatternAnalysis pBarAnalysis; + poiDetector.AnalyseBarPatterns( + pBar, + pBarAnalysis, + structureConfig.barsAnalysisConfig // + ); + + // + // Check Bar Patterns ... + bool isPBarHasBullishPatterns = + (bar.close > pBar.low || + bar.open > pBar.low) && + ( + // + pBarAnalysis.IsPinned(X_DIRECTION_BULLISH) || + pBarAnalysis.IsEngulfed(X_DIRECTION_BULLISH) || + pBarAnalysis.IsMomentum(X_DIRECTION_BULLISH) || + pBarAnalysis.IsPiercing(X_DIRECTION_BULLISH) || + pBarAnalysis.IsSignalKey(X_DIRECTION_BULLISH) + // + ); + bool isPBarHasBearishPatterns = + (bar.close < pBar.high || + bar.open < pBar.high) && + ( + // + pBarAnalysis.IsPinned(X_DIRECTION_BEARISH) || + pBarAnalysis.IsEngulfed(X_DIRECTION_BEARISH) || + pBarAnalysis.IsMomentum(X_DIRECTION_BEARISH) || + pBarAnalysis.IsPiercing(X_DIRECTION_BEARISH) || + pBarAnalysis.IsSignalKey(X_DIRECTION_BEARISH) + // + ); + + // + double peak = fimaHelper.GetPeak(bar.Index()); + double vale = fimaHelper.GetVale(bar.Index()); + double pPeak = fimaHelper.GetPeak(pBar.Index()); + double pVale = fimaHelper.GetVale(pBar.Index()); + double p2Peak = fimaHelper.GetPeak(p2Bar.Index()); + double p2Vale = fimaHelper.GetVale(p2Bar.Index()); + bool isPPeakOverLast = fimaParser.IsPeakOverLast(pBar.Index()); + bool isPValeUnderLast = fimaParser.IsValeUnderLast(pBar.Index()); + bool isP2PeakOverLast = fimaParser.IsPeakOverLast(p2Bar.Index()); + bool isP2ValeUnderLast = fimaParser.IsValeUnderLast(p2Bar.Index()); + bool isPeakOverLast = isPPeakOverLast || + isP2PeakOverLast; + bool isValeUnderLast = isPValeUnderLast || + isP2ValeUnderLast; + bool isP2ValeOverLast = pVale > p2Vale; + bool isP2PeakUnderLast = pPeak < p2Peak; + + // + // Check PBar Close Over Under Fast Ma ... + bool isPBarCloseOverFast = pBar.close > fimaHelper.GetMAFast(pBar.Index()); + bool isPBarCloseUnderFast = pBar.close < fimaHelper.GetMAFast(pBar.Index()); + bool isFastOverLast = fimaHelper.GetMAFast(pBar.Index()) > fimaHelper.GetMAFast(p2Bar.Index()); + bool isFastUnderLast = fimaHelper.GetMAFast(pBar.Index()) < fimaHelper.GetMAFast(p2Bar.Index()); + + // + // Force P2Bar is Pin Bar ... + ENUM_X_DIRECTION p2Dir; + bool isP2BarPinned = poiDetector.IsPinnedBar( + p2Bar, + p2Dir // + ); + bool isP2BarBullishPinned = + isP2BarPinned && + IsXBullish(p2Dir); + bool isP2BarBearishPinned = + isP2BarPinned && + IsXBearish(p2Dir); + + // + // Do ... + + // + isBullish = + // + isFastOverLast && + isValeUnderLast && + !isP2PeakUnderLast && + isPBarCloseOverFast && + isP2BarBullishPinned && + isPBarHasBullishPatterns + // + ; + + // + isBearish = + // + isPeakOverLast && + isFastUnderLast && + !isP2ValeOverLast && + isPBarCloseUnderFast && + isP2BarBearishPinned && + isPBarHasBearishPatterns + // + ; + + // + // Validate ... + result = isBullish || + isBearish; + if (result) + { + // + dir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + result = HasDirection(dir); + } + + // + // Prepare Zone ... + if (result) + { + // + zone.Clean(); + result = ToBox( + p2Bar, + zone, + dir, + X_BAR_PATTERN_PINNED // + ); + + // + // Manage Stops ... + if (result) + { + // + double entry = GetEntry(zone.symbol, zone.dir); + double riskSide = zone.IsBullish() ? zone.lower : zone.upper; + double risk = MathAbs(entry - riskSide); + + // + // Collecting Affected Zones ... + XBoxZone tmps[]; + XBoxZone zones[]; + XBoxZone actedZones[]; + XBoxZone insideZones[]; + XBoxZone breakedZones[]; + XBoxZone affectedZones[]; + + // + // Support and Resistances ... + poiDetector.CollectZones(bar, tmps); + Copy(tmps, zones, false); + + // + // OBS ... + poiDetector.CollectOBs(bar, tmps); + Copy(tmps, zones, false); + + // + // FVGs ... + poiDetector.CollectFVGs(bar, tmps); + Copy(tmps, zones, false); + + // + ExtractAffectedZones(bar, zones, affectedZones); + + // + // Acteds Zones ... + ExtractActeds(bar, actedZones, affectedZones); + + // + // Inside Zones ... + ExtractInsides(bar, insideZones, affectedZones); + + // + // Breaked Zones ... + ExtractBreakeds(bar, breakedZones, affectedZones); + + // + // Cleanup ... + XClean(tmps); + XClean(zones); + XClean(actedZones); + XClean(insideZones); + XClean(breakedZones); + XClean(affectedZones); + } + + // + result = zone.IsValid(); + } + + // + // Prepare Targets ... + if (result) + { + } + + // + // Cleanup ... + if (!result) + { + // + zone.Clean(); + XClean(targets); + dir = X_DIRECTION_NONE; + } + pBar.Clean(); + p2Bar.Clean(); + + // + return result; + } + + /** + * Check Bar Has Signal Based on Strategy 4 ... + * + * @param bar: XOHCL, reference to Bar ... + * @param zone: XBoxZone, reference to holds affected zone ... + * @param targets: XTarget, reference to detected Signal's Targets collections ... + * @param dir: ENUM_X_DIRECTION, detected Signal's direction ... + * + * @return ( bool ) + */ + bool Strategy3HasSignal( + XOHCL &bar, + XBoxZone &zone, + XTarget &targets[], + ENUM_X_DIRECTION &dir // + ) + { + // + bool result = false; + + // + // Prepare ... + zone.Clean(); + XClean(targets); + dir = X_DIRECTION_NONE; + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + // Define Requirements ... + + // + XOHCL pBar; + XOHCL p2Bar; + bool isBullish = false; + bool isBearish = false; + + // + // Read PBar ... + result = bar.GetPreviousBar(pBar); + result = result && + pBar.GetPreviousBar(p2Bar); + if (!result) + { + // + pBar.Clean(); + p2Bar.Clean(); + + // + return result; + } + + // + // Do ... + // XFIMA Consolidation ... + + // + bool isConsolidation = poiDetector.DetectPVConsolidationZone( + zone, + pBar.Index(), + true, // Force PV Break ... + true // Force Has Sar Switch ... + ); + + // + isBullish = + isConsolidation && + zone.IsBullish(); + + // + isBearish = + isConsolidation && + zone.IsBearish(); + + // + // Validate based on Bars Patterns ... + bool validateByBarPatterns = true; + if (validateByBarPatterns) + { + // + // Reading pBar Patterns ... + XPatternAnalysis pBarAnalysis; + poiDetector.AnalyseBarPatterns( + pBar, + pBarAnalysis, + structureConfig.barsAnalysisConfig // + ); + + // + // Bullish ... + bool isPBarHasBullishPatterns = + (bar.close > pBar.low || + bar.open > pBar.low) && + ( + // + pBarAnalysis.IsPinned(X_DIRECTION_BULLISH) || + pBarAnalysis.IsEngulfed(X_DIRECTION_BULLISH) || + pBarAnalysis.IsMomentum(X_DIRECTION_BULLISH) || + pBarAnalysis.IsPiercing(X_DIRECTION_BULLISH) || + pBarAnalysis.IsSignalKey(X_DIRECTION_BULLISH) + // + ); + + // + // Bearish ... + bool isPBarHasBearishPatterns = + (bar.close < pBar.high || + bar.open < pBar.high) && + ( + // + pBarAnalysis.IsPinned(X_DIRECTION_BEARISH) || + pBarAnalysis.IsEngulfed(X_DIRECTION_BEARISH) || + pBarAnalysis.IsMomentum(X_DIRECTION_BEARISH) || + pBarAnalysis.IsPiercing(X_DIRECTION_BEARISH) || + pBarAnalysis.IsSignalKey(X_DIRECTION_BEARISH) + // + ); + + // + isBullish = + isBullish && + isPBarHasBullishPatterns && + !isPBarHasBearishPatterns; + + // + isBearish = + isBearish && + isPBarHasBearishPatterns && + !isPBarHasBullishPatterns; + + // + // Summarize Result ... + result = isBullish || + isBearish; + } + + // + // Checking PullBack ... + bool validateByPullback = false; + if (validateByPullback) + { + // + XBoxZone pullback; + ENUM_X_DIRECTION pullbackDir; + bool isPullBack = result && + poiDetector.IsPullbackPattern( + pBar, + pullback, + pullbackDir, + 2, + false // Force Break ... + ); + bool isPullbackBullish = isPullBack && + IsXBullish(pullbackDir); + bool isPullbackBearish = isPullBack && + IsXBearish(pullbackDir); + + // + isBullish = + isBullish && + isPullbackBullish; + + // + isBearish = + isBearish && + isPullbackBearish; + + // + // Summarize Result ... + result = isBullish || + isBearish; + } + + // + // Validate ... + result = isBullish || + isBearish; + + // + // Prepare Zone ... + if (result) + { + } + + // + // Prepare Targets ... + if (result) + { + } + + // + // Cleanup ... + if (!result) + { + // + zone.Clean(); + XClean(targets); + dir = X_DIRECTION_NONE; + } + pBar.Clean(); + p2Bar.Clean(); + + // + return result; + } + + /** + * Check Bar Has Signal Based on Strategy 4 ... + * + * Strategy 4: + * =========== + * - Works Based on Order Flow ... + * - Looking for new and Fresh Order Flow ... + * - Validate Bar is Inside Order Flow ... + * - Validate Bar has Proper Pattern ... + * - Validate Bar Based on ATR Band in two Step: + * - Step 1: Bars is Inside ATR Band (Middle) ... + * - Step 2: Trigger Bars Close Price based on ATR Band ... + * - Validate Order Flow based on Market Structure Zone ... + * - Validate Trigger Bar based on InDirectional Market Structure Zones ... + * + * Manipulations: + * ================ + * there are Some Flags properties to Change Validations in Strategy ... + * we can use them for Testing Purposes ... + * + * @param bar: XOHCL, reference to Bar ... + * @param zone: XBoxZone, reference to holds affected zone ... + * @param targets: XTarget, reference to detected Signal's Targets collections ... + * @param dir: ENUM_X_DIRECTION, detected Signal's direction ... + * + * @return ( bool ) + */ + bool Strategy4HasSignal( + XOHCL &bar, + XBoxZone &zone, + XTarget &targets[], + ENUM_X_DIRECTION &dir // + ) + { + // + bool result = false; + + // + // Prepare ... + zone.Clean(); + XClean(targets); + dir = X_DIRECTION_NONE; + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + // Validation Flags ... + bool validateBarInsideZone = true; + bool validateByBarPatterns = true; + bool validateByBarInsideATRBand = true; + bool validateByBarBasedOnATRBand = true; + bool validateMarketStructureHasDirectionalZone = true; + bool validateMarketStructureDirectionalZoneInsideOrderFlow = true; + bool validateMarketStructureHasNotInDirectionalZoneOrUnReachedTP = true; + + // + // Define Requirements ... + + // + XOHCL pBar; + XOHCL p2Bar; + XOHCL p3Bar; + bool isBullish = false; + bool isBearish = false; + + // + // Read PBar ... + result = bar.GetPreviousBar(pBar); + result = result && + pBar.GetPreviousBar(p2Bar); + result = result && + p2Bar.GetPreviousBar(p3Bar); + if (!result) + { + // + pBar.Clean(); + p2Bar.Clean(); + p3Bar.Clean(); + + // + return result; + } + + // + // Do ... + + // + // Retrieve pBar Patterns ... + XPatternAnalysis pBarPatterns; + XPatternAnalysisConfig patternConfig = structureConfig.barsAnalysisConfig; + + // + poiDetector.AnalyseBarPatterns( + pBar, + pBarPatterns, + patternConfig // + ); + + // + // Detecting OrderFlow ... + XBoxZone oFlow[]; + bool hasOrderFlow = poiDetector.HasOrderFlow( + p3Bar, + dir, + oFlow, + structureConfig.orderFlowValidation, + structureConfig.orderFlowUseOB, + structureConfig.orderFlowUseFVG, + structureConfig.orderFlowUseSupportAndResistance, + patternConfig.supportAndResistanceLoopbackLength, + patternConfig.supportAndResistanceValidationLength, + structureConfig.loopback // + ); + + // + double atrBandUpper = EMPTY_VALUE; + double atrBandLower = EMPTY_VALUE; + double atrBandMiddle = EMPTY_VALUE; + + // + isBullish = hasOrderFlow && + IsXBullish(dir); + + // + isBearish = hasOrderFlow && + IsXBearish(dir); + + // + // Summarize Result ... + result = isBullish || isBearish; + + // + // Force Price of p2Bar is Inside Order Flow ... + if (result && validateBarInsideZone) + { + // + double orderFlowUpper = 0; + double orderFlowLower = 0; + + // + int idx = -1; + idx = GetHighest(oFlow); + if (IsValidIndex(idx)) + { + orderFlowUpper = oFlow[idx].upper; + } + idx = GetLowest(oFlow); + if (IsValidIndex(idx)) + { + orderFlowLower = oFlow[idx].lower; + } + + // + result = NotEmptyZero(orderFlowUpper) && + NotEmptyZero(orderFlowLower) && + orderFlowUpper > orderFlowLower && + (isBullish + ? p2Bar.low < orderFlowUpper + : p2Bar.high > orderFlowLower); + + // + // Reset Flags ... + if (!result) + { + // + isBullish = false; + isBearish = false; + } + } + + // + // Force PBar Has Pattern ... + if (result && validateByBarPatterns) + { + // + // Analyse Bar Patterns ... + result = pBarPatterns.IsValid(); + + // + // Bullish ... + bool isPBarHasBullishPatterns = + result && + // (bar.close > pBar.low || + // bar.open > pBar.low) && + ( + // + pBarPatterns.IsPinned(X_DIRECTION_BULLISH) || + pBarPatterns.IsEngulfed(X_DIRECTION_BULLISH) || + pBarPatterns.IsMomentum(X_DIRECTION_BULLISH) || + pBarPatterns.IsPiercing(X_DIRECTION_BULLISH) || + pBarPatterns.IsSignalKey(X_DIRECTION_BULLISH) + // + ); + + // + // Bearish ... + bool isPBarHasBearishPatterns = + result && + // (bar.close < pBar.high || + // bar.open < pBar.high) && + ( + // + pBarPatterns.IsPinned(X_DIRECTION_BEARISH) || + pBarPatterns.IsEngulfed(X_DIRECTION_BEARISH) || + pBarPatterns.IsMomentum(X_DIRECTION_BEARISH) || + pBarPatterns.IsPiercing(X_DIRECTION_BEARISH) || + pBarPatterns.IsSignalKey(X_DIRECTION_BEARISH) + // + ); + + // + isBullish = + isBullish && + isPBarHasBullishPatterns && + !isPBarHasBearishPatterns; + + // + isBearish = + isBearish && + isPBarHasBearishPatterns && + !isPBarHasBullishPatterns; + + // + // Summarize Result ... + result = isBullish || isBearish; + + // + // Reset Flags ... + if (!result) + { + // + isBullish = false; + isBearish = false; + } + } + + // + // Force P2Bar Place Checking based on ATR Band ... + if (result && validateByBarInsideATRBand) + { + // + atrBandUpper = fimaHelper.GetATRBandUpper(p2Bar.Index()); + atrBandLower = fimaHelper.GetATRBandLower(p2Bar.Index()); + + // + atrBandMiddle = atrBandLower + ((atrBandUpper - atrBandLower) / 2); + + // + isBullish = + isBullish && + NotEmptyZero(atrBandMiddle) && + p2Bar.low < atrBandMiddle; + + // + isBearish = + isBearish && + NotEmptyZero(atrBandMiddle) && + p2Bar.high > atrBandMiddle; + + // + // Summarize Result ... + result = isBullish || isBearish; + + // + // Reset Flags ... + if (!result) + { + // + isBullish = false; + isBearish = false; + } + } + + // + // Force PBar Place Checking based on ATR Band ... + if (result && validateByBarBasedOnATRBand) + { + // + atrBandUpper = fimaHelper.GetATRBandUpper(pBar.Index()); + atrBandLower = fimaHelper.GetATRBandLower(pBar.Index()); + + // + result = + NotEmptyZero(atrBandUpper) && + NotEmptyZero(atrBandLower) && + (isBullish + ? pBar.close > atrBandLower + : pBar.close < atrBandUpper); + + // + // Reset Flags ... + if (!result) + { + // + isBullish = false; + isBearish = false; + } + } + + // + // for Bullish has Support ... + // for Bearish has Resistance ... + if (result && validateMarketStructureHasDirectionalZone) + { + // + XOHCL tmpBar; + XPivot tmpPivot; + XBoxZone support; + XBoxZone resistance; + + // + // Check Market Strucutre Has Support / Resistance ... + bool hasSupport = pBarPatterns.IsSupport(); + bool hasResistance = pBarPatterns.IsResistance(); + + // + // Retrieve Support / Resistance Zone ... + if (hasSupport) + { + pBarPatterns.GetSupport(tmpBar, tmpPivot, support); + } + if (hasResistance) + { + pBarPatterns.GetResistance(tmpBar, tmpPivot, resistance); + } + + // + // Validate Support and Resistance by Order Flow ... + + // + // Converts Order Flow to Zone ... + XBoxZone ofZone; + bool hasOFBox = ToBox(ofZone, oFlow); + + // + // Check Market Strucutre Support and Resistance Validation ... + if (validateMarketStructureDirectionalZoneInsideOrderFlow) + { + // + hasSupport = + hasOFBox && + hasSupport && + ofZone.lower < support.lower && + ofZone.upper > support.upper; + + // + hasResistance = + hasOFBox && + hasResistance && + ofZone.lower < resistance.lower && + ofZone.upper > resistance.upper; + } + + // + // Validate Directional Support or Resistance Exists ... + + // + isBullish = + isBullish && + hasSupport; + + // + isBearish = + isBearish && + hasResistance; + + // + // Cleanup ... + ofZone.Clean(); + tmpBar.Clean(); + support.Clean(); + tmpPivot.Clean(); + resistance.Clean(); + + // + // Summarize Result ... + result = isBullish || isBearish; + } + + // + // Validate Makret Structure Has Not Indirectional Zone ... + if (result && validateMarketStructureHasNotInDirectionalZoneOrUnReachedTP) + { + // + XOHCL tmpBar; + XPivot tmpPivot; + XBoxZone support; + XBoxZone resistance; + + // + // Check Market Strucutre Has Support / Resistance ... + bool hasSupport = pBarPatterns.IsSupport(); + bool hasResistance = pBarPatterns.IsResistance(); + + // + // Retrieve Support / Resistance Zone ... + if (hasSupport) + { + pBarPatterns.GetSupport(tmpBar, tmpPivot, support); + } + if (hasResistance) + { + pBarPatterns.GetResistance(tmpBar, tmpPivot, resistance); + } + + // + // Converts Order Flow to Zone ... + XBoxZone ofZone; + bool hasOFBox = ToBox(ofZone, oFlow); + + // + bool hasIndirectionalZone = + (isBullish && hasResistance) || + (isBearish && hasSupport); + if (hasIndirectionalZone) + { + // + // Here we Have to Validate Zone Place ... + + // + double point = GetPoints(bar.symbol); + double entry = GetEntry(bar.symbol, dir); + double slAddition = slAdditionDistance > 0 ? slAdditionDistance : 0; + double risk = MathAbs(entry - (isBullish ? oFlow[0].lower : oFlow[0].upper)) + (slAddition * point); + double reward = (defaultSignalR2R * risk); + double tp = isBullish + ? entry + reward + : entry - reward; + + // + // Bullish ... + if (isBullish && hasResistance) + { + hasResistance = resistance.lower <= tp; + } + + // + // Bearish ... + if (isBearish && hasSupport) + { + hasSupport = support.upper >= tp; + } + } + + // + isBullish = + isBullish && + !hasResistance; + + // + isBearish = + isBearish && + !hasSupport; + + // + // Cleanup ... + ofZone.Clean(); + tmpBar.Clean(); + support.Clean(); + tmpPivot.Clean(); + resistance.Clean(); + + // + // Summarize Result ... + result = isBullish || isBearish; + } + + // + // Validate ... + result = isBullish || + isBearish; + if (result) + { + // + dir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + result = HasDirection(dir); + } + + // + // Prepare Zone ... + if (result) + { + // + zone.Clean(); + result = ToBox( + p2Bar, + zone, + dir, + X_BAR_PATTERN_PINNED // + ); + + // + // Refine Zone ... + zone.to = bar.time; + zone.upper = MathMax(zone.upper, atrBandMiddle); + zone.lower = MathMin(zone.lower, atrBandMiddle); + + // + // Manage Stops ... + if (result) + { + // + // Since Stop Management Changes Zones Edge(s) ... + // we do it here for Refining Zone ... + + // + poiDrawer.DrawZone(zone, structureDrawConfig.drawConfig); + poiDrawer.DrawPatternAnalysis(pBarPatterns, structureDrawConfig.barAnalysisDrawConfig); + + // + DebugBreak(); + } + + // + result = zone.IsValid(); + } + + // + // Prepare Targets ... + if (result) + { + // + XTarget iTarget; + + // + // Calculate Requirements ... + double point = GetPoints(bar.symbol); + double entry = GetEntry(bar.symbol, dir); + double slAddition = slAdditionDistance > 0 ? slAdditionDistance : 0; + double risk = MathAbs(entry - (isBullish ? zone.lower : zone.upper)) + (slAddition * point); + double reward = (defaultSignalR2R * risk); + double tp = isBullish + ? entry + reward + : entry - reward; + + // + // High Risk Target is Used to Protect In Profit Positiions + // from Reversal Patterns ... + double highRiskR2r = (defaultSignalR2R / 5) * 4; + double highRiskReward = highRiskR2r * risk; + double highRiskTP = isBullish + ? entry + highRiskReward + : entry - highRiskReward; + iTarget.Clean(); + iTarget.actingDistance = 5; + iTarget.doRFOnEntry = true; + iTarget.target = highRiskTP; + iTarget.volumeMultiplier = 0.8; + AddRef(iTarget, targets); + + // + // Cleanup ... + iTarget.Clean(); + } + + // + // Cleanup ... + if (!result) + { + // + zone.Clean(); + XClean(targets); + dir = X_DIRECTION_NONE; + } + pBar.Clean(); + p2Bar.Clean(); + p3Bar.Clean(); + XClean(orderFlow); + pBarPatterns.Clean(); + + // + return result; + } + + // +}; + +// \ No newline at end of file diff --git a/Libraries/x-saherelm.x-poi.extensions.lib.mq5 b/Libraries/x-saherelm.x-poi.extensions.lib.mq5 index 0a93ceb1..c321ee15 100644 --- a/Libraries/x-saherelm.x-poi.extensions.lib.mq5 +++ b/Libraries/x-saherelm.x-poi.extensions.lib.mq5 @@ -4654,6 +4654,57 @@ bool ToBox( return result; } +/** + * Converts Order Flow to Zone ... + * + * @param zone: XBoxZone, reference to holds result ... + * @param orderFlow: XBoxZone, collection reference to provides order flow ... + * + * @return ( bool ) + */ +bool ToBox( + XBoxZone &zone, + XBoxZone &orderFlow[] // +) +{ + // + bool result = false; + + // + // Prepare ... + zone.Clean(); + + // + // Validate ... + result = HasChild(orderFlow); + if (!result) + { + return result; + } + + // + zone = orderFlow[0]; + int idx = GetHighest(orderFlow); + if (IsValidIndex(idx)) + { + zone.upper = orderFlow[idx].upper; + } + idx = GetLowest(orderFlow); + if (IsValidIndex(idx)) + { + zone.lower = orderFlow[idx].lower; + } + + // + zone.type = "XOrderFlowP"; + + // + result = zone.IsValid(); + + // + return result; +} + /** * Converts a Bar to OB Box ... * @@ -4993,7 +5044,10 @@ bool ToResistanceBox( * * @return ( int ) */ -int RemoveBreakedZones(XBoxZone &source[]) +int RemoveBreakedZones( + XBoxZone &source[], + bool forceBreak = false // +) { // int result = 0; @@ -5014,22 +5068,37 @@ int RemoveBreakedZones(XBoxZone &source[]) tmps // ); XClean(source); + XOHCL tmpBars[]; + int breakerBars = 0; while (HasChild(tmps)) { // iZone.Clean(); iZone = tmps[0]; ArrayRemove(tmps, 0, 1); - has = iZone.IsValid() && - !IsXValid(iZone.breakAt); + has = IsXValid(iZone.breakAt); if (has) { - // - AddIfNotExists( - iZone, - source // - ); + continue; } + + // + if (forceBreak) + { + // + breakerBars = GetBreakerBars(iZone, tmpBars); + has = IsValidSize(breakerBars); + } + if (has) + { + continue; + } + + // + AddIfNotExists( + iZone, + source // + ); } // @@ -5904,6 +5973,113 @@ int GetTesterBars( // return result; } + +bool IsBreaked( + XBoxZone &zone, + ENUM_X_PRICE priceType = X_PRICE_CLOSE // +) +{ + // + bool result = false; + + // + // Validate ... + result = zone.IsValid() && + IsXValid(priceType); + if (!result) + { + // + result = true; + return result; + } + + // + XOHCL iBar; + double iPrice; + bool isBullish; + int start = zone.ToIndex(); + int end = zone.FromIndex(); + for (int i = start; i < end; i++) + { + // + // Initialize Indexed Bar ... + iBar.Clean(); + result = iBar.Init(zone.symbol, zone.period, i); + if (!result) + { + // + result = true; + break; + } + + // + isBullish = zone.IsBullish(); + iPrice = iBar.GetPrice(priceType); + result = isBullish + ? iPrice < zone.lower + : iPrice > zone.upper; + if (result) + { + break; + } + } + + // + // Cleanup ... + iBar.Clean(); + + // + return result; +} + +int RemoveBreakedZones( + XBoxZone &source[], + ENUM_X_PRICE priceType = X_PRICE_CLOSE // +) +{ + // + int result = 0; + + // + // Validate ... + if (!HasChild(source) || !IsXValid(priceType)) + { + return result; + } + + // + XBoxZone tmp[]; + Copy(source, tmp); + XClean(source); + XBoxZone iTMP; + bool isBreaked = false; + while (HasChild(tmp)) + { + // + iTMP.Clean(); + iTMP = tmp[0]; + ArrayRemove(tmp, 0, 1); + + // + isBreaked = IsBreaked(iTMP, priceType); + if (!isBreaked) + { + // + AddIfNotExists(iTMP, source); + } + } + + // + result = ArraySize(source); + + // + // Cleanup ... + XClean(tmp); + iTMP.Clean(); + + // + return result; +} //+------------------------------------------------------------------+ // \ No newline at end of file diff --git a/XFIMAEA/Classes/x-saherelm.xfima.signaller.class.mq5 b/XFIMAEA/Classes/x-saherelm.xfima.signaller.class.mq5 index eed647c6..5d1c13bb 100644 --- a/XFIMAEA/Classes/x-saherelm.xfima.signaller.class.mq5 +++ b/XFIMAEA/Classes/x-saherelm.xfima.signaller.class.mq5 @@ -907,7 +907,10 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller // // Target Flags ... - bool hasPartialCloseOnTp1 = true; + bool hasPartialCloseOnTp1 = false; + + // + bool doRFOnEntryOnTP1 = false; // // Draw Flags ... @@ -918,6 +921,10 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller bool drawMarketStructureOrderFlow = true; XPOIDrawConfig iDrawConfig; + // + drawLeg = false; + drawOrderFlow = false; + // // Signal Checking ... @@ -927,15 +934,16 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller // // Check Market ... - result = HasLeg() && - HasOrderFlow() && - orderFlowDir == leg.dir; - if (result) - { - // - result = false; - DebugBreak(); - } + // result = HasLeg() && + // HasOrderFlow() && + // orderFlowDir == leg.dir; + // result = HasBearishOrderFlow(); + // if (result) + // { + // // + // result = false; + // DebugBreak(); + // } // // Signaller 1 ... @@ -1125,9 +1133,9 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller // iTarget.Clean(); iTarget.target = tp1; - iTarget.doRFOnEntry = true; iTarget.actingDistance = 5; iTarget.volumeMultiplier = 0.8; + iTarget.doRFOnEntry = doRFOnEntryOnTP1; // AddRef(iTarget, targets); @@ -2025,6 +2033,23 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller /** * Check Bar Has Signal Based on Strategy 4 ... * + * Strategy 4: + * =========== + * - Works Based on Order Flow ... + * - Looking for new and Fresh Order Flow ... + * - Validate Bar is Inside Order Flow ... + * - Validate Bar has Proper Pattern ... + * - Validate Bar Based on ATR Band in two Step: + * - Step 1: Bars is Inside ATR Band (Middle) ... + * - Step 2: Trigger Bars Close Price based on ATR Band ... + * - Validate Order Flow based on Market Structure Zone ... + * - Validate Trigger Bar based on InDirectional Market Structure Zones ... + * + * Manipulations: + * ================ + * there are Some Flags properties to Change Validations in Strategy ... + * we can use them for Testing Purposes ... + * * @param bar: XOHCL, reference to Bar ... * @param zone: XBoxZone, reference to holds affected zone ... * @param targets: XTarget, reference to detected Signal's Targets collections ... @@ -2062,6 +2087,9 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller bool validateByBarPatterns = true; bool validateByBarInsideATRBand = true; bool validateByBarBasedOnATRBand = true; + bool validateMarketStructureHasDirectionalZone = true; + bool validateMarketStructureDirectionalZoneInsideOrderFlow = true; + bool validateMarketStructureHasNotInDirectionalZoneOrUnReachedTP = true; // // Define Requirements ... @@ -2098,9 +2126,6 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller // Retrieve pBar Patterns ... XPatternAnalysis pBarPatterns; XPatternAnalysisConfig patternConfig = structureConfig.barsAnalysisConfig; - // patternConfig.Default(); - // patternConfig.supportAndResistanceLoopbackLength = 21; - // patternConfig.supportAndResistanceValidationLength = 7; // poiDetector.AnalyseBarPatterns( @@ -2111,7 +2136,19 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller // // Detecting OrderFlow ... - bool hasOrderFlow = HasOrderFlow(); + XBoxZone oFlow[]; + bool hasOrderFlow = poiDetector.HasOrderFlow( + p3Bar, + dir, + oFlow, + structureConfig.orderFlowValidation, + structureConfig.orderFlowUseOB, + structureConfig.orderFlowUseFVG, + structureConfig.orderFlowUseSupportAndResistance, + patternConfig.supportAndResistanceLoopbackLength, + patternConfig.supportAndResistanceValidationLength, + structureConfig.loopback // + ); // double atrBandUpper = EMPTY_VALUE; @@ -2139,15 +2176,16 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller double orderFlowLower = 0; // - int idx = GetHighest(orderFlow); + int idx = -1; + idx = GetHighest(oFlow); if (IsValidIndex(idx)) { - orderFlowUpper = orderFlow[idx].upper; + orderFlowUpper = oFlow[idx].upper; } - idx = GetLowest(orderFlow); + idx = GetLowest(oFlow); if (IsValidIndex(idx)) { - orderFlowLower = orderFlow[idx].lower; + orderFlowLower = oFlow[idx].lower; } // @@ -2179,6 +2217,7 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller // // Bullish ... bool isPBarHasBullishPatterns = + result && // (bar.close > pBar.low || // bar.open > pBar.low) && ( @@ -2194,6 +2233,7 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller // // Bearish ... bool isPBarHasBearishPatterns = + result && // (bar.close < pBar.high || // bar.open < pBar.high) && ( @@ -2296,46 +2336,171 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller } // - result = false; - isBullish = false; - isBearish = false; - if (result) + // for Bullish has Support ... + // for Bearish has Resistance ... + if (result && validateMarketStructureHasDirectionalZone) { - // // - // UpdateToTime(orderFlow, bar.time); - // poiDrawer.DrawZones(orderFlow, structureDrawConfig.drawConfig); - // poiDrawer.DrawPatternAnalysis(pBarPatterns, structureDrawConfig.barAnalysisDrawConfig); + // + XOHCL tmpBar; + XPivot tmpPivot; + XBoxZone support; + XBoxZone resistance; - // // - // // Draw ATR Band Middle ... - // if (NotEmptyZero(atrBandMiddle)) - // { - // // - // XPOIDrawConfig iConfig = structureDrawConfig.drawConfig; - // iConfig.trendRayLeft = false; - // iConfig.trendRayRight = false; + // + // Check Market Strucutre Has Support / Resistance ... + bool hasSupport = pBarPatterns.IsSupport(); + bool hasResistance = pBarPatterns.IsResistance(); - // // - // datetime to = bar.time; - // datetime from = p2Bar.BeforeOn(); - // string trendName = "ATRBandMiddle_" + ToXString(TimeToSeconds(p2Bar.time)); - // poiDrawer.DrawTrendLine( - // trendName, - // atrBandMiddle, - // from, - // atrBandMiddle, - // to, - // iConfig, - // clrYellow // - // ); + // + // Retrieve Support / Resistance Zone ... + if (hasSupport) + { + pBarPatterns.GetSupport(tmpBar, tmpPivot, support); + } + if (hasResistance) + { + pBarPatterns.GetResistance(tmpBar, tmpPivot, resistance); + } - // // - // iConfig.Clean(); - // } + // + // Validate Support and Resistance by Order Flow ... - // // - // Print("OrderFlow ..."); - // DebugBreak(); + // + // Converts Order Flow to Zone ... + XBoxZone ofZone; + bool hasOFBox = ToBox(ofZone, oFlow); + + // + // Check Market Strucutre Support and Resistance Validation ... + if (validateMarketStructureDirectionalZoneInsideOrderFlow) + { + // + hasSupport = + hasOFBox && + hasSupport && + ofZone.lower < support.lower && + ofZone.upper > support.upper; + + // + hasResistance = + hasOFBox && + hasResistance && + ofZone.lower < resistance.lower && + ofZone.upper > resistance.upper; + } + + // + // Validate Directional Support or Resistance Exists ... + + // + isBullish = + isBullish && + hasSupport; + + // + isBearish = + isBearish && + hasResistance; + + // + // Cleanup ... + ofZone.Clean(); + tmpBar.Clean(); + support.Clean(); + tmpPivot.Clean(); + resistance.Clean(); + + // + // Summarize Result ... + result = isBullish || isBearish; + } + + // + // Validate Makret Structure Has Not Indirectional Zone ... + if (result && validateMarketStructureHasNotInDirectionalZoneOrUnReachedTP) + { + // + XOHCL tmpBar; + XPivot tmpPivot; + XBoxZone support; + XBoxZone resistance; + + // + // Check Market Strucutre Has Support / Resistance ... + bool hasSupport = pBarPatterns.IsSupport(); + bool hasResistance = pBarPatterns.IsResistance(); + + // + // Retrieve Support / Resistance Zone ... + if (hasSupport) + { + pBarPatterns.GetSupport(tmpBar, tmpPivot, support); + } + if (hasResistance) + { + pBarPatterns.GetResistance(tmpBar, tmpPivot, resistance); + } + + // + // Converts Order Flow to Zone ... + XBoxZone ofZone; + bool hasOFBox = ToBox(ofZone, oFlow); + + // + bool hasIndirectionalZone = + (isBullish && hasResistance) || + (isBearish && hasSupport); + if (hasIndirectionalZone) + { + // + // Here we Have to Validate Zone Place ... + + // + double point = GetPoints(bar.symbol); + double entry = GetEntry(bar.symbol, dir); + double slAddition = slAdditionDistance > 0 ? slAdditionDistance : 0; + double risk = MathAbs(entry - (isBullish ? oFlow[0].lower : oFlow[0].upper)) + (slAddition * point); + double reward = (defaultSignalR2R * risk); + double tp = isBullish + ? entry + reward + : entry - reward; + + // + // Bullish ... + if (isBullish && hasResistance) + { + hasResistance = resistance.lower <= tp; + } + + // + // Bearish ... + if (isBearish && hasSupport) + { + hasSupport = support.upper >= tp; + } + } + + // + isBullish = + isBullish && + !hasResistance; + + // + isBearish = + isBearish && + !hasSupport; + + // + // Cleanup ... + ofZone.Clean(); + tmpBar.Clean(); + support.Clean(); + tmpPivot.Clean(); + resistance.Clean(); + + // + // Summarize Result ... + result = isBullish || isBearish; } // @@ -2377,6 +2542,16 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller // Manage Stops ... if (result) { + // + // Since Stop Management Changes Zones Edge(s) ... + // we do it here for Refining Zone ... + + // + poiDrawer.DrawZone(zone, structureDrawConfig.drawConfig); + poiDrawer.DrawPatternAnalysis(pBarPatterns, structureDrawConfig.barAnalysisDrawConfig); + + // + DebugBreak(); } // @@ -2387,6 +2562,38 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller // Prepare Targets ... if (result) { + // + XTarget iTarget; + + // + // Calculate Requirements ... + double point = GetPoints(bar.symbol); + double entry = GetEntry(bar.symbol, dir); + double slAddition = slAdditionDistance > 0 ? slAdditionDistance : 0; + double risk = MathAbs(entry - (isBullish ? zone.lower : zone.upper)) + (slAddition * point); + double reward = (defaultSignalR2R * risk); + double tp = isBullish + ? entry + reward + : entry - reward; + + // + // High Risk Target is Used to Protect In Profit Positiions + // from Reversal Patterns ... + double highRiskR2r = (defaultSignalR2R / 5) * 4; + double highRiskReward = highRiskR2r * risk; + double highRiskTP = isBullish + ? entry + highRiskReward + : entry - highRiskReward; + iTarget.Clean(); + iTarget.actingDistance = 5; + iTarget.doRFOnEntry = true; + iTarget.target = highRiskTP; + iTarget.volumeMultiplier = 0.8; + AddRef(iTarget, targets); + + // + // Cleanup ... + iTarget.Clean(); } //