From 2f0efd02854e8fe1c039dd8bbd973fced866c506 Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Mon, 2 Jun 2025 03:41:33 +0330 Subject: [PATCH] last ... --- XCATBEA/Classes/xcatbea.signaller.class.mq5 | 561 +++++++++++++++++--- XCATBEA/Libraries/xcatbea.lib.mq5 | 340 ++++++++++++ XCATBEA/Libraries/xcatbea.signaller.lib.mq5 | 58 +- 3 files changed, 883 insertions(+), 76 deletions(-) diff --git a/XCATBEA/Classes/xcatbea.signaller.class.mq5 b/XCATBEA/Classes/xcatbea.signaller.class.mq5 index 623d6a8f..56ccb6e9 100644 --- a/XCATBEA/Classes/xcatbea.signaller.class.mq5 +++ b/XCATBEA/Classes/xcatbea.signaller.class.mq5 @@ -110,6 +110,12 @@ class XCXCATBEASignaller : XCBase // // Props ... + // + // Signalling Methods ... + bool allowSignallingBasedOnConditions; // Signalling and Entry based on Market Conditions ... + bool allowSignallingBasedOnTriggerBlocks; // Signalling Based on Trigger Block Detection ... + bool allowSignallingBasedOnTriggerBlocksInsideOther; // Signalling based on Trigger Blocks inside other Trigger Blocks ... + // bool allowDraws; // Allow Draws or not ... bool allowGuards; // Allow Guards or not ... @@ -126,7 +132,12 @@ class XCXCATBEASignaller : XCBase XTriggerBlockValidationRules validations; // Trigger Block Validations ... // - XBoxZone unavailableZones[]; // Un Available Zones ... + XBoxZone cPeak; // Current Peak ... + XBoxZone cVale; // Current Vale ... + XBoxZone unavailableZones[]; // Un Available Zones ... + XTriggerBlock cTriggerBlock; // Currently Selected Trigger Block ... + XTriggerBlock triggerBlocks[]; // Founded Trigger Blocks ... + XTriggerBlock cInsideTriggerBlock; // a TriggerBlock which Currently Selected Trigger Block is Inside it ... // XCATBEAStrategyConditions mConditions; @@ -195,6 +206,8 @@ class XCXCATBEASignaller : XCBase int count = 0; bool has = false; int barIndex = 0; + cTriggerBlock.Clean(); + cInsideTriggerBlock.Clean(); // // Check Guards ... @@ -320,6 +333,42 @@ class XCXCATBEASignaller : XCBase drawer.Draw(bar.time); } + // + // Detect Trigger Blocks and Collect them ... + XTriggerBlock iTriggerBlock; + X121XCatbConditions iConditions; + has = DetectTriggerBlock( + helper, + barAnalyser, + iTriggerBlock, + iConditions, + validations, + filters, + barIndex, + 10 // Loopback ... + ); + if (has) + { + // + // Add Trigger Block to Collection if not Exists ... + AddIfNotExists( + iTriggerBlock, + triggerBlocks // + ); + } + iConditions.Clean(); + iTriggerBlock.Clean(); + + // + // Draw Trigger Blocks ... + if (allowDraws) + { + // + // Handle To Updating ... + // datetime cTime = TimeCurrent(); + // DrawTriggerBlocks(cTime); + } + // // Here we Check Active Session ... // and Prevent Moving forward if there is not @@ -372,93 +421,274 @@ class XCXCATBEASignaller : XCBase helper.Update(barIndex); // - // Trigger Block Detection ... - result = DetectTriggerBlock( - helper, - barAnalyser, - mConditions.triggerBlock, - mConditions.conditions, - validations, - filters, - barIndex, - 10 // Loopback ... - ); - if (result) + // Detect Signal Setup Based on Market Conditions ... + if (!result && + allowSignallingBasedOnConditions) { // - // Prepare Condition ... - - // - // Prepare Signal ... - mConditions.dir = - mConditions - .triggerBlock - .GetDirection(); - mConditions.symbol = symbol; - mConditions.period = period; - mConditions.provider = provider; - mConditions.reward = riskToRewardRatio; - mConditions.time = mConditions.conditions.bars[0].time; - mConditions.setupTime = mConditions.conditions.bars[0].time; - - // - // Prepare Target ... - double targets[]; - for (int i = 1; i <= riskToRewardRatio; i++) - { - // - Add( - (double)i, - targets // - ); - } - - // - // Calculate SL Additions ... - double iATR = 0; - if (barIndex > 0 && - barIndex < ArraySize(helper.atrBuffer)) - { - iATR = helper.atrBuffer[barIndex]; - } - double slAdditional = slATRMultiplier * iATR; - - // - // Preparing Signal ... - result = ToSignal( - mConditions.triggerBlock.trigger, - mConditions.triggerBlock.signal, - targets, - slAdditional // + // Detect Signalling Zone ... + result = DetectSignalZone( + helper, + barAnalyser, + mConditions.conditions, + mConditions.pivotZone, + barIndex, + 10 // Loopback ... ); if (result) { // - mConditions.triggerBlock.signal.provider = provider; - mConditions.sl = mConditions.triggerBlock.signal.sl; - mConditions.tp = mConditions.triggerBlock.signal.tp; - mConditions.pivot = mConditions.triggerBlock.signal.sl; - mConditions.entry = mConditions.triggerBlock.signal.entry; - mConditions.point = mConditions.triggerBlock.signal.entry; - mConditions.type = ToPositionType(mConditions.triggerBlock.signal.type); + // Filling Conditions of Strategy ... + } + } + + // + // Detect Signal Setup Based on Trigger Block Detection ... + if (!result && + allowSignallingBasedOnTriggerBlocks) + { + // + // Detect Trigger Block ... + result = DetectTriggerBlock( + helper, + barAnalyser, + mConditions.triggerBlock, + mConditions.conditions, + validations, + filters, + barIndex, + 10 // Loopback ... + ); + if (result) + { + // + // Use Trigger Block ... + UseTriggerBlock(mConditions.triggerBlock); // - // Draw Trigger Block ... - if (allowDraws) + // Prepare Condition ... + + // + // Prepare Signal ... + mConditions.dir = + mConditions + .triggerBlock + .GetDirection(); + mConditions.symbol = symbol; + mConditions.period = period; + mConditions.provider = provider; + mConditions.reward = riskToRewardRatio; + mConditions.time = mConditions.conditions.bars[0].time; + mConditions.setupTime = mConditions.conditions.bars[0].time; + + // + // Prepare Target ... + double targets[]; + for (int i = 1; i <= riskToRewardRatio; i++) { // - DrawTriggerBlock( - mConditions.triggerBlock, - drawer.drawer, - mObjects, - NULL, // To ... - false // Draw Signal ... + Add( + (double)i, + targets // ); } + + // + // Calculate SL Additions ... + double iATR = 0; + if (barIndex > 0 && + barIndex < ArraySize(helper.atrBuffer)) + { + iATR = helper.atrBuffer[barIndex]; + } + double slAdditional = slATRMultiplier * iATR; + + // + // Preparing Signal ... + result = ToSignal( + mConditions.triggerBlock.trigger, + mConditions.triggerBlock.signal, + targets, + slAdditional // + ); + if (result) + { + // + mConditions.triggerBlock.signal.provider = provider; + mConditions.sl = mConditions.triggerBlock.signal.sl; + mConditions.tp = mConditions.triggerBlock.signal.tp; + mConditions.pivot = mConditions.triggerBlock.signal.sl; + mConditions.entry = mConditions.triggerBlock.signal.entry; + mConditions.point = mConditions.triggerBlock.signal.entry; + mConditions.type = ToPositionType(mConditions.triggerBlock.signal.type); + + // + // Draw Trigger Block ... + if (allowDraws) + { + // + DrawTriggerBlock( + mConditions.triggerBlock, + drawer.drawer, + mObjects, + NULL, // To ... + false // Draw Signal ... + ); + } + } } } // + // Detect Signal Setup Based On Trigger Blocks Second Entry ... + if (!result && + allowSignallingBasedOnTriggerBlocksInsideOther) + { + // + // First We Hvae to Select Peak and Vale ... + + // + // Check Peak and Vale Exists ... + int peakIDX = GetYoungest(detector.peakPivots); + int valeIDX = GetYoungest(detector.valePivots); + result = IsValidIndex(peakIDX) && + IsValidIndex(valeIDX); + if (result) + { + // + cPeak = detector.peakPivots[peakIDX]; + cVale = detector.valePivots[valeIDX]; + + // + // Trigger Block Detection ... + result = HasChild(triggerBlocks) && + ArraySize(triggerBlocks) > 1; + if (result) + { + // + // Check Newest Trigger Block ... + int newestIDX = GetYoungest(triggerBlocks); + result = IsValidIndex(newestIDX); + if (result) + { + // + cTriggerBlock = triggerBlocks[newestIDX]; + + // + // Check Trigger Block is New ... + int toIDX = cTriggerBlock.ToIndex() == 0; + bool isNewest = toIDX == 0; + if (isNewest) + { + // + // Now we have to Check Newest Trigger Block Place ... + int insideTBIDX = DetectInsideTriggerBlock( + cTriggerBlock, + cInsideTriggerBlock, + triggerBlocks // + ); + + // + // Check InsideTB is Exists and Valid ... + result = + cInsideTriggerBlock.IsValid() && + IsValidIndex(insideTBIDX); + if (result) + { + // + // Remove Peak from Detector Collections ... + // and Make it unavailable ... + ArrayRemove( + detector.peakPivots, + peakIDX, + 1 // + ); + AddRef( + cPeak, + unavailableZones // + ); + + // + // Remove Vale from Detector Collections ... + // and Make it unavailable ... + ArrayRemove( + detector.peakPivots, + peakIDX, + 1 // + ); + AddRef( + cVale, + unavailableZones // + ); + + // + // Remove Selected Trigger Block ... + // and Make it unavailable ... + RemoveTriggerBlock( + cTriggerBlock, + triggerBlocks // + ); + UseTriggerBlock(cTriggerBlock); + + // + // Remove Selected Inside Trigger Block ... + // and Make it unavailable ... + RemoveTriggerBlock( + cInsideTriggerBlock, + triggerBlocks // + ); + UseTriggerBlock(cInsideTriggerBlock); + + // + CleanupArray( + unavailableZones, + maxAllowedCollection // + ); + + // + // Draw Trigger Blocks if Allowed ... + if (allowDraws) + { + // + // + // Draw Blocks ... + datetime cTime = TimeCurrent(); + + // + // mObjects.Clear(); + + // + // Detected Block ... + DrawTriggerBlock( + cTriggerBlock, + drawer.drawer, + mObjects, + cTime, + false // Draw Signal ... + ); + + // + // Inside Block ... + DrawTriggerBlock( + cInsideTriggerBlock, + drawer.drawer, + mObjects, + cTime, + false // Draw Signal ... + ); + } + + // + Print("Salam ..."); + } + } + } + } + } + } + + // + // Check a Signal Setup Exists or not ... result = mConditions.IsValid() && mConditions.IsSetuped(); @@ -617,6 +847,14 @@ class XCXCATBEASignaller : XCBase */ void Init(XCATBEASignallerInputs &inputs) { + // + maxAllowedCollection = 50; + + // + allowSignallingBasedOnConditions = false; + allowSignallingBasedOnTriggerBlocks = true; + allowSignallingBasedOnTriggerBlocksInsideOther = false; + // bool has = inputs.IsValid(); if (!has) @@ -714,12 +952,16 @@ class XCXCATBEASignaller : XCBase * @return ( int ) */ int AddConditionsIfNotExists( - int maxAllowed = 10 // + int maxAllowed = 50 // ) { // int result = 0; + // + // Normalize Args ... + maxAllowed = maxAllowedCollection; + // bool isSetuped = IsValid(mConditions.setupTime) && HasDirection(mConditions.dir); @@ -788,6 +1030,178 @@ class XCXCATBEASignaller : XCBase return result; } + /** + * Add TriggerBlock if not Exists + * inside a Collection ... + */ + int AddIfNotExists( + XTriggerBlock &tb, + XTriggerBlock &tbs[], + int maxAllowed = 50 // + ) + { + // + int result = 0; + + // + // Normalize Args ... + maxAllowed = maxAllowedCollection; + + // + // First Validate ... + if (!tb.IsValid()) + { + return result; + } + + // + // Check Exists ... + // and prevent moving forward if exists ... + int idx = -1; + bool isExists = FindTriggerBlockIndex( + idx, + tb, + tbs // + ); + result = !isExists; + if (!result) + { + return result; + } + + // + // Add if not Exists ... + AddRef( + tb, + tbs // + ); + + // + // Cleanup ... + CleanupArray( + tbs, + maxAllowed // + ); + + // + result = ArraySize(tbs); + + // + return result; + } + + /** + * Use Specified Trigger Block and Make it Un Available ... + * + * @param tb: XTriggerBlock instance reference, Specified Used Trigger Block ... + */ + void UseTriggerBlock(XTriggerBlock &tb) + { + // + bool has = tb.IsValid(); + if (!has) + { + return; + } + + // + // Trigger Box ... + has = tb.trigger.IsValid(); + if (has) + { + // + AddRef( + tb.trigger, + unavailableZones // + ); + } + + // + // Order Block Box ... + has = tb.ob.IsValid(); + if (has) + { + // + AddRef( + tb.ob, + unavailableZones // + ); + } + + // + // Fair Value Gap ... + has = tb.fvg.IsValid(); + if (has) + { + // + AddRef( + tb.fvg, + unavailableZones // + ); + } + + // + // Following Liquidity ... + has = tb.fLiquidity.IsValid(); + if (has) + { + // + AddRef( + tb.fLiquidity, + unavailableZones // + ); + } + + // + // Reversal Liquidity ... + has = tb.rLiquidity.IsValid(); + if (has) + { + // + AddRef( + tb.rLiquidity, + unavailableZones // + ); + } + + // + // Cleaning Up ... + CleanupArray( + unavailableZones, + maxAllowedCollection // + ); + } + + /** + * Draw Exists Trigger Blocks ... + */ + void DrawTriggerBlocks(datetime to = NULL) + { + // + // Check Has Child of trigger Blocks ... + bool has = HasChild(triggerBlocks); + if (!has) + { + return; + } + + // + // Loop through Blocks ... + int count = ArraySize(triggerBlocks); + for (int i = 0; i < count; i++) + { + // + // Draw Indexed Trigger Block ... + DrawTriggerBlock( + triggerBlocks[i], + drawer.drawer, + mObjects, + to, + false // + ); + } + } + // // Private ... private: @@ -797,6 +1211,7 @@ class XCXCATBEASignaller : XCBase string provider; CArrayObj *mObjects; ENUM_TIMEFRAMES period; + int maxAllowedCollection; // Max Allowed Collection Items ... // // Initialize and Configure POI Detector and Drawer ... diff --git a/XCATBEA/Libraries/xcatbea.lib.mq5 b/XCATBEA/Libraries/xcatbea.lib.mq5 index 0d65d111..e27840ba 100644 --- a/XCATBEA/Libraries/xcatbea.lib.mq5 +++ b/XCATBEA/Libraries/xcatbea.lib.mq5 @@ -303,6 +303,346 @@ struct XTriggerBlockFilters // // Extensions ... +/** + * Get Newest Trigger Block Index inside a Collection ... + * + * @return ( int ) + */ +int GetYoungest(XTriggerBlock &tbs[]) +{ + // + int result = -1; + + // + // Checking Collection Has Childs ... + if (!HasChild(tbs)) + { + return result; + } + + // + datetime selected = NULL; + int count = ArraySize(tbs); + for (int i = 0; i < count; i++) + { + // + bool canSelect = + !IsValid(selected) + ? true + : tbs[i].trigger.from > selected; + if (canSelect) + { + // + result = i; + selected = tbs[i].trigger.from; + } + } + + // + return result; +} + +/** + * Get Oldest Trigger Block Index inside a Collection ... + * + * @return ( int ) + */ +int GetOldest(XTriggerBlock &tbs[]) +{ + // + int result = -1; + + // + // Checking Collection Has Childs ... + if (!HasChild(tbs)) + { + return result; + } + + // + datetime selected = NULL; + int count = ArraySize(tbs); + for (int i = 0; i < count; i++) + { + // + bool canSelect = + !IsValid(selected) + ? true + : tbs[i].trigger.from < selected; + if (canSelect) + { + // + result = i; + selected = tbs[i].trigger.from; + } + } + + // + return result; +} + +/** + * Get Highest Trigger Block Index inside a Collection ... + * + * @return ( int ) + */ +int GetHighest(XTriggerBlock &tbs[]) +{ + // + int result = -1; + + // + // Checking Collection Has Childs ... + if (!HasChild(tbs)) + { + return result; + } + + // + double selected = 0; + int count = ArraySize(tbs); + for (int i = 0; i < count; i++) + { + // + bool canSelect = + selected <= 0 + ? true + : tbs[i].trigger.lower > selected; + if (canSelect) + { + // + result = i; + selected = tbs[i].trigger.lower; + } + } + + // + return result; +} + +/** + * Get Lowest Trigger Block Index inside a Collection ... + * + * @return ( int ) + */ +int GetLowest(XTriggerBlock &tbs[]) +{ + // + int result = -1; + + // + // Checking Collection Has Childs ... + if (!HasChild(tbs)) + { + return result; + } + + // + double selected = 0; + int count = ArraySize(tbs); + for (int i = 0; i < count; i++) + { + // + bool canSelect = + selected <= 0 + ? true + : tbs[i].trigger.upper < selected; + if (canSelect) + { + // + result = i; + selected = tbs[i].trigger.upper; + } + } + + // + return result; +} + +/** + * Find Trigger Block Index inside a Colletion ... + */ +bool FindTriggerBlockIndex( + int &index, + XTriggerBlock &tb, + XTriggerBlock &tbs[] // +) +{ + // + bool result = false; + + // + index = -1; + + // + result = tb.IsValid(); + if (!result) + { + return result; + } + + // + bool isExists = false; + bool has = HasChild(tbs); + if (has) + { + // + int count = ArraySize(tbs); + for (int i = 0; i < count; i++) + { + // + isExists = tb.trigger.IsSameAs(tbs[i].trigger); + if (isExists) + { + // + index = i; + break; + } + } + } + + // + result = + isExists && + IsValidIndex(index); + + // + return result; +} + +/** + * Remove Specified Trigger Block from a Collection, if Exists ... + * + * @param tb: XTriggerBlock instance reference, Specified Trigger Block for Checking ... + * @param tbs: XTriggerBlock instance reference Array, Collection of Trigger Blocks ... + * + * @return ( bool ) + */ +bool RemoveTriggerBlock( + XTriggerBlock &tb, + XTriggerBlock &tbs[] // +) +{ + // + bool result = false; + + // + // Validate Args ... + result = tb.IsValid() && + HasChild(tbs); + if (!result) + { + return result; + } + + // + int idx = -1; + result = FindTriggerBlockIndex( + idx, + tb, + tbs // + ); + if (!result) + { + return result; + } + + // + result = ArrayRemove( + tbs, + idx, + 1 // + ); + + // + return result; +} + +/** + * Detect a TriggerBlock which Specified TriggerBlock is Inside of it ... + * + * @param tb: XTriggerBlock instance reference, Specified Trigger Block for Checking ... + * @param insideTB: XTriggerBlock instance reference, Holds founded inside Trigger Block ... + * @param tbs: XTriggerBlock instance collection, Specified Collection for Checking ... + * @param minimumLengthBetweenTBs: int, Minimum Bars between two Trigger Blocks ... + * + * @return ( int ) founded Inside TriggerBlock index ... + */ +int DetectInsideTriggerBlock( + XTriggerBlock &tb, + XTriggerBlock &insideTB, + XTriggerBlock &tbs[], + int minimumLengthBetweenTBs = 5 // +) +{ + // + int result = -1; + + // + // Normalize Args ... + minimumLengthBetweenTBs = NormalizeInt(minimumLengthBetweenTBs, 3); + + // + // Check Collection has Childs ... + bool has = HasChild(tbs); + if (!has) + { + return result; + } + + // + insideTB.Clean(); + bool isBullish = tb.IsBullish(); + bool isBearish = tb.IsBearish(); + + // + int count = ArraySize(tbs); + for (int i = 0; i < count; i++) + { + // + // Check Trigger Block Conditions ... + bool isInside = + // + // Check Not Same ... + !tb.trigger.IsSameAs(tbs[i].trigger) && + // + // Check Direction ... + tb.trigger.dir == tbs[i].trigger.dir && + // + // Check Length of TBS ... + (minimumLengthBetweenTBs <= 0 + ? true + : tb.trigger.FromIndex() + minimumLengthBetweenTBs <= tbs[i].trigger.FromIndex()) && + // + // Check Inside it ... + (isBullish + ? (tb.trigger.lower < tbs[i].trigger.upper && + tb.trigger.lower > tbs[i].trigger.lower && + tb.trigger.lower < tbs[i].trigger.GetMid()) + : (tb.trigger.upper > tbs[i].trigger.lower && + tb.trigger.upper < tbs[i].trigger.upper && + tb.trigger.upper > tbs[i].trigger.GetMid())) && + // + // Check Last ... + (!insideTB.IsValid() + ? true + : isBullish + ? insideTB.trigger.upper > tbs[i].trigger.upper + : insideTB.trigger.lower < tbs[i].trigger.lower) + // + ; + if (isInside) + { + // + result = i; + insideTB = tbs[i]; + } + } + + // + return result; +} + /** * Detect Trigger Block ... * diff --git a/XCATBEA/Libraries/xcatbea.signaller.lib.mq5 b/XCATBEA/Libraries/xcatbea.signaller.lib.mq5 index 431d3c90..2875ca73 100644 --- a/XCATBEA/Libraries/xcatbea.signaller.lib.mq5 +++ b/XCATBEA/Libraries/xcatbea.signaller.lib.mq5 @@ -275,12 +275,64 @@ struct XCATBEAStrategyConditions // }; -// -bool DetectSignalZone() +/** + * Detect Signal Zone based on Market Conditions ... + * + * @param helper: XCX121XCatbHelper instance pointer ... + * @param barAnalyser: XCBarAnalyser instance pointer ... + * @param conditions: X121XCatbConditions instance reference, hold signalling Conditions ... + * @param signalZone: XBoxZone instance reference, hold Signal Zone ... + * @param barIndex: int, Bar Index ... + * @param loopback: int, Loopback for Market Conditions ... + * + * @return ( bool ) + */ +bool DetectSignalZone( + XCX121XCatbHelper *helper, + XCBarAnalyser *barAnalyser, + X121XCatbConditions &conditions, + XBoxZone &signalZone, + int barIndex = 0, + int loopback = 10 // +) { // bool result = false; + // + // Normalize Args ... + signalZone.Clean(); + conditions.Clean(); + loopback = NormalizeInt(loopback, 0); + barIndex = NormalizeInt(barIndex, 0); + + // + // Validate Args ... + result = + helper != NULL && + barAnalyser != NULL; + if (!result) + { + return result; + } + + // + // Validate Result ... + result = signalZone.IsValid(); + + // + // Cleanup Resources ... + + // + if (!result) + { + // + signalZone.Clean(); + conditions.Clean(); + } + // return result; -} \ No newline at end of file +} + +// \ No newline at end of file