/////////////////////////////////////////////////////// // // 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 = true; bool useSignaller2 = false; bool useSignaller3 = false; bool useSignaller4 = false; bool useSignaller5 = false; bool useSignaller6 = false; bool useSignaller7 = false; // 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; } // // 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); // // Check KI Slow Trend ... bool kiSlowBullish = kiParser.IsKISlowBullish(barIndex); bool kiSlowBearish = kiParser.IsKISlowBearish(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()) { // 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 // #region ATR Volatility Check ... // // Check Volatility Expansion ... bool volatilityHigh = kiParser.IsVolatilityHigh(barIndex); bool volatilitySwitchedHigh = kiParser.IsVolatilitySwitchdToHigh(barIndex); // // 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[]; // 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++) { // double obRange = (bullishOBs[i].upper - bullishOBs[i].lower) / points; if (obRange >= minOBPoints && !IsXValid(bullishOBs[i].breakAt)) { AddIfNotExists(bullishOBs[i], validBullishOBs); } } // // 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; XBoxZone swingLow; // poiDetector.DetectRecentSwings(swingHigh, swingLow, barIndex, 50, 500, period, true); // // Check if Liquidity was Swept ... bool liquiditySweptHigh = false; bool liquiditySweptLow = false; // if (swingHigh.IsValid()) { liquiditySweptHigh = bar.high > swingHigh.upper; } // if (swingLow.IsValid()) { liquiditySweptLow = bar.low < swingLow.lower; } // #endregion // #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; } // // HTF bias more important if (kiSuperSlowBullish) { bullishScore += 2; } 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) { isBearish = false; } else if (bearishScore > bullishScore) { isBullish = false; } else { // Same score, no signal ... isBullish = false; isBearish = false; } } // // Generate Bullish Signal ... if (isBullish) { // dir = X_DIRECTION_BULLISH; // // Select Best POI (Youngest Valid OB or FVG) ... XBoxZone selectedPOI; // int obIdx = GetYoungest(validBullishOBs); int fvgIdx = GetYoungest(validBullishFVGs); // if (IsValidIndex(obIdx) && IsValidIndex(fvgIdx)) { // // Choose the one closer to current price ... double obDistance = bar.close - validBullishOBs[obIdx].upper; double fvgDistance = bar.close - validBullishFVGs[fvgIdx].upper; // selectedPOI = (obDistance < fvgDistance) ? validBullishOBs[obIdx] : validBullishFVGs[fvgIdx]; } else if (IsValidIndex(obIdx)) { selectedPOI = validBullishOBs[obIdx]; } else if (IsValidIndex(fvgIdx)) { selectedPOI = validBullishFVGs[fvgIdx]; } // // Validate Selected POI ... if (selectedPOI.IsValid()) { // zone = selectedPOI; zone.type = "S1_POI_KI"; // // Calculate Targets ... double entry = GetEntry(symbol, dir); double risk = MathAbs(entry - zone.lower); 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 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); } } } // // 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) { // 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 ... XClean(bullishOBs); XClean(bearishOBs); XClean(bullishFVGs); XClean(bearishFVGs); XClean(validBullishOBs); XClean(validBearishOBs); XClean(validBullishFVGs); XClean(validBearishFVGs); // 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 // }; //