diff --git a/X121XKIEA/Backup/x-saherelm.x121.xki.signaller.class.mq5 b/X121XKIEA/Backup/x-saherelm.x121.xki.signaller.class.mq5 new file mode 100644 index 00000000..703df08a --- /dev/null +++ b/X121XKIEA/Backup/x-saherelm.x121.xki.signaller.class.mq5 @@ -0,0 +1,1878 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class +// ------------------------------------------------- +// Name: XCX121XKISignaller ... +// Description: X121XKI 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 X121XKI Signaller Class" +#property strict + +// +// Imports ... +#include "../../Classes/x-saherelm.x-signaller.class.mq5" +#include "../../Helpers/x-saherelm.x121.xki.helper.mq5" +#include "../Classes/x-saherelm.x121.xki.parser.class.mq5" +#include "../Classes/x-saherelm.x121.xki.x-poi.detector.class.mq5" +#include "../Classes/x-saherelm.x121.xki.x-poi.drawer.class.mq5" +#include "../Libraries/x-saherelm.x121.xki.lib.mq5" + +// +// Implementation ... + +// +// Base X121XKI base Signaller ... +class XCX121XKIBaseSignaller : public XCBaseSignaller +{ + // + // Public ... + public: + // + // Props ... + + // + CArrayObj drawnObjects; // Drawing Objects Holder ... + X121XKIInputs kiInputs; // X121XKI Inputs ... + XCX121XKIHelper *kiHelper; // X121XKI Indicator Helper ... + XCX121XKIPOIDrawer *poiDrawer; // X121XKI POI Drawer ... + XCX121XKIPOIDetector *poiDetector; // X121XKI POI Detector ... + XCX121XKIHelperParser *kiParser; // X121XKI Helper Parser ... + + // + // Constructor ... + XCX121XKIBaseSignaller( + string _name, // Name ... + string _symbol, // Symbol ... + ENUM_TIMEFRAMES _period, // Period ... + X121XKIInputs &_kiInputs, // X121XKIInputs ... + 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 X121XKI Indicator Helper Class ... + if (_kiInputs.IsValid()) + { + // + kiHelper = new XCX121XKIHelper(); + bool isInited = kiHelper.Init( + _symbol, + _period, + _kiInputs // + ); + if (isInited) + { + kiInputs = _kiInputs; + } + else + { + // + delete kiHelper; + ZeroMemory(kiHelper); + } + } + + // + // Instantiate X121XKI Helper Parser ... + kiParser = new XCX121XKIHelperParser(kiHelper); + + // + poiDrawer = new XCX121XKIPOIDrawer(); + poiDetector = new XCX121XKIPOIDetector(kiHelper, kiParser); + } + + // + // Deconstructor ... + ~XCX121XKIBaseSignaller() + { + Destroy(); + } + + // + // Overrides ... + + // + // Actions ... + + /** + * Destroy ... + */ + void Destroy() + { + // + BeforeDestroy(); + + // + kiInputs.Clean(); + + // + delete poiDrawer; + ZeroMemory(poiDrawer); + + // + delete poiDetector; + ZeroMemory(poiDetector); + + // + delete kiHelper; + ZeroMemory(kiHelper); + } + + // + // 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 = kiInputs.IsValid() && + kiHelper != 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: + // +}; + +// +// X121XKI Strategy 1 Signaller Class ... +class XCX121XKIStrategy1Signaller : public XCX121XKIBaseSignaller +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructor ... + XCX121XKIStrategy1Signaller( + string _symbol, // Symbol ... + ENUM_TIMEFRAMES _period, // Period ... + X121XKIInputs &_kiInputs, // X121XKIInputs ... + 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 ... + ) : XCX121XKIBaseSignaller("X121XKI1", + _symbol, + _period, + _kiInputs, + _processAllTicks, + _defaultSignalR2R, + _defaultSignalRiskInPoint, + _defaultSignalVolume // + ) + { + } + + // + // Deconstructor ... + ~XCX121XKIStrategy1Signaller() + { + // + 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; + } + + // + // 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 .... + ); + if (has) + { + iSignal.provider += "_" + iZone.type; + } + } + + // + // 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); + return result; + + // + int positionsCount = ArraySize(positions); + if (!IsValidSize(positionsCount)) + { + return result; + } + + // + // Requirements ... + XGuard iGuard; + bool has = false; + int samePeaks = 0; + int sameVales = 0; + double iValue = 0; + double points10 = 0; + double points50 = 0; + double points100 = 0; + string provider = NULL; + int samePVValidation = 5; + bool isPeakOverLast = false; + bool isValeUnderLast = false; + + // + for (int i = 0; i < positionsCount; i++) + { + // + points10 = 10 * positions[i].GetPointsValue(); + points50 = 50 * positions[i].GetPointsValue(); + points100 = 100 * positions[i].GetPointsValue(); + + // + // Check Provided By Strategy 1 ... + provider = positions[i].provider; + StringReplace( + provider, + name, + "" // + ); + has = Contains(ToXString(X121_XKI_STRATEGY_1), positions[i].provider); + if (has) + { + // + // Now we Check Exit ... + // if (positions[i].IsLong()) + // { + // has = ExitBullishPOILong(); + // } + // else if (positions[i].IsShort()) + // { + // has = ExitBearishPOIShort(); + // } + + // // + // if (has) + // { + // } + } + } + + // + result = ArraySize(guards); + + // + // Cleanup ... + iGuard.Clean(); + + // + return result; + } + + // + // Protected ... + protected: + // + + // + // Private ... + private: + // + // Props ... + + // + // 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 = false; + bool useSignaller5 = false; + bool useSignaller6 = false; + bool useSignaller7 = true; + + // + XBoxZone tmpZone; + string provider = NULL; + ENUM_X_DIRECTION tmpDir; + + // + bool signaller1HasSignal = false; + bool signaller2HasSignal = false; + bool signaller3HasSignal = false; + bool signaller4HasSignal = false; + bool signaller5HasSignal = false; + bool signaller6HasSignal = false; + bool signaller7HasSignal = false; + + // + // Validator Flags ... + bool validateByOrderFlow = false; + + // + // Target Flags ... + bool hasPartialCloseOnTp1 = false; + + // + bool doRFOnEntryOnTP1 = false; + + // + // Draw Flags ... + bool draw = true; + + // + // Signal Checking ... + + // + // Signal Detection Flags ... + + // + // Signaller 1 ... + // POI ... + if (useSignaller1) + { + // + signaller1HasSignal = Strategy1HasSignal( + bar, + tmpZone, + targets, + tmpDir // + ); + + // + if (signaller1HasSignal) + { + // + provider += ToXString(X121_XKI_STRATEGY_1); + + // + if (!zone.IsValid()) + { + // + dir = tmpDir; + zone = tmpZone; + } + } + + // + tmpZone.Clean(); + tmpDir = X_DIRECTION_NONE; + } + + // + // Signaller 2 ... + // Breakout POI ... + if (useSignaller2) + { + // + signaller2HasSignal = Strategy2HasSignal( + bar, + tmpZone, + targets, + tmpDir // + ); + + // + if (signaller2HasSignal) + { + // + provider += ToXString(X121_XKI_STRATEGY_2); + + // + if (!zone.IsValid()) + { + // + dir = tmpDir; + zone = tmpZone; + } + } + + // + tmpZone.Clean(); + tmpDir = X_DIRECTION_NONE; + } + + // + // Signaller 3 ... + // Reversal ... + if (useSignaller3) + { + // + signaller3HasSignal = Strategy3HasSignal( + bar, + tmpZone, + targets, + tmpDir // + ); + + // + if (signaller3HasSignal) + { + // + provider += ToXString(X121_XKI_STRATEGY_3); + + // + if (!zone.IsValid()) + { + // + dir = tmpDir; + zone = tmpZone; + } + } + + // + tmpZone.Clean(); + tmpDir = X_DIRECTION_NONE; + } + + // + // Signaller 4 ... + // Continuation ... + if (useSignaller4) + { + // + signaller4HasSignal = Strategy4HasSignal( + bar, + tmpZone, + targets, + tmpDir // + ); + + // + if (signaller4HasSignal) + { + // + provider += ToXString(X121_XKI_STRATEGY_4); + + // + if (!zone.IsValid()) + { + // + dir = tmpDir; + zone = tmpZone; + } + } + + // + tmpZone.Clean(); + tmpDir = X_DIRECTION_NONE; + } + + // + // Signaller 5 ... + // Exhaustion ... + if (useSignaller5) + { + // + signaller5HasSignal = Strategy5HasSignal( + bar, + tmpZone, + targets, + tmpDir // + ); + + // + if (signaller5HasSignal) + { + // + provider += ToXString(X121_XKI_STRATEGY_5); + + // + if (!zone.IsValid()) + { + // + dir = tmpDir; + zone = tmpZone; + } + } + + // + tmpZone.Clean(); + tmpDir = X_DIRECTION_NONE; + } + + // + // Signaller 6 ... + // Trend Exhaustion ... + if (useSignaller6) + { + // + signaller6HasSignal = Strategy6HasSignal( + bar, + tmpZone, + targets, + tmpDir // + ); + + // + if (signaller6HasSignal) + { + // + provider += ToXString(X121_XKI_STRATEGY_6); + + // + if (!zone.IsValid()) + { + // + dir = tmpDir; + zone = tmpZone; + } + } + + // + tmpZone.Clean(); + tmpDir = X_DIRECTION_NONE; + } + + // + // Signaller 7 ... + // Supply and Demand ... + if (useSignaller7) + { + // + signaller7HasSignal = Strategy7HasSignal( + bar, + tmpZone, + targets, + tmpDir // + ); + + // + if (signaller7HasSignal) + { + // + provider += ToXString(X121_XKI_STRATEGY_7); + + // + if (!zone.IsValid()) + { + // + dir = tmpDir; + zone = tmpZone; + } + } + + // + tmpZone.Clean(); + tmpDir = X_DIRECTION_NONE; + } + + // + // Summarize Signallers Result ... + result = signaller1HasSignal || + signaller2HasSignal || + signaller3HasSignal || + signaller4HasSignal || + signaller5HasSignal || + signaller6HasSignal || + signaller7HasSignal; + + // + // Signal Validating ... + + // + // 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); + if (result) + { + zone.type = "" + provider; + } + + // + // Cleanup ... + iTarget.Clean(); + } + + // + // Draws ... + if (result && draw) + { + // + // Other Drawing Materials ... + XPOIDrawConfig drawConfig; + drawConfig.Default(); + + // + poiDrawer.DrawZone(zone, drawConfig); + } + + // + // Cleanup ... + if (!result) + { + // + zone.Clean(); + XClean(targets); + dir = X_DIRECTION_NONE; + } + + // + // Cleanup ... + tmpZone.Clean(); + + // + return result; + } + + // #region Custom Signal Strategies ... + //+------------------------------------------------------------------+ + //| X121XKI Strategy 1: POI + KI Confluence | + //| Concept: Order Block/FVG + KI Trend Confirmation | + //+------------------------------------------------------------------+ + + /** + * Check Bar Has Signal Based on Strategy 1 ... + * POI + KI Confluence ... + * + * @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; + + // + zone.Clean(); + XClean(targets); + dir = X_DIRECTION_NONE; + + // + result = bar.IsValid() && + kiParser.IsValid(); + if (!result) + { + return result; + } + + // + double score = 0; + bool isBullish = false; + bool isBearish = false; + int barIndex = bar.Index() + 1; + + // + // TEST ... + + // + if (kiParser.IsKIFastBullish(barIndex)) + { + DebugBreak(); + } + + // // + // bool hasTrend = + // kiParser.HasCompositeTrend( + // score, + // dir, + // barIndex, + // 20, // Required Score ... + // 2, // Tolerance ... + // X_PRICE_CLOSE, + // 55, + // 45, + // 70, + // 30 // + // ); + // if (hasTrend && IsXBearish(dir)) + // { + // DebugBreak(); + // } + + // + return false; + + // + // Initialize Indexed Bar ... + XOHCL iBar; + result = iBar.Init(bar.symbol, bar.period, barIndex); + if (!result) + { + return result; + } + + // + XBoxZone swingLow; + XBoxZone swingHigh; + ENUM_X_DIRECTION patternsDir[]; + ENUM_X_BAR_PATTERN patterns[]; + poiDetector.FillStrategy1Patterns( + patterns, + patternsDir // + ); + + // + // Reading Swings ... + poiDetector.DetectRecentSwings( + swingHigh, + swingLow, + barIndex // + ); + + // + // Reading Order Flow ... + + // + // Bullish Order Flow ... + XBoxZone bullishOrderFlow[]; + int bullishOrderFlowRejectdIDX = -1; + poiDetector.HasOrderFlow(bullishOrderFlow, barIndex, 4, X_DIRECTION_BULLISH, 15); + + // + // Bearish Order Flow ... + XBoxZone bearishOrderFlow[]; + int bearishOrderFlowRejectdIDX = -1; + poiDetector.HasOrderFlow(bearishOrderFlow, barIndex, 4, X_DIRECTION_BEARISH, 15); + + // + // Base Conditions ... + + // + isBullish = + IsTFBullishPattern(barIndex, PERIOD_M1) && + IsTFBullishPattern(barIndex, PERIOD_M5) && + IsTFBullishPattern(barIndex, iBar.period) && + HasRejected( + bullishOrderFlowRejectdIDX, + iBar, + bullishOrderFlow // + ) && + poiDetector.HasRecentPatternRejected( + zone, + patterns, + patternsDir, + barIndex, + 3, // Loopback .. + iBar.period, + X_DIRECTION_BULLISH // + ); + if (!isBullish) + { + // + isBearish = + IsTFBearishPattern(barIndex, PERIOD_M1) && + IsTFBearishPattern(barIndex, PERIOD_M5) && + IsTFBearishPattern(barIndex, iBar.period) && + HasRejected( + bearishOrderFlowRejectdIDX, + iBar, + bearishOrderFlow // + ) && + poiDetector.HasRecentPatternRejected( + zone, + patterns, + patternsDir, + barIndex, + 3, // Loopback .. + iBar.period, + X_DIRECTION_BEARISH // + ); + } + + // + // Summarize Result ... + result = isBullish || isBearish; + + // + // Count Touches ... + // int bullishTouches = 0; + // int bearishTouches = 0; + // if (result) + // { + // // + // kiParser.CountTouches( + // bullishTouches, + // bearishTouches, + // barIndex, + // 4 // Loopback ... + // ); + + // // + // isBullish = + // isBullish && + // bullishTouches >= bearishTouches; + + // // + // isBearish = + // isBearish && + // bearishTouches >= bullishTouches; + + // // + // // Summarize Result ... + // result = isBullish || isBearish; + // if (!result) + // { + // // + // isBullish = false; + // isBearish = false; + // } + + // // + // if (bullishTouches > 0 || bearishTouches > 0) + // { + // // DebugBreak(); + // } + // } + + // + if (!result) + { + // + iBar.Clean(); + + // + return result; + } + + // + // Do Directional Validation ... + if (result) + { + // + poiDetector.RefactorStrategy1OperationalZone(zone); + + // + // Bullish ... + if (isBullish) + { + // // + // isBullish = + // isBullish && + // isLowerTFBullish && + // isCandlestickBullish; + } + + // + // Bearish ... + if (isBearish) + { + // // + // isBearish = + // isBearish && + // isLowerTFBearish && + // isCandlestickBearish; + } + + // + result = isBullish || isBearish; + if (!result) + { + // + isBullish = false; + isBearish = false; + } + } + + // + // Draws ... + bool draw = true; + if (draw && result) + { + // + int drawn = 0; + + // + poiDrawer.drawnObjects.Clear(); + + // + XPOIDrawConfig config; + config.Default(); + + // + if (zone.IsValid()) + { + // + drawn++; + + // + config.zonesWidth = 3; + config.bullishColor = clrYellow; + config.bearishColor = clrOrange; + + // + poiDrawer.DrawZone(zone, config); + + // + config.Default(); + } + + // + if (swingLow.IsValid()) + { + // + drawn++; + poiDrawer.DrawZone(swingLow, config); + } + + // + if (swingHigh.IsValid()) + { + // + drawn++; + poiDrawer.DrawZone(swingHigh, config); + } + + // + if (HasChild(bullishOrderFlow)) + { + // + drawn += ArraySize(bullishOrderFlow); + poiDrawer.DrawZones(bullishOrderFlow, config); + } + + // + if (HasChild(bearishOrderFlow)) + { + // + drawn += ArraySize(bearishOrderFlow); + poiDrawer.DrawZones(bearishOrderFlow, config); + } + + // + if (drawn > 0) + { + DebugBreak(); + return false; + } + + // + config.Clean(); + } + + // + // Check and Prepare Direction ... + dir = + isBullish + ? X_DIRECTION_BULLISH + : isBearish ? X_DIRECTION_BEARISH + : X_DIRECTION_NONE; + result = result && + HasDirection(dir); + if (result) + { + // + // Prepare Zone ... + double entry = GetEntry(iBar.symbol, dir); + + // + double upper = isBullish + ? entry + : zone.upper; + double lower = isBullish + ? zone.lower + : entry; + datetime to = bar.time; + datetime from = isBullish + ? zone.from + : zone.from; + result = zone.Init( + iBar.symbol, + iBar.period, + upper, + lower, + from, + to, + dir, + "XS1" // + ); + } + + // + // Cleanup Resources ... + iBar.Clean(); + swingLow.Clean(); + XClean(patterns); + swingHigh.Clean(); + XClean(patternsDir); + XClean(bullishOrderFlow); + XClean(bearishOrderFlow); + + // + result = + result && + zone.IsValid() && + HasDirection(dir); + + // + return result; + } + + /** + * Check Bar Has Signal Based on Strategy 2 ... + * Breakout POI ... + * + * @return ( bool ) + */ + bool Strategy2HasSignal( + XOHCL &bar, + XBoxZone &zone, + XTarget &targets[], + ENUM_X_DIRECTION &dir // + ) + { + // + bool result = false; + + // + zone.Clean(); + XClean(targets); + dir = X_DIRECTION_NONE; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int barIndex = bar.Index() + 1; + + // + // Retrieve Base Conditions ... + bool isBullish = false; + bool isBearish = false; + + // + // Validate Conditions ... + result = isBullish || isBearish; + if (!result) + { + return result; + } + + // + // Do Validation and Filtering Market Structure if required ... + + // + // Check and Prepare Direction ... + dir = + isBullish + ? X_DIRECTION_BULLISH + : isBearish ? X_DIRECTION_BEARISH + : X_DIRECTION_NONE; + result = HasDirection(dir); + if (!result) + { + return result; + } + + // + // Prepare Zone ... + + // + result = + result && + zone.IsValid() && + HasDirection(dir); + + // + return result; + } + + /** + * Check Bar Has Signal Based on Strategy 3 ... + * Reversal ... + * + * @return ( bool ) + */ + bool Strategy3HasSignal( + XOHCL &bar, + XBoxZone &zone, + XTarget &targets[], + ENUM_X_DIRECTION &dir // + ) + { + // + bool result = false; + + // + zone.Clean(); + XClean(targets); + dir = X_DIRECTION_NONE; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int barIndex = bar.Index() + 1; + + // + // Retrieve Base Conditions ... + bool isBullish = false; + bool isBearish = false; + + // + // Validate Conditions ... + result = isBullish || isBearish; + if (!result) + { + return result; + } + + // + // Do Validation and Filtering Market Structure if required ... + + // + // Check and Prepare Direction ... + dir = + isBullish + ? X_DIRECTION_BULLISH + : isBearish ? X_DIRECTION_BEARISH + : X_DIRECTION_NONE; + result = HasDirection(dir); + if (!result) + { + return result; + } + + // + // Prepare Zone ... + + // + result = + result && + zone.IsValid() && + HasDirection(dir); + + // + return result; + } + + /** + * Check Bar Has Signal Based on Strategy 4 ... + * Continuation ... + * + * @return ( bool ) + */ + bool Strategy4HasSignal( + XOHCL &bar, + XBoxZone &zone, + XTarget &targets[], + ENUM_X_DIRECTION &dir // + ) + { + // + bool result = false; + + // + zone.Clean(); + XClean(targets); + dir = X_DIRECTION_NONE; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int barIndex = bar.Index() + 1; + + // + // Retrieve Base Conditions ... + bool isBullish = false; + bool isBearish = false; + + // + // Validate Conditions ... + result = isBullish || isBearish; + if (!result) + { + return result; + } + + // + // Do Validation and Filtering Market Structure if required ... + + // + // Check and Prepare Direction ... + dir = + isBullish + ? X_DIRECTION_BULLISH + : isBearish ? X_DIRECTION_BEARISH + : X_DIRECTION_NONE; + result = HasDirection(dir); + if (!result) + { + return result; + } + + // + // Prepare Zone ... + + // + result = + result && + zone.IsValid() && + HasDirection(dir); + + // + return result; + } + + /** + * Check Bar Has Signal Based on Strategy 5 ... + * Exhaustion ... + * + * @return ( bool ) + */ + bool Strategy5HasSignal( + XOHCL &bar, + XBoxZone &zone, + XTarget &targets[], + ENUM_X_DIRECTION &dir // + ) + { + // + bool result = false; + + // + zone.Clean(); + XClean(targets); + dir = X_DIRECTION_NONE; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int barIndex = bar.Index() + 1; + + // + // Retrieve Base Conditions ... + bool isBullish = false; + bool isBearish = false; + + // + // Validate Conditions ... + result = isBullish || isBearish; + if (!result) + { + return result; + } + + // + // Do Validation and Filtering Market Structure if required ... + + // + // Check and Prepare Direction ... + dir = + isBullish + ? X_DIRECTION_BULLISH + : isBearish ? X_DIRECTION_BEARISH + : X_DIRECTION_NONE; + result = HasDirection(dir); + if (!result) + { + return result; + } + + // + // Prepare Zone ... + + // + result = + result && + zone.IsValid() && + HasDirection(dir); + + // + return result; + } + + /** + * Check Bar Has Signal Based on Strategy 6 ... + * Trend Exhaustion ... + * + * @return ( bool ) + */ + bool Strategy6HasSignal( + XOHCL &bar, + XBoxZone &zone, + XTarget &targets[], + ENUM_X_DIRECTION &dir // + ) + { + // + bool result = false; + + // + zone.Clean(); + XClean(targets); + dir = X_DIRECTION_NONE; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int barIndex = bar.Index() + 1; + + // + // Retrieve Base Conditions ... + bool isBullish = false; + bool isBearish = false; + + // + // Validate Conditions ... + result = isBullish || isBearish; + if (!result) + { + return result; + } + + // + // Do Validation and Filtering Market Structure if required ... + + // + // Check and Prepare Direction ... + dir = + isBullish + ? X_DIRECTION_BULLISH + : isBearish ? X_DIRECTION_BEARISH + : X_DIRECTION_NONE; + result = HasDirection(dir); + if (!result) + { + return result; + } + + // + // Prepare Zone ... + + // + result = + result && + zone.IsValid() && + HasDirection(dir); + + // + return result; + } + + /** + * Check Bar Has Signal Based on Strategy 7 ... + * ُSupply and Demand ... + * + * @return ( bool ) + */ + bool Strategy7HasSignal( + XOHCL &bar, + XBoxZone &zone, + XTarget &targets[], + ENUM_X_DIRECTION &dir // + ) + { + // + bool result = false; + + // + zone.Clean(); + XClean(targets); + dir = X_DIRECTION_NONE; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + int barIndex = bar.Index() + 1; + + // + // Retrieve Base Conditions ... + bool isBullish = false; + bool isBearish = false; + + // + XBoxZone demandZones[]; + int demandZonesCount = poiDetector.DetectDemands( + demandZones, + barIndex, + bar.symbol, + bar.period, + 100, + 4, + 1, + 15 // + ); + + // + // Validate Conditions ... + result = isBullish || isBearish; + if (!result) + { + return result; + } + + // + // Do Validation and Filtering Market Structure if required ... + + // + // Check and Prepare Direction ... + dir = + isBullish + ? X_DIRECTION_BULLISH + : isBearish ? X_DIRECTION_BEARISH + : X_DIRECTION_NONE; + result = HasDirection(dir); + if (!result) + { + return result; + } + + // + // Prepare Zone ... + + // + result = + result && + zone.IsValid() && + HasDirection(dir); + + // + return result; + } + // #endregion + + // #region TF Patterns ... + bool IsTFBullishPattern( + int barIndex = 0, + ENUM_TIMEFRAMES forPeriod = NULL // + ) + { + // + bool result = false; + + // + // Normalize ... + barIndex = kiParser.NormalizeBarIndex(barIndex); + if (!IsXValid(forPeriod)) + { + forPeriod = period; + } + + // + XOHCL bar; + result = bar.Init(symbol, forPeriod, barIndex) && + poiDetector.HasCandlestickDirection(bar, X_DIRECTION_BULLISH); + bar.Clean(); + + // + return result; + } + + bool IsTFBearishPattern( + int barIndex = 0, + ENUM_TIMEFRAMES forPeriod = NULL // + ) + { + // + bool result = false; + + // + // Normalize ... + barIndex = kiParser.NormalizeBarIndex(barIndex); + if (!IsXValid(forPeriod)) + { + forPeriod = period; + } + + // + XOHCL bar; + result = bar.Init(symbol, forPeriod, barIndex) && + poiDetector.HasCandlestickDirection(bar, X_DIRECTION_BEARISH); + bar.Clean(); + + // + return result; + } + // #endregion + + // +}; + +// \ No newline at end of file diff --git a/X121XKIEA/Classes/x-saherelm.x121.xki.signaller.class.mq5 b/X121XKIEA/Classes/x-saherelm.x121.xki.signaller.class.mq5 index f44bb53c..6c25840e 100644 --- a/X121XKIEA/Classes/x-saherelm.x121.xki.signaller.class.mq5 +++ b/X121XKIEA/Classes/x-saherelm.x121.xki.signaller.class.mq5 @@ -533,13 +533,13 @@ class XCX121XKIStrategy1Signaller : public XCX121XKIBaseSignaller // // Signaller Flags ... - bool useSignaller1 = false; + bool useSignaller1 = true; bool useSignaller2 = false; bool useSignaller3 = false; bool useSignaller4 = false; bool useSignaller5 = false; bool useSignaller6 = false; - bool useSignaller7 = true; + bool useSignaller7 = false; // XBoxZone tmpZone; @@ -975,9 +975,14 @@ class XCX121XKIStrategy1Signaller : public XCX121XKIBaseSignaller } // #region Custom Signal Strategies ... + //+------------------------------------------------------------------+ + //| X121XKI Strategy 1: POI + KI Confluence | + //| Concept: Order Block/FVG + KI Trend Confirmation | + //+------------------------------------------------------------------+ + /** * Check Bar Has Signal Based on Strategy 1 ... - * POI ... + * POI + KI Confluence ... * * @param bar: XOHCL, reference to Bar ... * @param zone: XBoxZone, reference to holds affected zone ... @@ -1002,359 +1007,669 @@ class XCX121XKIStrategy1Signaller : public XCX121XKIBaseSignaller dir = X_DIRECTION_NONE; // - result = bar.IsValid(); + result = bar.IsValid() && + kiParser.IsValid(); if (!result) { return result; } // + // Configuration ... double score = 0; bool isBullish = false; bool isBearish = false; int barIndex = bar.Index() + 1; + double points = GetPoints(symbol); + int minOBPoints = 30; // Minimum Order Block size in points + int minFVGPoints = 20; // Minimum FVG size in points + double minScore = 15.0; // Minimum score for signal + int kiConfirmationBars = 3; // Bars for KI confirmation + + // #region KI Trend Confirmation ... + // + // Check KI Fast Trend ... + bool kiFastBullish = kiParser.IsKIFastBullish(barIndex); + bool kiFastBearish = kiParser.IsKIFastBearish(barIndex); // - // TEST ... + // Check KI Slow Trend ... + bool kiSlowBullish = kiParser.IsKISlowBullish(barIndex); + bool kiSlowBearish = kiParser.IsKISlowBearish(barIndex); // - if (kiParser.IsKIFastBullish(barIndex)) + // Check KI Super Slow Trend ... + bool kiSuperSlowBullish = kiParser.IsKISlowBullish(barIndex); + bool kiSuperSlowBearish = kiParser.IsKISlowBearish(barIndex); + + // + bool kiWaveBullish = kiParser.IsKIWaveSwitchedToBullish(barIndex); + bool kiWaveBearish = kiParser.IsKIWaveSwitchedToBearish(barIndex); + + // + bool priceAboveKIFast = bar.close > kiHelper.GetKIFast(barIndex); + bool priceBelowKIFast = bar.close < kiHelper.GetKIFast(barIndex); + // #endregion + + // #region RSI Momentum Confirmation ... + // + // Check RSI State ... + bool rsiBullish = kiParser.IsRSISwitchedToBullish(barIndex, 55, 2); + bool rsiBearish = kiParser.IsRSISwitchedToBearish(barIndex, 45, 2); + + // + // Check RSI Overbought/Oversold ... + bool rsiOverbought = kiParser.IsRSIOverbought(barIndex, 70, 2); + bool rsiOversold = kiParser.IsRSIOversold(barIndex, 30, 2); + + // + // Check RSI Divergence (Price vs RSI) ... + bool rsiBullishDivergence = false; + bool rsiBearishDivergence = false; + + // + // Simple Divergence Check (can be enhanced) ... + if (barIndex + 5 < bar.TotalBars()) { - DebugBreak(); + // + double currentRSI = kiHelper.GetRSI(barIndex); + double previousRSI = kiHelper.GetRSI(barIndex + 5); + double currentLow = bar.low; + double previousLow = bar.FindLowest(5, MODE_LOW); + double currentHigh = bar.high; + double previousHigh = bar.FindHighest(5, MODE_HIGH); + + // + // Bullish Divergence ... + rsiBullishDivergence = (currentLow < previousLow) && (currentRSI > previousRSI); + + // + // Bearish Divergence ... + rsiBearishDivergence = (currentHigh > previousHigh) && (currentRSI < previousRSI); } + // #endregion - // // - // bool hasTrend = - // kiParser.HasCompositeTrend( - // score, - // dir, - // barIndex, - // 20, // Required Score ... - // 2, // Tolerance ... - // X_PRICE_CLOSE, - // 55, - // 45, - // 70, - // 30 // - // ); - // if (hasTrend && IsXBearish(dir)) - // { - // DebugBreak(); - // } + // #region ATR Volatility Check ... + // + // Check Volatility Expansion ... + bool volatilityHigh = kiParser.IsVolatilityHigh(barIndex); + bool volatilitySwitchedHigh = kiParser.IsVolatilitySwitchdToHigh(barIndex); // - return false; + // Check ATR Breakout ... + bool atrBreakoutUp = kiParser.IsATRBreakoutUp(barIndex, X_PRICE_CLOSE); + bool atrBreakoutDown = kiParser.IsATRBreakoutDown(barIndex, X_PRICE_CLOSE); + // #endregion + + // #region POI Detection (Order Blocks & FVG) ... + // + // Detect Order Blocks ... + XBoxZone bullishOBs[]; + XBoxZone bearishOBs[]; // - // Initialize Indexed Bar ... - XOHCL iBar; - result = iBar.Init(bar.symbol, bar.period, barIndex); - if (!result) + int bullishOBCount = poiDetector.CollectOBs(bar, bullishOBs, 5, 10, 100); + int bearishOBCount = poiDetector.CollectOBs(bar, bearishOBs, 5, 10, 100); + + // + // Detect Fair Value Gaps ... + XBoxZone bullishFVGs[]; + XBoxZone bearishFVGs[]; + + // + int bullishFVGCount = poiDetector.CollectFVGs(bar, bullishFVGs, 5, 10, 100); + int bearishFVGCount = poiDetector.CollectFVGs(bar, bearishFVGs, 5, 10, 100); + + // + // Validate OB/FVG Size ... + XBoxZone validBullishOBs[]; + XBoxZone validBearishOBs[]; + XBoxZone validBullishFVGs[]; + XBoxZone validBearishFVGs[]; + + // + // Filter Bullish OBs ... + for (int i = 0; i < bullishOBCount; i++) { - return result; + // + double obRange = (bullishOBs[i].upper - bullishOBs[i].lower) / points; + if (obRange >= minOBPoints && !IsXValid(bullishOBs[i].breakAt)) + { + AddIfNotExists(bullishOBs[i], validBullishOBs); + } } // - XBoxZone swingLow; + // Filter Bearish OBs ... + for (int i = 0; i < bearishOBCount; i++) + { + // + double obRange = (bearishOBs[i].upper - bearishOBs[i].lower) / points; + if (obRange >= minOBPoints && !IsXValid(bearishOBs[i].breakAt)) + { + AddIfNotExists(bearishOBs[i], validBearishOBs); + } + } + + // + // Filter Bullish FVGs ... + for (int i = 0; i < bullishFVGCount; i++) + { + // + double fvgRange = (bullishFVGs[i].upper - bullishFVGs[i].lower) / points; + if (fvgRange >= minFVGPoints && !IsXValid(bullishFVGs[i].breakAt)) + { + AddIfNotExists(bullishFVGs[i], validBullishFVGs); + } + } + + // + // Filter Bearish FVGs ... + for (int i = 0; i < bearishFVGCount; i++) + { + // + double fvgRange = (bearishFVGs[i].upper - bearishFVGs[i].lower) / points; + if (fvgRange >= minFVGPoints && !IsXValid(bearishFVGs[i].breakAt)) + { + AddIfNotExists(bearishFVGs[i], validBearishFVGs); + } + } + // #endregion + + // #region Liquidity Check ... + // + // Detect Recent Swings (Liquidity Pools) ... XBoxZone swingHigh; - ENUM_X_DIRECTION patternsDir[]; - ENUM_X_BAR_PATTERN patterns[]; - poiDetector.FillStrategy1Patterns( - patterns, - patternsDir // - ); + XBoxZone swingLow; // - // Reading Swings ... - poiDetector.DetectRecentSwings( - swingHigh, - swingLow, - barIndex // - ); + poiDetector.DetectRecentSwings(swingHigh, swingLow, barIndex, 50, 500, period, true); // - // Reading Order Flow ... + // Check if Liquidity was Swept ... + bool liquiditySweptHigh = false; + bool liquiditySweptLow = false; // - // Bullish Order Flow ... - XBoxZone bullishOrderFlow[]; - int bullishOrderFlowRejectdIDX = -1; - poiDetector.HasOrderFlow(bullishOrderFlow, barIndex, 4, X_DIRECTION_BULLISH, 15); - - // - // Bearish Order Flow ... - XBoxZone bearishOrderFlow[]; - int bearishOrderFlowRejectdIDX = -1; - poiDetector.HasOrderFlow(bearishOrderFlow, barIndex, 4, X_DIRECTION_BEARISH, 15); - - // - // Base Conditions ... - - // - isBullish = - IsTFBullishPattern(barIndex, PERIOD_M1) && - IsTFBullishPattern(barIndex, PERIOD_M5) && - IsTFBullishPattern(barIndex, iBar.period) && - HasRejected( - bullishOrderFlowRejectdIDX, - iBar, - bullishOrderFlow // - ) && - poiDetector.HasRecentPatternRejected( - zone, - patterns, - patternsDir, - barIndex, - 3, // Loopback .. - iBar.period, - X_DIRECTION_BULLISH // - ); - if (!isBullish) + if (swingHigh.IsValid()) { - // - isBearish = - IsTFBearishPattern(barIndex, PERIOD_M1) && - IsTFBearishPattern(barIndex, PERIOD_M5) && - IsTFBearishPattern(barIndex, iBar.period) && - HasRejected( - bearishOrderFlowRejectdIDX, - iBar, - bearishOrderFlow // - ) && - poiDetector.HasRecentPatternRejected( - zone, - patterns, - patternsDir, - barIndex, - 3, // Loopback .. - iBar.period, - X_DIRECTION_BEARISH // - ); + liquiditySweptHigh = bar.high > swingHigh.upper; } // - // Summarize Result ... - result = isBullish || isBearish; - - // - // Count Touches ... - // int bullishTouches = 0; - // int bearishTouches = 0; - // if (result) - // { - // // - // kiParser.CountTouches( - // bullishTouches, - // bearishTouches, - // barIndex, - // 4 // Loopback ... - // ); - - // // - // isBullish = - // isBullish && - // bullishTouches >= bearishTouches; - - // // - // isBearish = - // isBearish && - // bearishTouches >= bullishTouches; - - // // - // // Summarize Result ... - // result = isBullish || isBearish; - // if (!result) - // { - // // - // isBullish = false; - // isBearish = false; - // } - - // // - // if (bullishTouches > 0 || bearishTouches > 0) - // { - // // DebugBreak(); - // } - // } - - // - if (!result) + if (swingLow.IsValid()) { - // - iBar.Clean(); + liquiditySweptLow = bar.low < swingLow.lower; + } + // #endregion - // - return result; + // #region Multi-Timeframe Confirmation ... + // + // Check Lower Timeframe Alignment ... + bool isLowerTFBullish = IsTFBullishPattern(barIndex, PERIOD_M1); + bool isLowerTFBearish = IsTFBearishPattern(barIndex, PERIOD_M1); + + // + // Check Higher Timeframe Alignment ... + bool isHigherTFBullish = IsTFBullishPattern(barIndex, GetNearestPeriod(period)); + bool isHigherTFBearish = IsTFBearishPattern(barIndex, GetNearestPeriod(period)); + // #endregion + + // + // + // + + // #region Bullish Signal Logic ... + // + // Calculate Bullish Score ... + double bullishScore = 0; + + // + // KI Trend Alignment (Max 5 points) ... + if (kiFastBullish) + { + bullishScore += 1; + } + + if (kiSlowBullish) + { + bullishScore += 1; } // - // Do Directional Validation ... - if (result) + // HTF bias more important + if (kiSuperSlowBullish) { - // - poiDetector.RefactorStrategy1OperationalZone(zone); + bullishScore += 2; + } - // - // Bullish ... - if (isBullish) + if (priceAboveKIFast) + { + bullishScore += 1; + } + + // + // KI Wave Momentum (Max 2 points) ... + if (kiWaveBullish) + { + bullishScore += 2; + } + + // + // RSI Confirmation (Max 3 points) ... + if (rsiBullish) + { + bullishScore += 2; + } + + // + // Divergence is strong signal ... + if (rsiBullishDivergence) + { + bullishScore += 3; + } + + if (rsiOversold) + { + bullishScore += 1; + } + + // + // Volatility (Max 2 points) ... + if (volatilityHigh) + { + bullishScore += 1; + } + + if (volatilitySwitchedHigh) + { + bullishScore += 1; + } + + // + // POI Presence (Max 5 points) ... + if (ArraySize(validBullishOBs) > 0) + { + bullishScore += 3; + } + + if (ArraySize(validBullishFVGs) > 0) + { + bullishScore += 2; + } + + // + // Liquidity Sweep (Max 3 points) ... + if (liquiditySweptLow) + { + bullishScore += 3; + } + + // + // MTF Alignment (Max 2 points) ... + if (isLowerTFBullish) + { + bullishScore += 1; + } + + if (isHigherTFBullish) + { + bullishScore += 1; + } + + // + // Check Bullish Conditions ... + isBullish = (bullishScore >= minScore) && + (ArraySize(validBullishOBs) > 0 || + ArraySize(validBullishFVGs) > 0) && + (kiFastBullish || kiWaveBullish); + // #endregion + + // #region Bearish Signal Logic ... + // + // Calculate Bearish Score ... + double bearishScore = 0; + + // + // KI Trend Alignment (Max 5 points) ... + if (kiFastBearish) + { + bearishScore += 1; + } + + if (kiSlowBearish) + { + bearishScore += 1; + } + + if (kiSuperSlowBearish) + { + bearishScore += 2; + } + + if (priceBelowKIFast) + { + bearishScore += 1; + } + + // + // KI Wave Momentum (Max 2 points) ... + if (kiWaveBearish) + { + bearishScore += 2; + } + + // + // RSI Confirmation (Max 3 points) ... + if (rsiBearish) + { + bearishScore += 2; + } + + if (rsiBearishDivergence) + { + bearishScore += 3; + } + + if (rsiOverbought) + { + bearishScore += 1; + } + + // + // Volatility (Max 2 points) ... + if (volatilityHigh) + { + bearishScore += 1; + } + + if (volatilitySwitchedHigh) + { + bearishScore += 1; + } + + // + // POI Presence (Max 5 points) ... + if (ArraySize(validBearishOBs) > 0) + { + bearishScore += 3; + } + + if (ArraySize(validBearishFVGs) > 0) + { + bearishScore += 2; + } + + // + // Liquidity Sweep (Max 3 points) ... + if (liquiditySweptHigh) + { + bearishScore += 3; + } + + // + // MTF Alignment (Max 2 points) ... + if (isLowerTFBearish) + { + bearishScore += 1; + } + + if (isHigherTFBearish) + { + bearishScore += 1; + } + + // + // Check Bearish Conditions ... + isBearish = (bearishScore >= minScore) && + (ArraySize(validBearishOBs) > 0 || + ArraySize(validBearishFVGs) > 0) && + (kiFastBearish || kiWaveBearish); + // #endregion + + // #region Signal Generation ... + // + // Ensure Only One Direction ... + if (isBullish && isBearish) + { + // Use higher score to determine direction ... + if (bullishScore > bearishScore) { - // // - // isBullish = - // isBullish && - // isLowerTFBullish && - // isCandlestickBullish; + isBearish = false; } - - // - // Bearish ... - if (isBearish) + else if (bearishScore > bullishScore) { - // // - // isBearish = - // isBearish && - // isLowerTFBearish && - // isCandlestickBearish; + isBullish = false; } - - // - result = isBullish || isBearish; - if (!result) + else { - // + // Same score, no signal ... isBullish = false; isBearish = false; } } // - // Draws ... - bool draw = true; - if (draw && result) + // Generate Bullish Signal ... + if (isBullish) { // - int drawn = 0; + dir = X_DIRECTION_BULLISH; // - poiDrawer.drawnObjects.Clear(); + // Select Best POI (Youngest Valid OB or FVG) ... + XBoxZone selectedPOI; // - XPOIDrawConfig config; - config.Default(); + int obIdx = GetYoungest(validBullishOBs); + int fvgIdx = GetYoungest(validBullishFVGs); // - if (zone.IsValid()) + if (IsValidIndex(obIdx) && IsValidIndex(fvgIdx)) { // - drawn++; + // Choose the one closer to current price ... + double obDistance = bar.close - validBullishOBs[obIdx].upper; + double fvgDistance = bar.close - validBullishFVGs[fvgIdx].upper; // - config.zonesWidth = 3; - config.bullishColor = clrYellow; - config.bearishColor = clrOrange; - - // - poiDrawer.DrawZone(zone, config); - - // - config.Default(); + selectedPOI = (obDistance < fvgDistance) ? validBullishOBs[obIdx] : validBullishFVGs[fvgIdx]; + } + else if (IsValidIndex(obIdx)) + { + selectedPOI = validBullishOBs[obIdx]; + } + else if (IsValidIndex(fvgIdx)) + { + selectedPOI = validBullishFVGs[fvgIdx]; } // - if (swingLow.IsValid()) + // Validate Selected POI ... + if (selectedPOI.IsValid()) { // - drawn++; - poiDrawer.DrawZone(swingLow, config); - } + zone = selectedPOI; + zone.type = "S1_POI_KI"; - // - if (swingHigh.IsValid()) - { // - drawn++; - poiDrawer.DrawZone(swingHigh, config); - } + // Calculate Targets ... + double entry = GetEntry(symbol, dir); + double risk = MathAbs(entry - zone.lower); + double reward = risk * defaultSignalR2R; - // - if (HasChild(bullishOrderFlow)) - { // - drawn += ArraySize(bullishOrderFlow); - poiDrawer.DrawZones(bullishOrderFlow, config); - } + // TP1: 1:1 R:R ... + XTarget tp1; + tp1.target = entry + risk; + tp1.volumeMultiplier = 0.5; + tp1.doRF = true; + tp1.doRFOnEntry = false; + AddRef(tp1, targets); - // - if (HasChild(bearishOrderFlow)) - { // - drawn += ArraySize(bearishOrderFlow); - poiDrawer.DrawZones(bearishOrderFlow, config); - } + // TP2: 1:2 R:R ... + XTarget tp2; + tp2.target = entry + (risk * 2); + tp2.volumeMultiplier = 0.5; + tp2.doRF = false; + tp2.doRFOnEntry = false; + AddRef(tp2, targets); - // - if (drawn > 0) - { - DebugBreak(); - return false; + // + // TP3: Next Liquidity (Swing High) ... + if (swingHigh.IsValid()) + { + // + XTarget tp3; + tp3.target = swingHigh.upper + (10 * points); + tp3.volumeMultiplier = 1.0; + tp3.doRF = false; + tp3.doRFOnEntry = false; + AddRef(tp3, targets); + } } - - // - config.Clean(); } // - // Check and Prepare Direction ... - dir = - isBullish - ? X_DIRECTION_BULLISH - : isBearish ? X_DIRECTION_BEARISH - : X_DIRECTION_NONE; - result = result && - HasDirection(dir); + // Generate Bearish Signal ... + else if (isBearish) + { + // + dir = X_DIRECTION_BEARISH; + + // + // Select Best POI (Youngest Valid OB or FVG) ... + XBoxZone selectedPOI; + + // + int obIdx = GetYoungest(validBearishOBs); + int fvgIdx = GetYoungest(validBearishFVGs); + + // + if (IsValidIndex(obIdx) && IsValidIndex(fvgIdx)) + { + // + // Choose the one closer to current price ... + double obDistance = zone.lower - bar.close; + double fvgDistance = zone.lower - bar.close; + + // + selectedPOI = (obDistance < fvgDistance) ? validBearishOBs[obIdx] : validBearishFVGs[fvgIdx]; + } + else if (IsValidIndex(obIdx)) + { + selectedPOI = validBearishOBs[obIdx]; + } + else if (IsValidIndex(fvgIdx)) + { + selectedPOI = validBearishFVGs[fvgIdx]; + } + + // + // Validate Selected POI ... + if (selectedPOI.IsValid()) + { + // + zone = selectedPOI; + zone.type = "S1_POI_KI"; + + // + // Calculate Targets ... + double entry = GetEntry(symbol, dir); + double risk = MathAbs(zone.upper - entry); + double reward = risk * defaultSignalR2R; + + // + // TP1: 1:1 R:R ... + XTarget tp1; + tp1.target = entry - risk; + tp1.volumeMultiplier = 0.5; + tp1.doRF = true; + tp1.doRFOnEntry = false; + AddRef(tp1, targets); + + // + // TP2: 1:2 R:R ... + XTarget tp2; + tp2.target = entry - (risk * 2); + tp2.volumeMultiplier = 0.5; + tp2.doRF = false; + tp2.doRFOnEntry = false; + AddRef(tp2, targets); + + // + // TP3: Next Liquidity (Swing Low) ... + if (swingLow.IsValid()) + { + // + XTarget tp3; + tp3.target = swingLow.lower - (10 * points); + tp3.volumeMultiplier = 1.0; + tp3.doRF = false; + tp3.doRFOnEntry = false; + AddRef(tp3, targets); + } + } + } + // #endregion + + // #region Validation & Risk Management ... + // + // Validate Signal ... + result = zone.IsValid() && HasDirection(dir) && HasChild(targets); + + // + // Check Max Allowed Risk ... + if (result && maxAllowedRiskDistance > 0) + { + // + double riskInPoints = 0; + if (dir == X_DIRECTION_BULLISH) + { + riskInPoints = MathAbs(zone.GetDirectionalPrice() - zone.GetInDirectionalPrice()) / points; + } + else + { + riskInPoints = MathAbs(zone.GetInDirectionalPrice() - zone.GetDirectionalPrice()) / points; + } + + // + if (riskInPoints > maxAllowedRiskDistance) + { + // + result = false; + zone.Clean(); + XClean(targets); + dir = X_DIRECTION_NONE; + } + } + // #endregion + + // + // Optional: Debug Break for Testing ... if (result) { // - // Prepare Zone ... - double entry = GetEntry(iBar.symbol, dir); - - // - double upper = isBullish - ? entry - : zone.upper; - double lower = isBullish - ? zone.lower - : entry; - datetime to = bar.time; - datetime from = isBullish - ? zone.from - : zone.from; - result = zone.Init( - iBar.symbol, - iBar.period, - upper, - lower, - from, - to, - dir, - "XS1" // - ); + Print("Strategy 1 Signal Detected:"); + Print(" Direction: ", ToXString(dir)); + Print(" Bullish Score: ", bullishScore); + Print(" Bearish Score: ", bearishScore); + Print(" POI Type: ", zone.type); + Print(" Targets Count: ", ArraySize(targets)); + DebugBreak(); } // // Cleanup Resources ... - iBar.Clean(); - swingLow.Clean(); - XClean(patterns); - swingHigh.Clean(); - XClean(patternsDir); - XClean(bullishOrderFlow); - XClean(bearishOrderFlow); - - // - result = - result && - zone.IsValid() && - HasDirection(dir); + XClean(bullishOBs); + XClean(bearishOBs); + XClean(bullishFVGs); + XClean(bearishFVGs); + XClean(validBullishOBs); + XClean(validBearishOBs); + XClean(validBullishFVGs); + XClean(validBearishFVGs); // return result;