/////////////////////////////////////////////////////// // // SaherElm IT Center MQL5 Class // ------------------------------------------------- // Name: XCXCATBEASignaller ... // Description: Class for XCATBEA Signaller ... // // // 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 XCXCATBEASignaller Class" #property strict // // Imports ... #include "../../Classes/x-saherelm.x-bar.analyser.class.mq5" #include "../../Classes/x-saherelm.x-guard.class.mq5" #include "../../Helpers/x-saherelm.x121.xcatb.helper.mq5" #include "../Classes/xcatbea.x-poi.detector.class.mq5" #include "../Classes/xcatbea.x-poi.drawer.class.mq5" #include "../Libraries/xcatbea.lib.mq5" #include "../Libraries/xcatbea.signaller.lib.mq5" #include "../Libraries/xcatbea.x-poi.extensions.lib.mq5" // // Definitions ... // struct XCATBEASignallerInputs { // // Pros ... string symbol; string provider; bool allowDraws; bool allowGuards; int riskToRewardRatio; ENUM_TIMEFRAMES period; double slATRMultiplier; X121XCatbInputs catbInputs; XTriggerBlockFilters filters; XTriggerBlockValidationRules validations; // // Constructor(s) ... XCATBEASignallerInputs() { Clean(); } // // Tools ... // // Cleanup ... void Clean() { // symbol = NULL; period = NULL; provider = NULL; filters.Clean(); catbInputs.Clean(); allowDraws = false; validations.Clean(); allowGuards = false; slATRMultiplier = 0; riskToRewardRatio = 0; // ZeroMemory(this); } // // Validate ... bool IsValid() { // bool result = false; // result = IsValid(symbol) && IsValid(period) && IsValid(provider) && catbInputs.IsValid() && riskToRewardRatio > 0; // return result; } // }; class XCXCATBEASignaller : XCBase { // // Public ... public: // // 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 ... int riskToRewardRatio; // Signals R2R ... double slATRMultiplier; // SL ATR Multiplier ... // XBarTracker barTraker; // Bar Tracker ... XCX121XCatbHelper *helper; // XCATB Helper Class instance ... XCBarAnalyser *barAnalyser; // Bar Analyser ... XCXCATBEAPOIDrawer *drawer; // POI Drawer ... XTriggerBlockFilters filters; // Trigger Block Filters ... XCXCATBEAPOIDetector *detector; // POI Detector ... XTriggerBlockValidationRules validations; // Trigger Block Validations ... // 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; XCATBEAStrategyConditions mConditionsCollection[]; // // Constructor ... XCXCATBEASignaller(XCATBEASignallerInputs &inputs) { Init(inputs); } // // Deconstructor ... ~XCXCATBEASignaller() { DeInit(); } // // Properties ... // string GetSymbol() { return symbol; } // string GetProvider() { return provider; } // ENUM_TIMEFRAMES GetPeriod() { return period; } // double GetR2R() { return riskToRewardRatio; } // // Tick Analyser ... /** * Process Tick ... */ void ProcessTick( XPosition &positions[], XGuard &guards[], XCATBEAStrategyConditions &conditions, bool isActiveSession = true // ) { // Clean(guards); conditions.Clean(); // XOHCL bar; int count = 0; bool has = false; int barIndex = 0; cTriggerBlock.Clean(); cInsideTriggerBlock.Clean(); // // Check Guards ... has = DetectGuards( guards, positions, barIndex // ); // // Check Triggered Conditions ... has = HasChild(mConditionsCollection); if (has) { // int selectedIDX = -1; count = ArraySize(mConditionsCollection); for (int i = 0; i < count; i++) { // // Select indexed Conditions ... XCATBEAStrategyConditions iConditions = mConditionsCollection[i]; // // Check Conditions Triggered ... has = DetectSignalTrigger( iConditions, barIndex // ); if (has) { // selectedIDX = i; conditions = iConditions; iConditions.Clean(); // break; } // // When Setup Invalidated // Signaller Clean Conditions ... if (!has && !iConditions.IsValid()) { // selectedIDX = i; break; } // // Cleanup Resources ... iConditions.Clean(); } // // Check Can Trigger ... has = IsValidIndex(selectedIDX) && conditions.IsValid() && conditions.IsSetuped() && conditions.CanTrigger(); if (has) { // ArrayRemove( mConditionsCollection, selectedIDX, 1 // ); } else { // // Check Selected Index for Invalid Conditions ... if (IsValidIndex(selectedIDX)) { // // Remove Invalidated Conditions ... ArrayRemove( mConditionsCollection, selectedIDX, 1 // ); } // // Cleanup Resource ... conditions.Clean(); } } // // Check Bar Processing ... if (!barTraker.CanProcessBar()) { return; } // // Initialize Bar ... bar.Init( symbol, period, barIndex // ); // // Detect POI(s) ... detector.Detect(barIndex); // // Validate POI(s) ... detector.Validate( unavailableZones, barIndex // ); // // Draw POI(s) ... if (allowDraws) { 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 // Session actives ... // for improvement Calculation Speeds ... if (isActiveSession) { // // Check Signal Setups ... has = DetectSignalSetup(barIndex); if (has) { // barTraker.Waits(); // AddConditionsIfNotExists(); // mConditions.Clean(); } } // // Cleanup Resources ... bar.Clean(); } // // Signalling Tools ... /** * Detect Setup Conditions based on Signalling ... * * @param maxAllowedSLDistanceInPoint: int, Max Allowed SL Distance in Points (if Bigger thn Zero Provided) ... * * @return ( bool ) */ bool DetectSignalSetup(int barIndex = 0) { // bool result = false; // // Normalize Args ... barIndex = NormalizeInt(barIndex, 0); // // Update All Required Buffers ... helper.Update(barIndex); // // Detect Signal Setup Based on Market Conditions ... if (!result && allowSignallingBasedOnConditions) { // // Detect Signalling Zone ... result = DetectSignalZone( helper, barAnalyser, mConditions.conditions, mConditions.pivotZone, barIndex, 10 // Loopback ... ); if (result) { // // 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); // // 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 // ); 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(); // // Cleanup Resource ... // return result; } /** * Detect Trigger Conditions for Specified Signal ... * * @param conditions: XCATBEAStrategyConditions instance Reference, Specified Signal Conditions ... * @param maxAllowedSetupAge: specified Setup Age for Expiration (if bigger than Zero) ... * * @return ( bool ) */ bool DetectSignalTrigger( XCATBEAStrategyConditions &conditions, int barIndex = 0 // ) { // bool result = false; // // Normalize Args ... barIndex = NormalizeInt(barIndex, 0); // // Validate Setup ... result = conditions.IsSetuped(); if (!result) { return result; } // bool isBullish = IsBullish(conditions.dir); bool isBearish = IsBearish(conditions.dir); // // Validate Direction of Setuped Conditions ... result = result && (isBullish || isBearish); // // Do Triggering Senario based on Trigger Block ... if (result && conditions.triggerBlock.IsValid()) { // // Checking Score ... double bullishScore = 0; double bearishScore = 0; conditions .conditions .GenerateScore( bullishScore, bearishScore // ); bool isScorePassed = isBullish ? bullishScore > bearishScore : bearishScore > bullishScore; // // Complete Conditions Here ... if (isScorePassed) { conditions.triggerTime = TimeCurrent(); } } // // Do Other Validation Senarios ... // result = conditions.IsValid() && conditions.IsSetuped() && conditions.CanTrigger(); // // Check Setup Age or Setup Validations here ... if (!result) { } // // Cleanup Resources ... // return result; } /** * Detect Guards bsed on Signalling Class ... * * @param guards: XCAEAGuard instance Collection, Holds Provided Guards ... * @param positions: XPosition instance Collection, Provides Signalling Based Positions for Apply Guards on them ... * @param provider: X121SMCStrategySignalProviderData instance Reference, Specified Data for Cycles ... * * @return ( bool ) */ bool DetectGuards( XGuard &guards[], const XPosition &positions[], int barIndex = 0 // ) { // bool result = false; // // Normalize Args ... Clean(guards); barIndex = NormalizeInt(barIndex, 0); // result = allowGuards && HasChild(positions); if (!result) { return result; } // // TODO: Implement this ... // result = HasChild(guards); // // Cleanup Resources ... // if (!result) { Clean(guards); } // return result; } // // Protected ... protected: // /** * Initialize ... */ void Init(XCATBEASignallerInputs &inputs) { // maxAllowedCollection = 50; // allowSignallingBasedOnConditions = false; allowSignallingBasedOnTriggerBlocks = true; allowSignallingBasedOnTriggerBlocksInsideOther = false; // bool has = inputs.IsValid(); if (!has) { return; } // symbol = inputs.symbol; period = inputs.period; filters = inputs.filters; provider = inputs.provider; allowDraws = inputs.allowDraws; allowGuards = inputs.allowGuards; validations = inputs.validations; slATRMultiplier = inputs.slATRMultiplier; riskToRewardRatio = inputs.riskToRewardRatio; // mObjects = new CArrayObj(); // // Initialize Bar Tracker ... has = barTraker.Init( symbol, period // ); if (!has) { return; } // // Initialize Bar Analyser ... barAnalyser = new XCBarAnalyser(); // // initialize Helper ... helper = new XCX121XCatbHelper(); has = helper.Init( symbol, period, inputs.catbInputs // ); if (!has) { return; } // mConditions.Clean(); Clean(mConditionsCollection); // InitPOI(); } /** * DeInitialize ... */ void DeInit() { // mObjects.Clear(); delete mObjects; ZeroMemory(mObjects); // drawer.Clear(); delete drawer; ZeroMemory(drawer); // detector.CleanPivots(); delete detector; ZeroMemory(detector); // delete helper; ZeroMemory(helper); // delete barAnalyser; ZeroMemory(barAnalyser); // barTraker.Clean(); } /** * Add Conditions to Conditions Collection if not Exists ... * * @param maxAllowed: int, Specified Max Allowed Holding Conditions ... * * @return ( int ) */ int AddConditionsIfNotExists( int maxAllowed = 50 // ) { // int result = 0; // // Normalize Args ... maxAllowed = maxAllowedCollection; // bool isSetuped = IsValid(mConditions.setupTime) && HasDirection(mConditions.dir); if (!isSetuped) { return result; } // int count = ArraySize(mConditionsCollection); if (IsValidSize(count)) { // // Copy Original Items ... XCATBEAStrategyConditions tmpItems[]; Copy( mConditionsCollection, tmpItems // ); // // Prese Item Data ... bool isBullish = IsBullish(mConditions.dir); // for (int i = 0; i < count; i++) { // XCATBEAStrategyConditions iItem = tmpItems[i]; // bool canRemove = mConditions.dir == iItem.dir && mConditions.pivot == iItem.pivot; if (canRemove) { // ArrayRemove( mConditionsCollection, i, 1 // ); } } // Clean(tmpItems); } // AddRef( mConditions, mConditionsCollection // ); // // Remove Olds ... CleanupArray( mConditionsCollection, maxAllowed // ); // result = ArraySize(mConditionsCollection); // 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: // // Props ... string symbol; string provider; CArrayObj *mObjects; ENUM_TIMEFRAMES period; int maxAllowedCollection; // Max Allowed Collection Items ... // // Initialize and Configure POI Detector and Drawer ... void InitPOI() { // // Initialize POI Detector ... bool has = helper != NULL; if (has) { // detector = new XCXCATBEAPOIDetector(helper); // // Configure ... detector.detectPeakPivots = true; detector.detectValePivots = true; } // // Initialize POI Drawer ... has = detector != NULL; if (has) { // drawer = new XCXCATBEAPOIDrawer(detector); // // Configure ... drawer.drawPeakPivots = true; drawer.drawValePivots = true; // XCATBPivotStyle iStyle; // // Styling Peak Pivot ... iStyle.width = 1; iStyle.clr = clrMagenta; iStyle.style = STYLE_SOLID; // drawer.peakPivotStyle = iStyle; // // Styling Vale Pivot ... iStyle.width = 1; iStyle.clr = clrAqua; iStyle.style = STYLE_SOLID; // drawer.valePivotStyle = iStyle; // // Cleanup Resources ... // iStyle.Clean(); } } // };