diff --git a/Classes/x-saherelm.x-guard.class.mq5 b/Classes/x-saherelm.x-guard.class.mq5 new file mode 100644 index 00000000..db459ae4 --- /dev/null +++ b/Classes/x-saherelm.x-guard.class.mq5 @@ -0,0 +1,198 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class +// ------------------------------------------------- +// Name: XCXGuard ... +// Description: Guard Provider 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 Guard Provider Class" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.base.class.mq5"; + +// +// Enumeration ... + +// +// Guard Actions ... +enum ENUM_X_GUARD_ACTIONS +{ + X_GUARD_ACTION_NONE, // Nothing to Do + X_GUARD_ACTION_CLOSE, // Close Specified Position + X_GUARD_ACTION_CLOSE_ALL, // Close All Positions + X_GUARD_ACTION_CLOSE_LONGS, // Close All Long Positions + X_GUARD_ACTION_CLOSE_SHORTS, // Close All Short Position + X_GUARD_ACTION_PARTIAL_CLOSE, // Partial Close Specified Position + X_GUARD_ACTION_TRAIL_STOP, // Trail Stop of Specified Position + X_GUARD_ACTION_TRAIL_TARGET, // Trail Target of Specified Position + X_GUARD_ACTION_HEDGE, // Hedge Specified Positions +}; + +// +// Definitions ... + +// +// Model a Guard Action ... +struct XGuard +{ + // + // Props ... + ENUM_X_GUARD_ACTIONS action; + datetime time; + + // + string symbol; + string provider; + + // + // Specified Position ... + ulong ticket; + + // + // Partial Close ... + double volumeMultiplier; + + // + // SL Trial ... + double sl; + + // + // TP Trial ... + double tp; + + // + // Constructor ... + XGuard() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleanup ... + */ + void Clean() + { + // + time = NULL; + action = X_GUARD_ACTION_NONE; + + // + symbol = NULL; + provider = NULL; + + // + ticket = 0; + + // + volumeMultiplier = 0; + + // + sl = 0; + tp = 0; + + // + ZeroMemory(this); + } + + /** + * Validate ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = + // + IsValid(time) && + IsValid(symbol) && + IsValid(provider) && + action != X_GUARD_ACTION_NONE + // + ; + if (!result) + { + return result; + } + + // + // Validate Model Based On Specified Guard Actions ... + + // + return result; + } +}; + +// +// Extensions ... + +// +bool IsValid(ENUM_X_GUARD_ACTIONS item) +{ + // + bool result = false; + + // + result = item != X_GUARD_ACTION_NONE; + + // + return result; +} + +/** + * Add Guard to Collection ... + * + * @param guard: XGuard instance ... + * @param guards: XGuard instance Collection ... + * + * @return ( int ) + */ +int AddGuard( + XGuard &guard, + XGuard &guards[] // +) +{ + // + int result = 0; + + // + if (!guard.IsValid()) + { + return result; + } + + // + AddRef( + guard, + guards // + ); + + // + result = ArraySize(guards); + + // + return result; +} + +// +// Implementation ... diff --git a/Documents/BKP/xcatb.test.ea.mq5 b/Documents/BKP/xcatb.test.ea.mq5 new file mode 100644 index 00000000..cefd7d17 --- /dev/null +++ b/Documents/BKP/xcatb.test.ea.mq5 @@ -0,0 +1,1143 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center XCATB MQL5 Expert Advisor +// ------------------------------------------------- +// Name: XCAEA +// Description: an Exper Advisor which used XCATB +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "EA based on X121 XCATB indicator" +#property strict + +// +// Include Common Library ... +#include "../Classes/x-saherelm.x-alert.class.mq5" +#include "../Classes/x-saherelm.x-bar.analyser.class.mq5" +#include "../Classes/x-saherelm.x-poi.drawer.class.mq5" +#include "../Classes/x-saherelm.x-trade.class.mq5" +#include "../Classes/x-saherelm.x-volume.class.mq5" +#include "../Helpers/x-saherelm.x121.xcatb.helper.mq5" +#include "../XCATBEA/Classes/xcatbea.signaller.class.mq5" +#include "../XCATBEA/Classes/xcatbea.x-trade.manager.class.mq5" +#include "../XCATBEA/Libraries/xcatbea.signaller.lib.mq5" + +// +#define ShortName "XCATBEA" + +// +// Inputs ... + +// +// Common ... +input group "Common"; +input long eaMagicNumber = 1694056; // Magic Number +input int eaSlippage = 10; // Slippgae +input string eaLogSuffix = ""; // Log Suffix + +// +// Detector ... +input group "Detector"; + +// +// Validating ... +input group "Validations"; +input bool eaForceHasSwing = false; // Force Block to Has Propper Swing +input bool eaForceOBBarType = false; // Force Order Block to Has InDirectional Bars +input int eaMinRequiredOBBar = 0; // Min Required OB Bar +input bool eaForceFVGBarType = false; // Force Fair Value Gaps Bars Type +input int eaLiquidityLoopback = 0; // Liquidity Detection Loopback +input double eaMaxAllowedRange = 0.0; // Max Allowed Order Block Range +input double eaMinAllowedRange = 0.0; // Min Allowed Order Block Range +input bool eaForceHasFLiquidity = false; // Force Order Block To Has Reversal Liquidity +input bool eaForceHasRLiquidity = false; // Force Order Block to Has Following Liquidity +input bool eaValidateGapSequence = false; // Validate Fair Value Gaps Bar Sequences +input int eaMinAllowedBlockLength = 0; // Min Allowed Block Length +input bool eaValidateBlockEdgeBreakout = false; // Validate Order Block Edge Breakeout + +// +// Filtering ... +input group "Filters"; +input bool eaFilterBasedOnPV = false; // Filter Based On PV +input int eaBosLoopback = 0; // PV Based Filtering BOS Lookup +input bool eaFilterBasedOnSar = false; // Filter Based On SAR +input bool eaForceSarSwitched = false; // SAR Switched on Sides for Filtering +input bool eaForceSarOnBothSide = false; // SAR Check on Both Sides for Filtering +input bool eaForceSarHasBreakout = false; // SAR Must Breakout +input bool eaForceSarHasReversalSide = false; // SAR Must Has Reversal Direction +input bool eaFilterBasedOnRSI = false; // Filter Based On RSI +input bool eaForceHasRSITrending = false; // RSI Must Has Trending +input bool eaForceHasRSIVPattern = false; // RSI Must Has Pattern +input bool eaForceHasRSICrossing = false; // RSI Must Has Crossing Levels +input bool eaFilterBasedOnADX = false; // Filter Based On ADX +input bool eaForceHasADXTrending = false; // ADX Must Has Trending +input bool eaForceHasADXCrossing = false; // ADX Must Has Crossing +DI/-DI +input bool eaFilterBasedOnATR = false; // Filter Based On ATR +input bool eaForceHasATRTrending = false; // ATR Must Has Trending +input bool eaForceHasATRBreakout = false; // ATR Must Has Breakout +input bool eaFilterBasedOnTrend = false; // Filter Based On Trend +input bool eaForceHasTrendDir = false; // TREND Must Has Following Direction +input bool eaForceHasTrendPlace = false; // TREND Place Based Filtering +input bool eaForceHasTrendChange = false; // TREND Change Filtering +input bool eaForceHasTrendTrending = false; // TREND Must Has Trending +input bool eaForceHasTrendRejection = false; // TREND Line Must Rejected +input bool eaForceHasTrendLineInside = false; // TREND Line has Inside +input bool eaForceHasTrendDirOnBothSide = false; // TREND Must Has Following Direction in Both Side +input bool eaFilterBasedOnDelta = false; // Filter Based On Delta +input bool eaFilterBasedOnVolume = false; // Filter Based On Volume +input bool eaFilterBasedOnSignalBar = false; // Filter Based on Signal Bar +input bool eaFilterBasedOnHKSignalBar = false; // Filter Based On HK Signal Bar + +// +// Signal ... +input group "Signal"; +input int eaSignalR2R = 2; // Risk Reward Ratio +input double eaSLAtrMultiplier = 0; // ATR Multiplier for SL + +// +// Volume ... +input group "Volume"; +input ENUM_X_VOLUME_SELECT_TYPE eaVolumeSelect = X_VOLUME_EQUITY; // Volume Applying Type +input double eaStaticVoluem = 0.0; // Static Volume +input double eaDynamicVolumeStepBalance = 0.0; // Step of Balance for Increase Volume +input double eaDynamicVolumeStepVolume = X_MIN_VOLUME; // Step of Volume Increasing +input double eaConstantRiskBalance = 0.0; // Constant Risk Balance per Trade +input double eaConstantPercent = 0.5; // Constant Percent of Balance Per Trade +input double eaConstantBalance = 0.0; // Constant Balance for Calculations + +// +// Management ... +// eaSessions => (SYDNEY_02:00_14:00),(NY_19:00_23:00) +input group "Management"; +input bool eaAllowTrade = true; // Allow Trade on Signals +input bool eaAllowLongs = true; // Allow Long Trades +input bool eaAllowShorts = true; // Allow Short Trades +input string eaSessions = ""; // Active Sessions +input ENUM_XCATBEA_TRADE_RESTRICTION_PERIOD eaRestrictionsPeriod = XCATBEA_TRADE_RESTRICATION_NONE; // Restrictions Period +input int eaMaxAllowedTPs = 0; // Max Allowed TP(s) in Restrictions Period +input int eaMaxAllowedSLs = 0; // Max Allowed SL(s) in Restrictions Period +input int eaMaxAllowedTrades = 0; // Max Allowed Trades in Restrictions Period +input int eaMaxAllowedPositions = 5; // Max Allowed Same Time Trades +input double eaMaxAllowedSpread = 25; // Max Allowed Spread For Trade +input double eaMaxAllowedDrawdownFactor = 0.3; // Max Allowed DrawDown for Trade +input string eaCloseAllOpenTradesAt = ""; // Close All Open Trades per Day At Specified Time + +// +// Alert ... +// Here we Provider All Requirements for +// Configuring Alert Provider ... +input group "Alert"; +input bool eaEnableAlerts = true; // Enable Alerts +input bool eaLogAlerts = true; // Log Alerts +input bool eaMailAlerts = false; // Mail Alerts +input bool eaPushAlerts = true; // Push Alerts +input bool eaTerminalAlerts = false; // Terminal Alerts + +// +// Time Report ... +input group "Reports"; +input bool eaReportNewMonths = false; // Report New Month +input bool eaReportNewWeeks = false; // Report New Weeks +input bool eaReportNewDays = true; // Report New Days +input bool eaReportNewHours = false; // Report New Hours +input bool eaReportTrades = true; // Report Trades +input bool eaReportSignals = true; // Report Signals +input bool eaReportProtector = true; // Report Protector Actions +input bool eaReportAfterTradesBalance = true; // Report Balance after a Trade Finished + +// +// Collector ... +input group "Collector"; +input bool eaSaveTrades = false; // Save Trades +input bool eaSaveSignals = false; // Save Signals +input bool eaSaveWins = false; // Save Winning Conditions +input bool eaSaveLosts = false; // Save Lost Conditions + +// +// Variables ... + +// +XCAlert *eaAlert; +XCTrade *eaTrade; +XSignal eaSignal; +string eaTag = ""; +XCVolume *eaVolume; +XTriggerBlock eaTB; +CArrayObj *eaObjects; +XCPOIDrawer *eaDrawer; +XBarTracker eaBarTraker; +X121XCatbInputs eaInputs; +XTimeTracker eaTimeTracker; +XCX121XCatbHelper *eaHelper; +XCBarAnalyser *eaBarAnalyser; +XTriggerBlockFilters eaFilters; +X121XCatbConditions eaCatbConditions; +XCXCATBEATradeManager *eaTradeManager; +XCATBEAStrategyConditions eaConditions; +XTriggerBlockValidationRules eaValidations; + +// +// Event Handlers ... + +// +// Initialization ... +int OnInit() +{ + // + // Validate Inputs and Required Parameters + // for EA to Works fine ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // Initial Requirements ... + InitRequirements(); + + // + // Initialize Volume Manger ... + if (!InitVolume()) + { + return INIT_FAILED; + } + + // + return (INIT_SUCCEEDED); +} + +// +// DeInitialization ... +void OnDeinit(const int reason) +{ + // + // REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + // REASON_REMOVE 1 Program removed from a chart + // REASON_RECOMPILE 2 Program recompiled + // REASON_CHARTCHANGE 3 A symbol or a chart period is changed + // REASON_CHARTCLOSE 4 Chart closed + // REASON_PARAMETERS 5 Inputs changed by a user + // REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + // REASON_TEMPLATE 7 Another chart template applied + // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + // REASON_CLOSE 9 Terminal closed + + // + // eaObjects.Clear(); + + // + delete eaHelper; + ZeroMemory(eaHelper); + + // + delete eaAlert; + ZeroMemory(eaAlert); + + // + delete eaTrade; + ZeroMemory(eaTrade); + + // + delete eaDrawer; + ZeroMemory(eaDrawer); + + // + delete eaVolume; + ZeroMemory(eaVolume); + + // + delete eaBarAnalyser; + ZeroMemory(eaBarAnalyser); + + // + eaTB.Clean(); + eaSignal.Clean(); + eaSignal.Clean(); + eaFilters.Clean(); + eaBarTraker.Clean(); + eaConditions.Clean(); + eaConditions.Clean(); + eaTimeTracker.Clean(); + eaValidations.Clean(); + eaCatbConditions.Clean(); + + // + DestroyTimer(); +} + +// +// On Tick Handler ... +void OnTick() +{ + // + // Handle Tradings ... + bool tradeUsingTriggerBlock = true; + bool tradeUsingMarketConditions1 = true; + + // + HandleTimeReport(); + + // + // Handle Position Management / Protections ... + eaTradeManager.Manage(); + + // + eaTB.Clean(); + eaSignal.Clean(); + eaConditions.Clean(); + eaCatbConditions.Clean(); + + // + bool has = false; + int barIndex = 0; + int cBarIndex = 0; + + // + // Check Bar Processing ... + if (!eaBarTraker.CanProcessBar()) + { + return; + } + + // + eaHelper.Check(barIndex); + + // + // Reading Required Bars ... + XOHCL zBar; + XOHCL cBar; + has = zBar.Init( + _Symbol, + _Period, + barIndex // + ); + has = + has && + zBar.GetPreviousBar(cBar); + if (!has) + { + // + zBar.Clean(); + cBar.Clean(); + + // + return; + } + + // + cBarIndex = barIndex + 1; + + // + // Update All Required Buffers ... + eaHelper.Update(cBarIndex); + + // + // Check Trigger Block Detected or Not ... + if (tradeUsingTriggerBlock) + { + // + // Trigger Block Detection ... + has = DetectTriggerBlock1( + eaHelper, + eaBarAnalyser, + eaTB, + eaCatbConditions, + eaValidations, + eaFilters, + barIndex, + 10 // Loopback ... + ); + + // + if (has) + { + // + // Wait for Next Bar for anything ... + eaBarTraker.Waits(); + + // + // Prepare Target ... + double targets[]; + for (int i = 1; i <= eaSignalR2R; i++) + { + // + Add( + (double)i, + targets // + ); + } + + // + // Calculate SL Additions ... + double iATR = 0; + if (barIndex > 0 && + barIndex < ArraySize(eaHelper.atrBuffer)) + { + iATR = eaHelper.atrBuffer[barIndex]; + } + double slAdditional = eaSLAtrMultiplier * iATR; + + // + // Preparing Signal ... + has = ToSignal( + eaTB.trigger, + eaTB.signal, + targets, + slAdditional // + ); + + // + // Draw Trigger Block ... + DrawTriggerBlock( + eaTB, + eaDrawer, + eaObjects, + NULL // + ); + + // + // Attach Signal ... + eaSignal = eaTB.signal; + + // + // Check Signal Type ... + bool isLong = IsLong(eaSignal.type); + + // + // Update Entry ... + eaSignal.entry = GetEntry( + eaSignal.symbol, + eaSignal.type // + ); + + // + // Update Signal Targets ... + UpdateSignalTargets(eaSignal); + + // + // Handle Volume Management ... + double iVolume = eaVolume.CalculateVolume(eaSignal); + if (iVolume > X_MIN_VOLUME && + iVolume != eaSignal.volume) + { + eaSignal.volume = iVolume; + } + + // + eaConditions.sl = eaSignal.sl; + eaConditions.tp = eaSignal.tp; + eaConditions.pivot = eaSignal.sl; + eaConditions.time = eaSignal.time; + eaConditions.reward = eaSignalR2R; + eaConditions.point = eaSignal.entry; + eaConditions.entry = eaSignal.entry; + eaConditions.symbol = eaSignal.symbol; + eaConditions.period = eaSignal.period; + eaConditions.setupTime = eaSignal.time; + eaConditions.triggerTime = eaSignal.time; + eaConditions.decisionZone = eaTB.trigger; + eaConditions.provider = eaSignal.provider; + eaConditions.conditions = eaCatbConditions; + eaConditions.type = ToPositionType(eaSignal.type); + eaConditions.dir = + isLong + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + Copy( + eaSignal.targets, + eaConditions.targets // + ); + eaSignal.conditions = + eaCatbConditions + .GenerateSummary( + false, // Commons ... + true, // Conditions ... + true, // Scores ... + false // Ignore Falses ... + ); + + // + // Execute Signal ... + has = eaTradeManager.Execute( + eaSignal, + eaConditions // + ); + } + + // + eaTB.Clean(); + } + + // + // Trade Using Market Conditions ... + if (tradeUsingMarketConditions1) + { + // + XBoxZone signalZone; + X121XCatbConditions conditions; + has = DetectSignalZone( + eaDrawer, + eaHelper, + eaBarAnalyser, + signalZone, + conditions, + barIndex // + ); + if (has) + { + // + // Convert Box to Signal ... + } + } + + // + // Cleanup Resources ... + + // + zBar.Clean(); + cBar.Clean(); + eaTB.Clean(); + eaSignal.Clean(); + eaConditions.Clean(); + eaCatbConditions.Clean(); +} + +// +// Handle On Trade Event ... +void OnTrade() +{ + eaTrade.HandleOnTrade(); +} + +// +// On Timer ... +void OnTimer() +{ +} + +// +// Chart Event Handler ... +void OnChartEvent( + const int id, + const long &lparam, + const double &dparam, + const string &sparam // +) +{ +} + +// +// Event Listeners ... + +/** + * Handle StopLoss Triggered Positions ... + * + * @param deal: XDeal instance ... + */ +void OnStopLossTriggered(const XDeal &deal) +{ + eaTradeManager.HandleSL(deal); +} + +/** + * Handle Take Profit Triggered Positions ... + * + * @param deal: XDeal instance ... + */ +void OnTakeProfitTriggered(const XDeal &deal) +{ + eaTradeManager.HandleTP(deal); +} + +/** + * Handle Force Close a Position ... + * + * @param ticket: ULONG ... + * @param position: XPosition instance ... + * @param comment: string ... + */ +void OnPositionForceClosed( + const ulong ticket, + const XPosition &position, + const string comment // +) +{ + eaTradeManager.HandleForceClose(position); +} + +/** + * Handle Position Partially Closed Event ... + * + * @param ticket: ULONG ... + * @param profit: double ... + * @param comment: string ... + */ +void OnPositionPartiallyClosed( + const ulong ticket, + const double profit, + const string comment // +) +{ + eaTradeManager.HandlePartiallyClosed( + ticket, + profit, + comment // + ); +} + +/** + * Handle Deals Changes ... + * + * @param count: Integer, Number of Changes ... + */ +void OnDealsChanged(int count) +{ +} + +/** + * Handle Orders Changes ... + * + * @param count: Integer, Number of Changes ... + */ +void OnOrdersChanged(int count) +{ +} + +/** + * Handle Positions Changes ... + * + * @param count: Integer, Number of Changes ... + */ +void OnPositionsChanged(int count) +{ +} + +// +// Custom Functions ... + +/** + * Validate all Inputs of Expert Adviser ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = false; + + // + string errMessage = ""; + + // + bool isCommonValid = ( + // + eaSlippage > 0 && + eaMagicNumber > 0 + // + ); + if (!isCommonValid) + { + // + errMessage += "common configurations error;" + "\n"; + } + + // + result = + // + // Common ... + isCommonValid && + // + // Otere ... + true + // + ; + + // + if (!result) + { + // + // Since here Logger not Initiallized, we Use Raw Print Command ... + Print(ShortName + " Errors: \n", errMessage); + } + + // + return result; +} + +/** + * Initialize Timer ... + * + * @return ( bool ) + */ +bool InitTimer() +{ + // + bool result = false; + + // + // TODO: Initialize Timer if necessary ... + // result = EventSetTimer(1); + // result = EventSetMillisecondTimer(100); + result = true; + + // + return result; +} + +/** + * Destroy Timer ... + */ +void DestroyTimer() +{ + // + // TODO: Use This ... + // EventKillTimer(); +} + +/** + * Initial Volume Manager Class Based on Given Configuration ... + * + * @return ( bool ) + */ +bool InitVolume() +{ + // + bool result = false; + + // + eaVolume = new XCVolume(); + + // + result = eaVolume.Init( + eaVolumeSelect, + eaStaticVoluem, + eaDynamicVolumeStepBalance, + eaDynamicVolumeStepVolume, + eaConstantRiskBalance, + eaConstantPercent, + eaConstantBalance // + ); + + // + return result; +} + +/** + * Initial Requirements of EA ... + */ +void InitRequirements() +{ + // + // Initial Bar Tracker ... + eaBarTraker.Init( + _Symbol, + _Period // + ); + + // + // Preparing Tags ... + eaTag = + (IsValid(eaLogSuffix) + ? eaLogSuffix + "_" + : "") + + ShortName; + + // + eaAlert = new XCAlert(); + eaAlert.SetPrefix(eaLogSuffix); + eaAlert.SetLogAlerts(eaLogAlerts); + eaAlert.SetMailAlerts(eaMailAlerts); + eaAlert.SetPushAlerts(eaPushAlerts); + eaAlert.SetEnableAlerts(eaEnableAlerts); + eaAlert.SetTerminalAlerts(eaTerminalAlerts); + + // + // Objects ... + eaObjects = new CArrayObj(); + + // + // Configure XCA ... + eaInputs.Default(); + + // + // Hide all Visible Buffers ... + eaInputs.Hide(); + + // + // we Can make Show all requirements here ... + + // + eaInputs.showPV = true; + eaInputs.showSar = true; + eaInputs.showTrend = true; + eaInputs.showATRBand = true; + eaInputs.showPVGolden = true; + + // + eaHelper = new XCX121XCatbHelper(); + bool isInited = eaHelper.Init( + _Symbol, + _Period, + eaInputs // + ); + + // + eaDrawer = new XCPOIDrawer(); + eaBarAnalyser = new XCBarAnalyser(); + + // + // EA Trade ... + eaTrade = new XCTrade( + eaSlippage, + eaMagicNumber, + eaMaxAllowedSpread, + eaMaxAllowedPositions, + eaMaxAllowedDrawdownFactor // + ); + eaTrade.AddOnStopLossEventHandler(OnStopLossTriggered); + eaTrade.AddOnTakeProfitEventHandler(OnTakeProfitTriggered); + eaTrade.AddOnForceClosePositionEventHandler(OnPositionForceClosed); + eaTrade.AddOnPartialClosePositionEventHandler(OnPositionPartiallyClosed); + + // + // EA Trae Manager ... + eaTradeManager = new XCXCATBEATradeManager( + eaTrade // + ); + // + eaTradeManager.SetAlertPrefix(eaTag); + eaTradeManager.SetAlertLogAlerts(eaLogAlerts); + eaTradeManager.SetAlertMailAlerts(eaMailAlerts); + eaTradeManager.SetAlertPushAlerts(eaPushAlerts); + eaTradeManager.SetAlertEnableAlerts(eaEnableAlerts); + eaTradeManager.SetAlertTerminalAlerts(eaTerminalAlerts); + // + eaTradeManager.SaveWins(eaSaveWins); + eaTradeManager.SaveLosts(eaSaveLosts); + eaTradeManager.SaveTrades(eaSaveTrades); + eaTradeManager.SaveSignals(eaSaveSignals); + + // + // Setting Trade Reports ... + eaTradeManager + .SetTradeReports( + eaReportTrades, + eaReportSignals, + eaReportProtector, + eaReportAfterTradesBalance // + ); + + // + // Setting Trade Permissions ... + eaTradeManager + .SetTradePermissions( + eaAllowTrade, + eaAllowLongs, + eaAllowShorts // + ); + + // + // Setting Trade Restrictions ... + eaTradeManager + .SetTradeRestrictions( + eaRestrictionsPeriod, + eaMaxAllowedTPs, + eaMaxAllowedSLs, + eaMaxAllowedTrades // + ); + + // + // Initializing Sessions ... + string sessions[]; + int sessionsCount = 0; + bool hasSession = IsValid(eaSessions); + if (hasSession) + { + // + // Extract Per Symbol Sessions ... + sessionsCount = SplitContent( + sessions, + eaSessions, + "," // + ); + + // + // Try to Extract Start and End Times Series ... + hasSession = IsValidSize(sessionsCount); + if (hasSession) + { + // + // Iterate Sessions ... + for (int i = 0; i < sessionsCount; i++) + { + // + // Ignore unused Cases and Extracts only Content ... + string iSessionDescriptorStr = ExtractString(sessions[i]); + isInited = IsValid(iSessionDescriptorStr); + if (isInited) + { + // + // Extract Session Descriptor Data ... + string parts[]; + int partsCount = SplitContent( + parts, + iSessionDescriptorStr, + "_" // + ); + isInited = IsValidSize(partsCount) && partsCount == 3; + if (isInited) + { + // + string iName = parts[0]; + string iStart = parts[1]; + string iEnd = parts[2]; + isInited = IsValid(iName) && + IsValid(iStart) && + IsValid(iEnd); + if (isInited) + { + // + // Set Active Session ... + eaTradeManager + .SetTradeSession( + _Symbol, + iStart, + iEnd, + iName // + ); + } + } + } + } + } + } + + // + // Fill Validations ... + eaValidations.forceHasSwing = eaForceHasSwing; + eaValidations.forceOBBarType = eaForceOBBarType; + eaValidations.minRequiredOBBar = eaMinRequiredOBBar; + eaValidations.forceFVGBarType = eaForceFVGBarType; + eaValidations.liquidityLoopback = eaLiquidityLoopback; + eaValidations.maxAllowedRange = eaMaxAllowedRange; + eaValidations.minAllowedRange = eaMinAllowedRange; + eaValidations.forceHasFLiquidity = eaForceHasFLiquidity; + eaValidations.forceHasRLiquidity = eaForceHasRLiquidity; + eaValidations.validateGapSequence = eaValidateGapSequence; + eaValidations.minAllowedBlockLength = eaMinAllowedBlockLength; + eaValidations.validateBlockEdgeBreakout = eaValidateBlockEdgeBreakout; + + // + // Fill Filters ... + + // + eaFilters.filterBasedOnPV = eaFilterBasedOnPV; + eaFilters.bosLoopback = eaBosLoopback; + + // + eaFilters.filterBasedOnSar = eaFilterBasedOnSar; + eaFilters.forceSarSwitched = eaForceSarSwitched; + eaFilters.forceSarOnBothSide = eaForceSarOnBothSide; + eaFilters.forceSarHasBreakout = eaForceSarHasBreakout; + eaFilters.forceSarHasReversalSide = eaForceSarHasReversalSide; + + // + eaFilters.filterBasedOnRSI = eaFilterBasedOnRSI; + eaFilters.forceHasRSITrending = eaForceHasRSITrending; + eaFilters.forceHasRSIVPattern = eaForceHasRSIVPattern; + eaFilters.forceHasRSICrossing = eaForceHasRSICrossing; + + // + eaFilters.filterBasedOnADX = eaFilterBasedOnADX; + eaFilters.forceHasADXTrending = eaForceHasADXTrending; + eaFilters.forceHasADXCrossing = eaForceHasADXCrossing; + + // + eaFilters.filterBasedOnATR = eaFilterBasedOnATR; + eaFilters.forceHasATRTrending = eaForceHasATRTrending; + eaFilters.forceHasATRBreakout = eaForceHasATRBreakout; + + // + eaFilters.filterBasedOnTrend = eaFilterBasedOnTrend; + eaFilters.forceHasTrendDir = eaForceHasTrendDir; + eaFilters.forceHasTrendPlace = eaForceHasTrendPlace; + eaFilters.forceHasTrendChange = eaForceHasTrendChange; + eaFilters.forceHasTrendTrending = eaForceHasTrendTrending; + eaFilters.forceHasTrendRejection = eaForceHasTrendRejection; + eaFilters.forceHasTrendLineInside = eaForceHasTrendLineInside; + eaFilters.forceHasTrendDirOnBothSide = eaForceHasTrendDirOnBothSide; + + // + eaFilters.filterBasedOnDelta = eaFilterBasedOnDelta; + eaFilters.filterBasedOnVolume = eaFilterBasedOnVolume; + eaFilters.filterBasedOnSignalBar = eaFilterBasedOnSignalBar; + eaFilters.filterBasedOnHKSignalBar = eaFilterBasedOnHKSignalBar; + + // +} + +/** + * Handling Time Reporting ... + */ +void HandleTimeReport() +{ + // + if (eaAlert == NULL) + { + return; + } + + // + // Monthly Report .... + if (eaReportNewMonths && + eaTimeTracker.IsNewMonth()) + { + // + string msg = "New Month ..."; + + // + eaAlert.SendAlert(msg); + } + + // + // Weekly Report .... + if (eaReportNewWeeks && + eaTimeTracker.IsNewWeek()) + { + // + string msg = "New Week ..."; + + // + eaAlert.SendAlert(msg); + } + + // + // Daily Report .... + if (eaReportNewDays && + eaTimeTracker.IsNewDay()) + { + // + string msg = "New Day ..."; + + // + eaAlert.SendAlert(msg); + } + + // + // Hourly Report .... + if (eaReportNewHours && + eaTimeTracker.IsNewHour()) + { + // + string msg = "New Hour ..."; + + // + eaAlert.SendAlert(msg); + } +} + +/** + * Update Signal Targets ... + */ +void UpdateSignalTargets(XSignal &signal) +{ + // + bool has = signal.IsValid(); + if (!has) + { + return; + } + + // + // Clean Signal Targets ... + Clean(signal.targets); + + // + // Calculate Requirements ... + double r2r = eaSignalR2R > 0 + ? eaSignalR2R + : 1; + double risk = signal.GetRisk(); + double reward = risk * r2r; + + // + double isLong = IsLong(signal.type); + + // + // Handling Signal TP ... + signal.tp = + isLong + ? signal.entry + reward + : signal.entry - reward; + + // + // Try to Apply Money Management ... + + // + // if (r2r <= 1) + // { + // return; + // } + + // + // XTarget iTarget; + + // // + // // Partial Close 0.5 of Position on Reward 1 ... + // reward = risk * 1; + // iTarget.target = + // isLong + // ? signal.entry + reward + // : signal.entry - reward; + // iTarget.volumeMultiplier = 0.5; + + // // + // AddRef(iTarget, signal.targets); + // iTarget.Clean(); + + // // + // if (r2r <= 2) + // { + // return; + // } + + // + // Making Loop ... + // for (int i = 2; i < ((int)r2r - 1); i++) + // { + // // + // iTarget.Clean(); + + // // + // reward = i * risk; + // iTarget.target = + // isLong + // ? signal.entry + reward + // : signal.entry - reward; + // iTarget.volumeMultiplier = 1 / (r2r - 2); + + // // + // AddRef(iTarget, signal.targets); + // } + + // + // Sort Targets ... + ENUM_X_DIRECTION sortingDir = + isLong + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + ApplySortOnTargets( + sortingDir, + signal.targets // + ); +} + +// \ No newline at end of file diff --git a/Experts/xcatb.test.ea.mq5 b/Experts/xcatb.test.ea.mq5 index cefd7d17..c0bc4cca 100644 --- a/Experts/xcatb.test.ea.mq5 +++ b/Experts/xcatb.test.ea.mq5 @@ -167,22 +167,11 @@ input bool eaSaveLosts = false; // Save Lost Conditions // XCAlert *eaAlert; XCTrade *eaTrade; -XSignal eaSignal; string eaTag = ""; XCVolume *eaVolume; -XTriggerBlock eaTB; -CArrayObj *eaObjects; -XCPOIDrawer *eaDrawer; -XBarTracker eaBarTraker; -X121XCatbInputs eaInputs; XTimeTracker eaTimeTracker; -XCX121XCatbHelper *eaHelper; -XCBarAnalyser *eaBarAnalyser; -XTriggerBlockFilters eaFilters; -X121XCatbConditions eaCatbConditions; +XCXCATBEASignaller *eaSignallers[]; XCXCATBEATradeManager *eaTradeManager; -XCATBEAStrategyConditions eaConditions; -XTriggerBlockValidationRules eaValidations; // // Event Handlers ... @@ -230,13 +219,6 @@ void OnDeinit(const int reason) // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value // REASON_CLOSE 9 Terminal closed - // - // eaObjects.Clear(); - - // - delete eaHelper; - ZeroMemory(eaHelper); - // delete eaAlert; ZeroMemory(eaAlert); @@ -245,29 +227,12 @@ void OnDeinit(const int reason) delete eaTrade; ZeroMemory(eaTrade); - // - delete eaDrawer; - ZeroMemory(eaDrawer); - // delete eaVolume; ZeroMemory(eaVolume); // - delete eaBarAnalyser; - ZeroMemory(eaBarAnalyser); - - // - eaTB.Clean(); - eaSignal.Clean(); - eaSignal.Clean(); - eaFilters.Clean(); - eaBarTraker.Clean(); - eaConditions.Clean(); - eaConditions.Clean(); eaTimeTracker.Clean(); - eaValidations.Clean(); - eaCatbConditions.Clean(); // DestroyTimer(); @@ -278,236 +243,345 @@ void OnDeinit(const int reason) void OnTick() { // - // Handle Tradings ... - bool tradeUsingTriggerBlock = true; - bool tradeUsingMarketConditions1 = true; - - // + // Time Report Handling ... HandleTimeReport(); // - // Handle Position Management / Protections ... + // Position Management / Protections Handling ... eaTradeManager.Manage(); // - eaTB.Clean(); - eaSignal.Clean(); - eaConditions.Clean(); - eaCatbConditions.Clean(); - - // - bool has = false; - int barIndex = 0; - int cBarIndex = 0; - - // - // Check Bar Processing ... - if (!eaBarTraker.CanProcessBar()) - { - return; - } - - // - eaHelper.Check(barIndex); - - // - // Reading Required Bars ... - XOHCL zBar; - XOHCL cBar; - has = zBar.Init( - _Symbol, - _Period, - barIndex // - ); - has = - has && - zBar.GetPreviousBar(cBar); + // Count Signallers ... + bool has = HasChild(eaSignallers); if (!has) { - // - zBar.Clean(); - cBar.Clean(); - - // return; } // - cBarIndex = barIndex + 1; + XGuard guards[]; + XCATBEAStrategyConditions conditions[]; // - // Update All Required Buffers ... - eaHelper.Update(cBarIndex); - - // - // Check Trigger Block Detected or Not ... - if (tradeUsingTriggerBlock) + int count = ArraySize(eaSignallers); + for (int i = 0; i < count; i++) { // - // Trigger Block Detection ... - has = DetectTriggerBlock1( - eaHelper, - eaBarAnalyser, - eaTB, - eaCatbConditions, - eaValidations, - eaFilters, - barIndex, - 10 // Loopback ... + // Retrieve indexed Signaller ... + XCXCATBEASignaller *iSignaller = eaSignallers[i]; + + // + string iSymbol = iSignaller.GetSymbol(); + string iProvider = iSignaller.GetProvider(); + ENUM_TIMEFRAMES iPeriod = iSignaller.GetPeriod(); + + // + // Now we Have to Check Handle Tick Resoult ... + + // + // Requirements ... + XGuard iGuards[]; // Hold Provided Guards ... + XPosition iPositions[]; // Retrieve Signaller Positions ... + XCATBEAStrategyConditions iConditions; // Recieve Triggered Conditions ... + + // + // Reading Signaller Positions ... + eaTradeManager.GetPositions( + iPositions, + iSymbol, + iProvider, + iPeriod // ); // + // Processing Tick for Signaller ... + iSignaller.ProcessTick( + iPositions, + iGuards, + iConditions // + ); + + // + // Check Results ... + has = HasChild(iGuards); if (has) { // - // Wait for Next Bar for anything ... - eaBarTraker.Waits(); - - // - // Prepare Target ... - double targets[]; - for (int i = 1; i <= eaSignalR2R; i++) - { - // - Add( - (double)i, - targets // - ); - } - - // - // Calculate SL Additions ... - double iATR = 0; - if (barIndex > 0 && - barIndex < ArraySize(eaHelper.atrBuffer)) - { - iATR = eaHelper.atrBuffer[barIndex]; - } - double slAdditional = eaSLAtrMultiplier * iATR; - - // - // Preparing Signal ... - has = ToSignal( - eaTB.trigger, - eaTB.signal, - targets, - slAdditional // - ); - - // - // Draw Trigger Block ... - DrawTriggerBlock( - eaTB, - eaDrawer, - eaObjects, - NULL // - ); - - // - // Attach Signal ... - eaSignal = eaTB.signal; - - // - // Check Signal Type ... - bool isLong = IsLong(eaSignal.type); - - // - // Update Entry ... - eaSignal.entry = GetEntry( - eaSignal.symbol, - eaSignal.type // - ); - - // - // Update Signal Targets ... - UpdateSignalTargets(eaSignal); - - // - // Handle Volume Management ... - double iVolume = eaVolume.CalculateVolume(eaSignal); - if (iVolume > X_MIN_VOLUME && - iVolume != eaSignal.volume) - { - eaSignal.volume = iVolume; - } - - // - eaConditions.sl = eaSignal.sl; - eaConditions.tp = eaSignal.tp; - eaConditions.pivot = eaSignal.sl; - eaConditions.time = eaSignal.time; - eaConditions.reward = eaSignalR2R; - eaConditions.point = eaSignal.entry; - eaConditions.entry = eaSignal.entry; - eaConditions.symbol = eaSignal.symbol; - eaConditions.period = eaSignal.period; - eaConditions.setupTime = eaSignal.time; - eaConditions.triggerTime = eaSignal.time; - eaConditions.decisionZone = eaTB.trigger; - eaConditions.provider = eaSignal.provider; - eaConditions.conditions = eaCatbConditions; - eaConditions.type = ToPositionType(eaSignal.type); - eaConditions.dir = - isLong - ? X_DIRECTION_BULLISH - : X_DIRECTION_BEARISH; Copy( - eaSignal.targets, - eaConditions.targets // - ); - eaSignal.conditions = - eaCatbConditions - .GenerateSummary( - false, // Commons ... - true, // Conditions ... - true, // Scores ... - false // Ignore Falses ... - ); - - // - // Execute Signal ... - has = eaTradeManager.Execute( - eaSignal, - eaConditions // + iGuards, + guards, + false // Force Clean ... ); } // - eaTB.Clean(); + // Check Triggered Conditions ... + has = iConditions.IsValid() && + iConditions.IsSetuped() && + iConditions.CanTrigger(); + if (has) + { + // + AddRef( + iConditions, + conditions // + ); + } + + // + // Cleanup Resources ... + Clean(iGuards); + Clean(iPositions); + iConditions.Clean(); } // - // Trade Using Market Conditions ... - if (tradeUsingMarketConditions1) + // Do Actions Based on Provided Info ... + + // + // Guards ... + has = HasChild(guards); + if (has) { // - XBoxZone signalZone; - X121XCatbConditions conditions; - has = DetectSignalZone( - eaDrawer, - eaHelper, - eaBarAnalyser, - signalZone, - conditions, - barIndex // - ); - if (has) - { - // - // Convert Box to Signal ... - } + // Handle Guards Firing ... + } + + // + // Triggers ... + has = HasChild(conditions); + if (has) + { + // + // Handle Conditions Triggering ... } // // Cleanup Resources ... // - zBar.Clean(); - cBar.Clean(); - eaTB.Clean(); - eaSignal.Clean(); - eaConditions.Clean(); - eaCatbConditions.Clean(); + Clean(guards); + Clean(conditions); + + // // + // eaTB.Clean(); + // eaSignal.Clean(); + // eaConditions.Clean(); + // eaCatbConditions.Clean(); + + // // + // bool has = false; + // int barIndex = 0; + // int cBarIndex = 0; + + // // + // // Check Bar Processing ... + // if (!eaBarTraker.CanProcessBar()) + // { + // return; + // } + + // // + // eaHelper.Check(barIndex); + + // // + // // Reading Required Bars ... + // XOHCL zBar; + // XOHCL cBar; + // has = zBar.Init( + // _Symbol, + // _Period, + // barIndex // + // ); + // has = + // has && + // zBar.GetPreviousBar(cBar); + // if (!has) + // { + // // + // zBar.Clean(); + // cBar.Clean(); + + // // + // return; + // } + + // // + // cBarIndex = barIndex + 1; + + // // + // // Update All Required Buffers ... + // eaHelper.Update(cBarIndex); + + // // + // // Check Trigger Block Detected or Not ... + // if (tradeUsingTriggerBlock) + // { + // // + // // Trigger Block Detection ... + // has = DetectTriggerBlock1( + // eaHelper, + // eaBarAnalyser, + // eaTB, + // eaCatbConditions, + // eaValidations, + // eaFilters, + // barIndex, + // 10 // Loopback ... + // ); + + // // + // if (has) + // { + // // + // // Wait for Next Bar for anything ... + // eaBarTraker.Waits(); + + // // + // // Prepare Target ... + // double targets[]; + // for (int i = 1; i <= eaSignalR2R; i++) + // { + // // + // Add( + // (double)i, + // targets // + // ); + // } + + // // + // // Calculate SL Additions ... + // double iATR = 0; + // if (barIndex > 0 && + // barIndex < ArraySize(eaHelper.atrBuffer)) + // { + // iATR = eaHelper.atrBuffer[barIndex]; + // } + // double slAdditional = eaSLAtrMultiplier * iATR; + + // // + // // Preparing Signal ... + // has = ToSignal( + // eaTB.trigger, + // eaTB.signal, + // targets, + // slAdditional // + // ); + + // // + // // Draw Trigger Block ... + // DrawTriggerBlock( + // eaTB, + // eaDrawer, + // eaObjects, + // NULL // + // ); + + // // + // // Attach Signal ... + // eaSignal = eaTB.signal; + + // // + // // Check Signal Type ... + // bool isLong = IsLong(eaSignal.type); + + // // + // // Update Entry ... + // eaSignal.entry = GetEntry( + // eaSignal.symbol, + // eaSignal.type // + // ); + + // // + // // Update Signal Targets ... + // UpdateSignalTargets(eaSignal); + + // // + // // Handle Volume Management ... + // double iVolume = eaVolume.CalculateVolume(eaSignal); + // if (iVolume > X_MIN_VOLUME && + // iVolume != eaSignal.volume) + // { + // eaSignal.volume = iVolume; + // } + + // // + // eaConditions.sl = eaSignal.sl; + // eaConditions.tp = eaSignal.tp; + // eaConditions.pivot = eaSignal.sl; + // eaConditions.time = eaSignal.time; + // eaConditions.reward = eaSignalR2R; + // eaConditions.point = eaSignal.entry; + // eaConditions.entry = eaSignal.entry; + // eaConditions.symbol = eaSignal.symbol; + // eaConditions.period = eaSignal.period; + // eaConditions.setupTime = eaSignal.time; + // eaConditions.triggerTime = eaSignal.time; + // eaConditions.decisionZone = eaTB.trigger; + // eaConditions.provider = eaSignal.provider; + // eaConditions.conditions = eaCatbConditions; + // eaConditions.type = ToPositionType(eaSignal.type); + // eaConditions.dir = + // isLong + // ? X_DIRECTION_BULLISH + // : X_DIRECTION_BEARISH; + // Copy( + // eaSignal.targets, + // eaConditions.targets // + // ); + // eaSignal.conditions = + // eaCatbConditions + // .GenerateSummary( + // false, // Commons ... + // true, // Conditions ... + // true, // Scores ... + // false // Ignore Falses ... + // ); + + // // + // // Execute Signal ... + // has = eaTradeManager.Execute( + // eaSignal, + // eaConditions // + // ); + // } + + // // + // eaTB.Clean(); + // } + + // // + // // Trade Using Market Conditions ... + // if (tradeUsingMarketConditions1) + // { + // // + // XBoxZone signalZone; + // X121XCatbConditions conditions; + // has = DetectSignalZone( + // eaDrawer, + // eaHelper, + // eaBarAnalyser, + // signalZone, + // conditions, + // barIndex // + // ); + // if (has) + // { + // // + // // Convert Box to Signal ... + // } + // } + + // // + // // Cleanup Resources ... + + // // + // zBar.Clean(); + // cBar.Clean(); + // eaTB.Clean(); + // eaSignal.Clean(); + // eaConditions.Clean(); + // eaCatbConditions.Clean(); } // @@ -735,13 +809,6 @@ bool InitVolume() */ void InitRequirements() { - // - // Initial Bar Tracker ... - eaBarTraker.Init( - _Symbol, - _Period // - ); - // // Preparing Tags ... eaTag = @@ -759,40 +826,6 @@ void InitRequirements() eaAlert.SetEnableAlerts(eaEnableAlerts); eaAlert.SetTerminalAlerts(eaTerminalAlerts); - // - // Objects ... - eaObjects = new CArrayObj(); - - // - // Configure XCA ... - eaInputs.Default(); - - // - // Hide all Visible Buffers ... - eaInputs.Hide(); - - // - // we Can make Show all requirements here ... - - // - eaInputs.showPV = true; - eaInputs.showSar = true; - eaInputs.showTrend = true; - eaInputs.showATRBand = true; - eaInputs.showPVGolden = true; - - // - eaHelper = new XCX121XCatbHelper(); - bool isInited = eaHelper.Init( - _Symbol, - _Period, - eaInputs // - ); - - // - eaDrawer = new XCPOIDrawer(); - eaBarAnalyser = new XCBarAnalyser(); - // // EA Trade ... eaTrade = new XCTrade( @@ -881,7 +914,7 @@ void InitRequirements() // // Ignore unused Cases and Extracts only Content ... string iSessionDescriptorStr = ExtractString(sessions[i]); - isInited = IsValid(iSessionDescriptorStr); + bool isInited = IsValid(iSessionDescriptorStr); if (isInited) { // @@ -921,65 +954,125 @@ void InitRequirements() } // - // Fill Validations ... - eaValidations.forceHasSwing = eaForceHasSwing; - eaValidations.forceOBBarType = eaForceOBBarType; - eaValidations.minRequiredOBBar = eaMinRequiredOBBar; - eaValidations.forceFVGBarType = eaForceFVGBarType; - eaValidations.liquidityLoopback = eaLiquidityLoopback; - eaValidations.maxAllowedRange = eaMaxAllowedRange; - eaValidations.minAllowedRange = eaMinAllowedRange; - eaValidations.forceHasFLiquidity = eaForceHasFLiquidity; - eaValidations.forceHasRLiquidity = eaForceHasRLiquidity; - eaValidations.validateGapSequence = eaValidateGapSequence; - eaValidations.minAllowedBlockLength = eaMinAllowedBlockLength; - eaValidations.validateBlockEdgeBreakout = eaValidateBlockEdgeBreakout; + // Initializing Signaller(s) ... + string symbols[]; + Add( + _Symbol, + symbols // + ); + bool hasSymbols = HasChild(symbols); + if (hasSymbols) + { + // + // Prepare Signaller Inputs ... + XCATBEASignallerInputs iSignallerInputs; - // - // Fill Filters ... + // + // Common Configs ... - // - eaFilters.filterBasedOnPV = eaFilterBasedOnPV; - eaFilters.bosLoopback = eaBosLoopback; + // + // Provider Name ... + iSignallerInputs.period = _Period; + iSignallerInputs.provider = "XTRGB"; - // - eaFilters.filterBasedOnSar = eaFilterBasedOnSar; - eaFilters.forceSarSwitched = eaForceSarSwitched; - eaFilters.forceSarOnBothSide = eaForceSarOnBothSide; - eaFilters.forceSarHasBreakout = eaForceSarHasBreakout; - eaFilters.forceSarHasReversalSide = eaForceSarHasReversalSide; + // + // CATB Indicator ... + iSignallerInputs.catbInputs.Default(); + iSignallerInputs.catbInputs.Hide(); - // - eaFilters.filterBasedOnRSI = eaFilterBasedOnRSI; - eaFilters.forceHasRSITrending = eaForceHasRSITrending; - eaFilters.forceHasRSIVPattern = eaForceHasRSIVPattern; - eaFilters.forceHasRSICrossing = eaForceHasRSICrossing; + // + // Trigger Block Validations ... + iSignallerInputs.validations.forceHasSwing = eaForceHasSwing; + iSignallerInputs.validations.forceOBBarType = eaForceOBBarType; + iSignallerInputs.validations.minRequiredOBBar = eaMinRequiredOBBar; + iSignallerInputs.validations.forceFVGBarType = eaForceFVGBarType; + iSignallerInputs.validations.liquidityLoopback = eaLiquidityLoopback; + iSignallerInputs.validations.maxAllowedRange = eaMaxAllowedRange; + iSignallerInputs.validations.minAllowedRange = eaMinAllowedRange; + iSignallerInputs.validations.forceHasFLiquidity = eaForceHasFLiquidity; + iSignallerInputs.validations.forceHasRLiquidity = eaForceHasRLiquidity; + iSignallerInputs.validations.validateGapSequence = eaValidateGapSequence; + iSignallerInputs.validations.minAllowedBlockLength = eaMinAllowedBlockLength; + iSignallerInputs.validations.validateBlockEdgeBreakout = eaValidateBlockEdgeBreakout; - // - eaFilters.filterBasedOnADX = eaFilterBasedOnADX; - eaFilters.forceHasADXTrending = eaForceHasADXTrending; - eaFilters.forceHasADXCrossing = eaForceHasADXCrossing; + // + // Trigger Block Filters ... - // - eaFilters.filterBasedOnATR = eaFilterBasedOnATR; - eaFilters.forceHasATRTrending = eaForceHasATRTrending; - eaFilters.forceHasATRBreakout = eaForceHasATRBreakout; + // + iSignallerInputs.filters.filterBasedOnPV = eaFilterBasedOnPV; + iSignallerInputs.filters.bosLoopback = eaBosLoopback; - // - eaFilters.filterBasedOnTrend = eaFilterBasedOnTrend; - eaFilters.forceHasTrendDir = eaForceHasTrendDir; - eaFilters.forceHasTrendPlace = eaForceHasTrendPlace; - eaFilters.forceHasTrendChange = eaForceHasTrendChange; - eaFilters.forceHasTrendTrending = eaForceHasTrendTrending; - eaFilters.forceHasTrendRejection = eaForceHasTrendRejection; - eaFilters.forceHasTrendLineInside = eaForceHasTrendLineInside; - eaFilters.forceHasTrendDirOnBothSide = eaForceHasTrendDirOnBothSide; + // + iSignallerInputs.filters.filterBasedOnSar = eaFilterBasedOnSar; + iSignallerInputs.filters.forceSarSwitched = eaForceSarSwitched; + iSignallerInputs.filters.forceSarOnBothSide = eaForceSarOnBothSide; + iSignallerInputs.filters.forceSarHasBreakout = eaForceSarHasBreakout; + iSignallerInputs.filters.forceSarHasReversalSide = eaForceSarHasReversalSide; - // - eaFilters.filterBasedOnDelta = eaFilterBasedOnDelta; - eaFilters.filterBasedOnVolume = eaFilterBasedOnVolume; - eaFilters.filterBasedOnSignalBar = eaFilterBasedOnSignalBar; - eaFilters.filterBasedOnHKSignalBar = eaFilterBasedOnHKSignalBar; + // + iSignallerInputs.filters.filterBasedOnRSI = eaFilterBasedOnRSI; + iSignallerInputs.filters.forceHasRSITrending = eaForceHasRSITrending; + iSignallerInputs.filters.forceHasRSIVPattern = eaForceHasRSIVPattern; + iSignallerInputs.filters.forceHasRSICrossing = eaForceHasRSICrossing; + + // + iSignallerInputs.filters.filterBasedOnADX = eaFilterBasedOnADX; + iSignallerInputs.filters.forceHasADXTrending = eaForceHasADXTrending; + iSignallerInputs.filters.forceHasADXCrossing = eaForceHasADXCrossing; + + // + iSignallerInputs.filters.filterBasedOnATR = eaFilterBasedOnATR; + iSignallerInputs.filters.forceHasATRTrending = eaForceHasATRTrending; + iSignallerInputs.filters.forceHasATRBreakout = eaForceHasATRBreakout; + + // + iSignallerInputs.filters.filterBasedOnTrend = eaFilterBasedOnTrend; + iSignallerInputs.filters.forceHasTrendDir = eaForceHasTrendDir; + iSignallerInputs.filters.forceHasTrendPlace = eaForceHasTrendPlace; + iSignallerInputs.filters.forceHasTrendChange = eaForceHasTrendChange; + iSignallerInputs.filters.forceHasTrendTrending = eaForceHasTrendTrending; + iSignallerInputs.filters.forceHasTrendRejection = eaForceHasTrendRejection; + iSignallerInputs.filters.forceHasTrendLineInside = eaForceHasTrendLineInside; + iSignallerInputs.filters.forceHasTrendDirOnBothSide = eaForceHasTrendDirOnBothSide; + + // + iSignallerInputs.filters.filterBasedOnDelta = eaFilterBasedOnDelta; + iSignallerInputs.filters.filterBasedOnVolume = eaFilterBasedOnVolume; + iSignallerInputs.filters.filterBasedOnSignalBar = eaFilterBasedOnSignalBar; + iSignallerInputs.filters.filterBasedOnHKSignalBar = eaFilterBasedOnHKSignalBar; + + // + // Loop Through Symbols for Signalling Initializing ... + int symbolsCount = ArraySize(symbols); + for (int i = 0; i < symbolsCount; i++) + { + // + string iSymbol = symbols[i]; + + // + iSignallerInputs.symbol = iSymbol; + if (iSignallerInputs.IsValid()) + { + // + // Initialize Signaller ... + XCXCATBEASignaller *iSignaller = new XCXCATBEASignaller(iSignallerInputs); + + // + // Add it to the Signallers List ... + Add( + iSignaller, + eaSignallers // + ); + + // + ZeroMemory(iSignaller); + } + } + + // + // Cleanup Resources ... + iSignallerInputs.Clean(); + } // } diff --git a/Libraries/x-saherelm.x-trade.lib.mq5 b/Libraries/x-saherelm.x-trade.lib.mq5 index d36f8748..e100659e 100644 --- a/Libraries/x-saherelm.x-trade.lib.mq5 +++ b/Libraries/x-saherelm.x-trade.lib.mq5 @@ -141,19 +141,6 @@ enum ENUM_X_SIGNAL_EXECUTION_RESULT X_SIGNAL_EXECUTION_FAILED_INVALID_PARAMS, // Invalid Params }; -// -// Available Guard Action ... -enum ENUM_X_GUARD_ACTIONS -{ - X_GUARD_ACTION_NOTHING, // Nothing - X_GUARD_ACTION_HEDGE, // Hedge - X_GUARD_PARTIAL_CLOSE, // Partial Close - X_GUARD_ACTION_TRAIL_STOP, // Trail StopLoss - X_GUARD_ACTION_FORCE_CLOSE, // Force Close - X_GUARD_ACTION_ADD_SUPPORT_SIGNAL, // Add Support Signal - X_GUARD_ACTION_CANCEL_PENDING_ORDERS, // Cancel Pending Orders -}; - // enum ENUM_X_POSITION_TYPES { @@ -2585,320 +2572,6 @@ struct XOnTradeHandlerState } }; -// -// Model Guard Info ... -struct XGuard -{ - // - string symbol; // Trading Symbol ... - string provider; // Signal Provider ... - ENUM_TIMEFRAMES period; // Trading Timeframe ... - ENUM_X_POSITION_TYPES type; // Position Type ... - ENUM_X_GUARD_ACTIONS action; // Which Action to Do ... - - // - double dblPayLoad; - string strPayload; - - // - // Constructor ... - XGuard() - { - Clean(); - } - - // - // Initialize ... - - // - // Global Initializer ... - bool Init( - string mSymbol, // Trading Symbol ... - ENUM_TIMEFRAMES mPeriod, // Trading Timeframe ... - ENUM_X_GUARD_ACTIONS mAction, // Which Action to Do ... - ENUM_X_POSITION_TYPES mType = NULL, // Position Type ... - string mProvider = NULL, // Signal Provider ... - double mDblPayLoad = NULL, - string mStrPayload = NULL // - ) - { - // - type = mType; - symbol = mSymbol; - period = mPeriod; - action = mAction; - provider = mProvider; - dblPayLoad = mDblPayLoad; - strPayload = mStrPayload; - - // - bool result = IsValid(); - - // - return result; - } - - // - // Tools ... - - // - // Cleanup ... - void Clean() - { - // - symbol = NULL; - provider = NULL; - period = NULL; - action = X_GUARD_ACTION_NOTHING; - - // - strPayload = NULL; - dblPayLoad = EMPTY_VALUE; - - // - ZeroMemory(this); - } - - // - // Validate ... - bool IsValid() - { - // - bool result = false; - - // - result = - // - action != X_GUARD_ACTION_NOTHING - // - ; - - // - return result; - } -}; - -// -// Model a Position with all of it's Supports ... -struct XPositionPack -{ - // - ulong ticket; // Main Position's Ticket - - // - XPosition position; // Main Position (if Exists) - - // - int supportOrdersCount; // Supported Orders (Untriggered) - int supportPositionsCount; // Supported Positions - - // - XOrder supportOrders[]; // Supported Orders (Untriggered) - XPosition supportPositions[]; // Supported Positions - - // - // Constructor ... - XPositionPack() - { - Clean(); - } - - // - // Tools ... - - // - // Cleanup ... - void Clean() - { - // - ticket = 0; - - // - position.Clean(); - - // - supportOrdersCount = 0; - supportPositionsCount = 0; - - // - Clean(supportOrders); - Clean(supportPositions); - - // - ZeroMemory(this); - } - - // - // Validate ... - bool IsValid() - { - // - bool result = false; - - // - result = - // - NotEmpty(ticket) && - ( - // - supportOrdersCount > 0 - ? ArraySize(supportOrders) == supportOrdersCount - : true - // - ) - // - && - // - ( - // - supportPositionsCount > 0 - ? ArraySize(supportPositions) == supportPositionsCount - : true - // - ) - // - ; - - // - return result; - } -}; - -// -// Check Position SL Trails Structure ... -struct XTrail -{ - // - ulong ticket; // Position Ticket ... - ENUM_POSITION_TYPE type; // Type ... - datetime time; // Trail Time ... - double before; // SL Value Before Trailing ... - double after; // SL Value After Trailing ... - int level; // Number of Trails SL ... - double profit; // Profit in SL Time ... - - // - // Constructor ... - XTrail() - { - Clean(); - } - - // - // Tools ... - - // - bool Init( - ulong mTicket, // Ticket - ENUM_POSITION_TYPE mType, // Type - double mProfit, // Profit - double mBefore, // Before - double mAfter // After - ) - { - // - Clean(); - - // - type = mType; - after = mAfter; - ticket = mTicket; - before = mBefore; - profit = mProfit; - - // - level++; - - // - time = TimeCurrent(); - - // - return IsValid(); - } - - // - bool Update( - double mSl, // new SL ... - double mProfit // Profit - ) - { - // - bool result = false; - - // - time = TimeCurrent(); - - // - double cAfter = after; - after = mSl; - before = cAfter; - profit = mProfit; - - // - level++; - - // - result = IsValid(); - - // - return result; - } - - // - string GenerateTag() - { - // - string result = NULL; - - // - string ticketLevelStr = ToString(ticket) + "," + ToString(level); - - // - result = Surround( - XSLTrailToken, - ticketLevelStr // - ); - - // - return result; - } - - // - // Cleanup ... - void Clean() - { - // - ticket = 0; - time = 0; - before = 0; - after = 0; - level = 0; - - // - ZeroMemory(this); - } - - // - // Validate ... - bool IsValid() - { - // - bool result = false; - - // - result = - // - ticket > 0 && - time > 0 && - level > 0 - // - ; - - // - return result; - } -}; - // struct XSymbolPositions { @@ -3508,493 +3181,6 @@ struct XSymbolPositions // }; -// -struct XSymbolLastPosition -{ - // - string symbol; - string provider; - datetime time; - - // - XSymbolLastPosition() - { - Clean(); - } - - // - // Tools ... - - void Clean() - { - // - time = NULL; - symbol = NULL; - provider = NULL; - - // - ZeroMemory(this); - } -}; - -// -// an Structure for Holding Positions Data ... -struct XTradeData -{ - // - datetime time; // Issue Time (Open Position) - string symbol; // Trading Symbol - double entry; // Entry Price - double volume; // Volume - string provider; // Signaller - ENUM_TIMEFRAMES period; // Trading Timeframe - ENUM_X_POSITION_TYPES type; // Position Type - - // - ulong ticket; // Position Ticket - double swap; // Swap - double profit; // Profit on Close - double commission; // Commission - double maxDrawdown; // Max Position Drawdown - string message; // Close Reason - datetime endTime; // End Time - - // - XSignal signal; // Signal Object - int pushers; // Signal Pushers - string conditions; // Signal Conditions - - // - // Constructor ... - void XTradeInfo() - { - Clean(); - } - - // - // Filling Trade Handler ... - bool Fill(XSignal &_signal) - { - // - bool result = false; - - // - Clean(); - - // - // Check Signal Validation ... - result = _signal.IsValid(); - if (!result) - { - return result; - } - - // - signal = _signal; - time = _signal.time; - entry = _signal.entry; - symbol = _signal.symbol; - volume = _signal.volume; - period = _signal.period; - provider = _signal.provider; - conditions = _signal.conditions; - type = ToPositionType(_signal.type); - - // - if (_signal.IsExecuted()) - { - ticket = _signal.positionId; - } - - // - return result; - } - - // - // Filling Trade Handler ... - bool Fill(XPosition &_position) - { - // - bool result = false; - - // - Clean(); - - // - // Check Signal Validation ... - result = _position.IsValid(); - if (!result) - { - return result; - } - - // - time = _position.openAt; - symbol = _position.symbol; - entry = _position.entry; - volume = _position.volume; - provider = _position.provider; - period = _position.period; - type = ToPositionType(_position.type); - - // - ticket = _position.ticket; - - // - return result; - } - - // - // Update Data ... - bool Update(XPosition &_position) - { - // - bool result = false; - - // - result = _position.IsValid(); - if (!result) - { - return result; - } - - // - profit = _position.profit; - swap = _position.swap; - - // - if (profit < 0 && - (maxDrawdown == 0 || - MathAbs(profit) > MathAbs(maxDrawdown))) - { - maxDrawdown = profit; - } - - // - return result; - } - - // - // Tools ... - - // - // Cleanup ... - void Clean() - { - // - time = NULL; - type = NULL; - symbol = NULL; - period = NULL; - endTime = NULL; - message = NULL; - provider = NULL; - - // - swap = 0; - entry = 0; - ticket = 0; - profit = 0; - volume = 0; - commission = 0; - maxDrawdown = 0; - - // - signal.Clean(); - - // - ResetTrail(); - ResetRecovery(); - - // - ZeroMemory(this); - } - - // - // Validation ... - bool IsValid() - { - // - bool result = false; - - // - result = - // - ticket > 0 && - IsValid(time) && - IsValid(symbol) && - IsValid(period) - // - ; - - // - return result; - } - - // - // Retrieve Trade Data Age ... - int GetAge() - { - // - int result = -1; - - // - if (!IsValid(symbol) || - !IsValid(time) || - !IsValid(endTime) || - !IsValid(period)) - { - return result; - } - - // - int startIndex = iBarShift( - symbol, - period, - time, - false // - ); - - // - int endIndex = iBarShift( - symbol, - period, - endTime, - false // - ); - - // - result = MathAbs(startIndex - endIndex); - - // - return result; - } - - // - // Check Own of Trade Data ... - // based on Ticket ... - bool IsOwn( - ulong _ticket // - ) - { - // - bool result = false; - - // - result = _ticket == ticket; - - // - return result; - } - - // - // Check Own of Trade Data ... - // based on Symbol/Provider and Period ... - bool IsOwn( - string _symbol, - string _provider, - ENUM_TIMEFRAMES _period, - ENUM_X_POSITION_TYPES _type // - ) - { - // - bool result = false; - - // - result = - // - IsValid(_symbol) && - IsValid(_period) && - IsValid(_provider) && - type != X_POSITION_TYPE_ALL && - type != X_POSITION_TYPE_NONE && - // - type == _type && - period == _period && - symbol == _symbol && - provider == _provider - // - ; - - // - return result; - } - - // - // Data Collector ... - - // - // Get Data File Name ... - string GetFileName() - { - // - string result = NULL; - - // - if (!IsValid()) - { - return result; - } - - // - result = - // - symbol + "\\" + - ToString(type) + "\\" + - (profit >= 0 ? "Profit" : "Loss") + "\\" + - ToString(ticket) + "_" + - ToString(period) + "_" + - ToFormatString(time) - // - ; - - // - return result; - } - - // - // Get Signal File Name ... - string GetSignalFileName() - { - // - string result = NULL; - - // - result = - // - symbol + "\\" + - ToString(type) + "\\" + - provider + "_" + - ToFormatString(time) - // - ; - - // - return result; - } - - // - // Convert(s) To String Representation(s) ... - string ToString( - bool onlySignals = false // - ) - { - // - string result = NULL; - - // - int age = GetAge(); - - // - result = - // - (onlySignals - ? "" - : ToString("Ticket", ticket)) + - ToString("Symbol", symbol) + - ToString("Period", period) + - ToString("Entry", entry) + - ToString("Provider", provider) + - ToString("Type", ToString(type)) + - ToString("Time", time) + - // - // Attach Trade Info ... - (onlySignals - ? "" - : - // - "-------------" + "\n" + - ToString("Volume", volume) + - ToString("Profit", profit) + - ToString("Commission", commission) + - ToString("Swap", swap) + - ToString("Max Drawdown", maxDrawdown) + - ToString("End Time", endTime) + - ToString("Age", age) + - ToString("Message", message) + - "" - // - ) + - // - // Attach Conditions to Signals ... - (!onlySignals - ? "" - : - // - "-------------" + "\n" + - ToString("Pushers", pushers) + - "Conditions:" + "\n" + - "-------------" + "\n" + - conditions + - "" - // - ) + - // - "" - // - ; - - // - return result; - } - - // - // There are some Controlling Situations for each Trade - // which implemented here ... - - // - // Trailing Stop .... - - // - bool allowTrailStop; // Specified Position Can Trail Stop or not - bool ignoreTPOnTrail; // Ignore TP when SL Trailed - bool trailBasedOnProfit; // Do Trail Based on Profit Points - int trailLevel; // Last Trail Level - double trailStartInPoint; // Trail Starts When Profits Growing in Point - double trailStepInPoint; // Profit Must Grows Point to do Trailling - - // - // Reset all Trailing Configurations .... - void ResetTrail() - { - // - trailLevel = 0; - trailStepInPoint = 0; - trailStartInPoint = 0; - allowTrailStop = false; - ignoreTPOnTrail = false; - trailBasedOnProfit = false; - } - - // - // Recovery ... - - // - bool allowRecover; // Allow Recover Specified Position - double recoveryTPPoint; // Recovery TP Point - double recoverySLPoint; // Recovery SL Point - int maxAllowedRecover; // Max Allowed Recovery - int recoveryLevel; // Number of Recovery Signals - double recoveryVolumeMultiplier; // Recovery Volume Multiplier - double recoveryVolume; // Next Recovery Positioin Volume - ENUM_X_POSITION_TYPES recoveryLookingType; // Looking for Next Recovery Type - - // - void ResetRecovery() - { - // - allowRecover = false; - recoveryLevel = 0; - recoveryVolume = 0; - recoveryTPPoint = 0; - recoverySLPoint = 0; - recoveryVolumeMultiplier = 0; - recoveryLookingType = X_POSITION_TYPE_NONE; - } - - // -}; - // // TypeDefs ... diff --git a/XCATBEA/Classes/xcatbea.signaller.class.mq5 b/XCATBEA/Classes/xcatbea.signaller.class.mq5 index e1d0a303..5ffaaf13 100644 --- a/XCATBEA/Classes/xcatbea.signaller.class.mq5 +++ b/XCATBEA/Classes/xcatbea.signaller.class.mq5 @@ -22,8 +22,8 @@ // // Imports ... -#include "../../Classes/x-saherelm.x-alert.class.mq5" #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"; @@ -33,6 +33,527 @@ // // Definitions ... -class XCXCATBEASignaller : XCBaseAlert + +// +struct XCATBEASignallerInputs { + // + // Pros ... + string symbol; + string provider; + ENUM_TIMEFRAMES period; + X121XCatbInputs catbInputs; + XTriggerBlockFilters filters; + XTriggerBlockValidationRules validations; + + // + // Constructor(s) ... + XCATBEASignallerInputs() + { + Clean(); + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + symbol = NULL; + period = NULL; + provider = NULL; + filters.Clean(); + catbInputs.Clean(); + validations.Clean(); + + // + ZeroMemory(this); + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + IsValid(symbol) && + IsValid(period) && + IsValid(provider) && + catbInputs.IsValid(); + + // + return result; + } + + // +}; + +class XCXCATBEASignaller : XCBase +{ + // + // Public ... + public: + // + // Props ... + + // + bool useGuards; // Use Guards or not ... + bool allowDraws; // Allow Draws or not ... + + // + XBarTracker barTraker; // Bar Tracker ... + XCX121XCatbHelper *helper; // XCATB Helper Class instance ... + XCBarAnalyser *barAnalyser; // Bar Analyser ... + XCXCATBEAPOIDrawer *drawer; // POI Drawer ... + XCXCATBEAPOIDetector *detector; // POI Detector ... + + // + 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; + } + + // + // Tick Analyser ... + + /** + * Process Tick ... + */ + void ProcessTick( + XPosition &positions[], + XGuard &guards[], + XCATBEAStrategyConditions &conditions // + ) + { + // + Clean(guards); + conditions.Clean(); + + // + int count = 0; + bool has = false; + int barIndex = 0; + + // + // 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; + } + + // + iConditions.Clean(); + } + + // + // Check Can Trigger ... + has = IsValidIndex(selectedIDX) && + conditions.IsValid() && + conditions.IsSetuped() && + conditions.CanTrigger(); + if (has) + { + // + ArrayRemove( + mConditionsCollection, + selectedIDX, + 1 // + ); + } + else + { + conditions.Clean(); + } + } + + // + // Check Bar Processing ... + if (!barTraker.CanProcessBar()) + { + return; + } + + // + // Check Signal Setups ... + has = DetectSignalSetup(barIndex); + if (has) { + // + barTraker.Waits(); + + // + AddConditionsIfNotExists(); + + // + mConditions.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); + + // + // 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; + } + + // + // 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 ... + barIndex = NormalizeInt(barIndex, 0); + + // + // TODO: Implement this ... + + // + // Cleanup Resources ... + + // + return result; + } + + // + // Protected ... + protected: + // + + /** + * Initialize ... + */ + void Init(XCATBEASignallerInputs &inputs) + { + // + bool has = inputs.IsValid(); + if (!has) + { + return; + } + + // + symbol = inputs.symbol; + period = inputs.period; + provider = inputs.provider; + + // + // Initialize Bar Tracker ... + has = barTraker.Init( + symbol, + period // + ); + if (!has) + { + return; + } + + // + // Initialize Bar Analyser ... + barAnalyser = new XCBarAnalyser(); + + // + // initialize Helper ... + has = helper.Init( + symbol, + period, + inputs.catbInputs // + ); + if (!has) + { + return; + } + + // + mConditions.Clean(); + Clean(mConditionsCollection); + + // + InitPOI(); + } + + /** + * DeInitialize ... + */ + void DeInit() + { + // + 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 = 10 // + ) + { + // + int result = 0; + + // + 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; + } + + // + // Private ... + private: + // + // Props ... + string symbol; + string provider; + ENUM_TIMEFRAMES period; + + // + // Initialize and Configure POI Detector and Drawer ... + void InitPOI() + { + // + // Initialize POI Detector ... + bool has = helper != NULL; + if (has) + { + // + detector = new XCXCATBEAPOIDetector(helper); + + // + // Configure ... + } + + // + // Initialize POI Drawer ... + has = detector != NULL; + if (has) + { + // + drawer = new XCXCATBEAPOIDrawer(detector); + + // + // Configure ... + } + } + + // }; \ No newline at end of file diff --git a/XCATBEA/Classes/xcatbea.x-poi.detector.class.mq5 b/XCATBEA/Classes/xcatbea.x-poi.detector.class.mq5 index 691a4008..7e632612 100644 --- a/XCATBEA/Classes/xcatbea.x-poi.detector.class.mq5 +++ b/XCATBEA/Classes/xcatbea.x-poi.detector.class.mq5 @@ -533,6 +533,21 @@ class XCXCATBEAPOIDetector : public XCBase { } + // + void CleanPivots() + { + // + Clean(invalidPivots); + + // + peakPivot.Clean(); + valePivot.Clean(); + + // + Clean(peakPivots); + Clean(valePivots); + } + // // Pivots ... @@ -1372,21 +1387,6 @@ class XCXCATBEAPOIDetector : public XCBase return result; } - // - void CleanPivots() - { - // - Clean(invalidPivots); - - // - peakPivot.Clean(); - valePivot.Clean(); - - // - Clean(peakPivots); - Clean(valePivots); - } - // void SortPivots() { diff --git a/XCATBEA/Classes/xcatbea.x-trade.manager.class.mq5 b/XCATBEA/Classes/xcatbea.x-trade.manager.class.mq5 index 2b3d3209..bfabdf16 100644 --- a/XCATBEA/Classes/xcatbea.x-trade.manager.class.mq5 +++ b/XCATBEA/Classes/xcatbea.x-trade.manager.class.mq5 @@ -1596,6 +1596,57 @@ class XCXCATBEATradeManager : public XCBaseAlert return result; } + /** + * Retrieve Specified Positions ... + * + * @param positions: XPosition instance Reference Array, which holds Founded Positions ... + * @param symbol: string, Specified Symbol Name ... + * @param provider: string, Specified Provider Name ... + * @param period: ENUM_TIMEFRAMES, Specified Period ... + * + * @return ( int ) + */ + int GetPositions( + XPosition &positions[], + string symbol, + string provider, + ENUM_TIMEFRAMES period // + ) + { + // + int result = 0; + + // + Clean(positions); + + // + bool has = + IsValid(symbol) && + IsValid(period) && + IsValid(provider); + if (!has) + { + return result; + } + + // + result = trader.GetPositions( + positions, + symbol, + provider, + period, + NULL, // All Types ... + true, // Filter By Magic ... + true // Force Clean ... + ); + + // + result = ArraySize(positions); + + // + return result; + } + /** * Handle Position Take Profit ... * diff --git a/XCATBEA/Libraries/xcatbea.lib.mq5 b/XCATBEA/Libraries/xcatbea.lib.mq5 index 6010865c..dd9cd7f5 100644 --- a/XCATBEA/Libraries/xcatbea.lib.mq5 +++ b/XCATBEA/Libraries/xcatbea.lib.mq5 @@ -22,72 +22,35 @@ // // Imports ... -#include "../../Libraries/x-saherelm.common.lib.mq5" -#include "../../Libraries/x-saherelm.x-poi.lib.mq5" -#include "../../Libraries/x-saherelm.x-trade.lib.mq5" -#include "../../Helpers/x-saherelm.x121.xcatb.helper.mq5" +#include "../../Classes/x-saherelm.x-bar.analyser.class.mq5" +#include "../../Classes/x-saherelm.x-poi.drawer.class.mq5" +#include "../Libraries/xcatbea.lib.mq5" // -// Enumeration ... +// Definiions ... // -// Guard Actions ... -enum ENUM_XCATBEA_GUARD_ACTIONS -{ - XCATBEA_GUARD_ACTION_NONE, // Nothing to Do - XCATBEA_GUARD_ACTION_CLOSE, // Close Specified Position - XCATBEA_GUARD_ACTION_CLOSE_ALL, // Close All Positions - XCATBEA_GUARD_ACTION_CLOSE_LONGS, // Close All Long Positions - XCATBEA_GUARD_ACTION_CLOSE_SHORTS, // Close All Short Position - XCATBEA_GUARD_ACTION_PARTIAL_CLOSE, // Partial Close Specified Position - XCATBEA_GUARD_ACTION_TRAIL_STOP, // Trail Stop of Specified Position - XCATBEA_GUARD_ACTION_TRAIL_TARGET, // Trail Target of Specified Position - XCATBEA_GUARD_ACTION_HEDGE, // Hedge Specified Positions -}; +#define XLiquidityToken "XLQ"; +#define XTriggerBlockToken "XTRG"; // -// Definitions ... - -// -// Conditions Struct ... -struct XCATBEAStrategyConditions +struct XTriggerBlock { // // Props ... + XBoxZone ob; // Order Block + XBoxZone fvg; // Fair Value Gap + XOHCL swingBar; // Swing of Trigger + XBoxZone trigger; // Trigger Block + XBoxZone rLiquidity; // Reversal Liquidity + XBoxZone fLiquidity; // Following Liquidity // - string symbol; - ENUM_TIMEFRAMES period; - - // - // Setup Props ... - - // - double sl; - double tp; - double pivot; - double point; - double entry; - double reward; - string provider; - - // - XTarget targets[]; - - // - datetime time; - datetime setupTime; - datetime triggerTime; - - // - ENUM_X_DIRECTION dir; - XBoxZone decisionZone; - ENUM_X_POSITION_TYPES type; - X121XCatbConditions conditions; + XSignal signal; // Pepared Signal // // Constructor ... - XCATBEAStrategyConditions() + XTriggerBlock() { Clean(); } @@ -95,195 +58,76 @@ struct XCATBEAStrategyConditions // // Tools ... - /** - * Cleaning Up ... - */ + // + // Cleanup ... void Clean() { // - sl = 0; - tp = 0; - pivot = 0; - point = 0; - entry = 0; - reward = 0; - - // - symbol = NULL; - period = NULL; - provider = NULL; - - // - time = NULL; - setupTime = NULL; - triggerTime = NULL; - - // - Clean(targets); - - // - conditions.Clean(); - decisionZone.Clean(); - - // - dir = X_DIRECTION_NONE; - type = X_POSITION_TYPE_NONE; + ob.Clean(); + fvg.Clean(); + signal.Clean(); + trigger.Clean(); + swingBar.Clean(); + rLiquidity.Clean(); + fLiquidity.Clean(); // ZeroMemory(this); } // - // Signalling ... - - /** - * Validate ... - * - * @return ( bool ) - */ + // Validate ... bool IsValid() { // bool result = false; // - result = IsSpecifiedValid(symbol) && - IsSpecifiedValid(period) && - IsSpecifiedValid(time); - - // - return result; - } - - /** - * Check Conditions Has Valid Bullish Signal ... - * - * @return ( bool ) - */ - bool HasBullishSignal() - { - // - bool result = false; - - // - result = - (sl > 0 || - tp > 0) && - IsValid() && - HasDirection(dir); - if (!result) - { - return result; - } - - // - result = - IsBullish(dir); - - // - return result; - } - - /** - * Check Conditions Has Valid Bearish Signal ... - * - * @return ( bool ) - */ - bool HasBearishSignal() - { - // - bool result = false; - - // - result = - (sl > 0 || - tp > 0) && - IsValid() && - HasDirection(dir); - if (!result) - { - return result; - } - - // - result = - IsBearish(dir); + result = ob.IsValid() && + fvg.IsValid() && + trigger.IsValid(); // return result; } // - // Setting Up and Triggering Up ... - - /** - * Check Condition is Setting Up ... - * - * @param dir: ENUM_X_DIRECTION member, Setting Up Direction ... - * - * @return ( bool ) - */ - bool IsSetuped() + bool IsBullish() { - // - bool result = false; - - // - result = IsValid(setupTime) && - HasDirection(dir); - if (!result) - { - return result; - } - - // - return result; + return IsValid() && + ob.IsBullish(); } - /** - * Calculate Setup Age ... - * - * @return ( int ) - */ - int GetSetupAge() + // + bool IsBearish() { - // - int result = 0; - - // - if (!IsSetuped()) - { - return result; - } - - // - result = (int)(TimeCurrent() - setupTime) / PeriodSeconds(period); - - // - return result; + return IsValid() && + ob.IsBearish(); } - /** - * Detect How we Can Trigger Signal ... - * - * @return ( bool ) - */ - bool CanTrigger() + // + int ToIndex() + { + return trigger.ToIndex(); + } + + // + int FromIndex() + { + return trigger.FromIndex(); + } + + // + ENUM_X_DIRECTION GetDirection() { // - bool result = false; + ENUM_X_DIRECTION result = X_DIRECTION_NONE; // - result = - // - sl > 0 && - IsValid(symbol) && - IsValid(period) && - IsValid(triggerTime) && - type != X_POSITION_TYPE_ALL && - type != X_POSITION_TYPE_NONE - // - ; + if (IsValid()) + { + result = ob.dir; + } // return result; @@ -291,3 +135,3085 @@ struct XCATBEAStrategyConditions // }; + +// +// Trigger Block Validation Rules ... +struct XTriggerBlockValidationRules +{ + // + // Props ... + bool forceHasSwing; // Force Block to Has Propper Swing ... + bool forceOBBarType; // Force Order Block to Has InDirectional Bars ... + int minRequiredOBBar; // Min Required OB Bar ... + bool forceFVGBarType; // Force Fair Value Gaps Bars Type ... + int liquidityLoopback; // Liquidity Detection Loopback ... + double maxAllowedRange; // Max Allowed Order Block Range ... + double minAllowedRange; // Min Allowed Order Block Range ... + bool forceHasFLiquidity; // Force Order Block To Has Reversal Liquidity ... + bool forceHasRLiquidity; // Force Order Block to Has Following Liquidity ... + bool validateGapSequence; // Validate Fair Value Gaps Bar Sequences ... + int minAllowedBlockLength; // Min Allowed Block Length ... + bool validateBlockEdgeBreakout; // Validate Order Block Edge Breakeout ... + + // + // Constructor(s) ... + XTriggerBlockValidationRules() + { + Clean(); + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + maxAllowedRange = 0; + minAllowedRange = 0; + minRequiredOBBar = 0; + liquidityLoopback = 0; + forceHasSwing = false; + forceOBBarType = false; + forceFVGBarType = false; + minAllowedBlockLength = 0; + forceHasFLiquidity = false; + forceHasRLiquidity = false; + validateGapSequence = false; + validateBlockEdgeBreakout = false; + + // + ZeroMemory(this); + } +}; + +// +// Trigger Block Filters ... +struct XTriggerBlockFilters +{ + // + // Props ... + bool filterBasedOnPV; // Filter Based On PV ... + bool filterBasedOnSar; // Filter Based On SAR ... + bool filterBasedOnRSI; // Filter Based On RSI ... + bool filterBasedOnADX; // Filter Based On ADX ... + bool filterBasedOnATR; // Filter Based On ATR ... + bool filterBasedOnTrend; // Filter Based On Trend ... + bool filterBasedOnDelta; // Filter Based On Delta ... + bool filterBasedOnVolume; // Filter Based On Volume ... + bool filterBasedOnSignalBar; // Filter Based on Signal Bar ... + bool filterBasedOnHKSignalBar; // Filter Based On HK Signal Bar ... + + // + int bosLoopback; // PV Based Filtering BOS Lookup ... + + // + bool forceSarSwitched; // SAR Switched on Sides for Filtering ... + bool forceSarOnBothSide; // SAR Check on Both Sides for Filtering ... + bool forceSarHasBreakout; // SAR Must SAR Must Breakout ... + bool forceSarHasReversalSide; // SAR Must SAR Must Has Reversal Direction ... + + // + bool forceHasRSITrending; // RSI Must Has Trending ... + bool forceHasRSIVPattern; // RSI Must Has Pattern ... + bool forceHasRSICrossing; // RSI Must Has Crossing Levels ... + + // + bool forceHasADXTrending; // ADX Must Has Trending ... + bool forceHasADXCrossing; // ADX Must Has Crossing +DI/-DI ... + + // + bool forceHasATRTrending; // ATR Must Has Trending ... + bool forceHasATRBreakout; // ATR Must Has Breakout ... + + // + bool forceHasTrendDir; // TREND Must Has Following Direction ... + bool forceHasTrendPlace; // TREND Place Based Filtering ... + bool forceHasTrendChange; // TREND Change Filtering ... + bool forceHasTrendTrending; // TREND Must Has Trending ... + bool forceHasTrendRejection; // TREND Line Must Rejected ... + bool forceHasTrendLineInside; // TREND Line has Inside ... + bool forceHasTrendDirOnBothSide; // TREND Must Has Following Direction in Both Side ... + + // + // Constructor(s) ... + XTriggerBlockFilters() + { + Clean(); + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + filterBasedOnPV = false; + filterBasedOnSar = false; + filterBasedOnRSI = false; + filterBasedOnADX = false; + filterBasedOnATR = false; + filterBasedOnTrend = false; + filterBasedOnDelta = false; + filterBasedOnVolume = false; + filterBasedOnSignalBar = false; + filterBasedOnHKSignalBar = false; + + // + bosLoopback = 0; + + // + forceSarSwitched = false; + forceSarOnBothSide = false; + forceSarHasBreakout = false; + forceSarHasReversalSide = false; + + // + forceHasRSITrending = false; + forceHasRSIVPattern = false; + forceHasRSICrossing = false; + + // + forceHasADXTrending = false; + forceHasADXCrossing = false; + + // + forceHasATRTrending = false; + forceHasATRBreakout = false; + + // + forceHasTrendDir = false; + forceHasTrendPlace = false; + forceHasTrendChange = false; + forceHasTrendTrending = false; + forceHasTrendRejection = false; + forceHasTrendLineInside = false; + forceHasTrendDirOnBothSide = false; + + // + ZeroMemory(this); + } +}; + +// +// Extensions ... + +/** + * Detect Trigger Block ... + * + * @param helper: XCX121XCatbHelper instance pointer ... + * @param barAnalyser: XCBarAnalyser instance pointer ... + * @param triggerBlock: XTriggerBlock Refrence, holds Detected Trigger Block ... + * @param conditions: X121XCatbConditions Refrence, holds Trigger Block Conditions ... + * @param validations: XTriggerBlockValidationRules Refrence, Provides Trigger Block Validation Rules ... + * @param filters: XTriggerBlockFilters Refrence, Provides Trigger Block Filters ... + * @param barIndex: int, Bar Index ... + * @param loopback: int, Loopback for Conditions reading ... + * + * @return ( bool ) + */ +bool DetectTriggerBlock1( + XCX121XCatbHelper *helper, + XCBarAnalyser *barAnalyser, + XTriggerBlock &triggerBlock, + X121XCatbConditions &conditions, + XTriggerBlockValidationRules &validations, + XTriggerBlockFilters &filters, + int barIndex = 0, + int loopback = 10 // +) +{ + // + bool result = false; + + // + // Normalize Args ... + conditions.Clean(); + triggerBlock.Clean(); + barIndex = NormalizeInt(barIndex, 0); + loopback = NormalizeInt(loopback, 0); + + // + // Validate Args ... + result = + helper != NULL && + barAnalyser != NULL; + if (!result) + { + return result; + } + + // + int zIDX = 0; + int cIDX = zIDX + 1; + int pIDX = cIDX + 1; + int p2IDX = pIDX + 1; + int p3IDX = p2IDX + 1; + int p4IDX = p3IDX + 1; + + // + bool has = false; + string symbol = helper.GetSymbol(); + ENUM_TIMEFRAMES period = helper.GetPeriod(); + + // + // Initial Requirements ... + + // + // Required Bars ... + XOHCL zBar; + XOHCL cBar; + result = + result && + zBar.Init( + symbol, + period, + barIndex // + ); + result = + result && + zBar.GetPreviousBar(cBar); + + // + // Here we Must Detect Order Block ... + // then Detect FVG ... + // then Prepare Trigger Box ... + + // + // Select Application Bar ... + XOHCL iBar; + if (barIndex == 0) + { + iBar = cBar; + } + else if (barIndex > 0) + { + iBar = zBar; + } + iBar = cBar; + result = + result && + iBar.IsValid(); + + // + // Detect Order Block ... + result = + result && + barAnalyser + .IsOB( + iBar, + triggerBlock.ob, + false, + false // + ); + + // + // Detect Fair Value Gap ... + result = + result && + barAnalyser + .IsFVG( + iBar, + triggerBlock.fvg, + false // + ); + + // + // Check Result and Create Trigger Box based on it ... + if (result) + { + // + triggerBlock.trigger = triggerBlock.ob; + triggerBlock.trigger.type = XTriggerBlockToken; + + // + // Update Upper and Lower ... + int toIDX = triggerBlock.ob.ToIndex(); + int fromIDX = triggerBlock.ob.FromIndex(); + + // + iBar.Clean(); + result = iBar.Init( + symbol, + period, + toIDX // + ); + if (result) + { + // + double iLL = iBar.FindLowest(fromIDX - toIDX, MODE_LOW); + double iHH = iBar.FindHighest(fromIDX - toIDX, MODE_HIGH); + + // + triggerBlock.trigger.upper = MathMax(iHH, triggerBlock.trigger.upper); + triggerBlock.trigger.lower = MathMin(iLL, triggerBlock.trigger.lower); + } + + // + iBar.Clean(); + } + + // + // Apply Validations ... + if (result) + { + // + result = ValidateTriggerBlock( + helper, + barAnalyser, + triggerBlock, + conditions, + validations, + barIndex, + loopback // + ); + + // + if (!result) + { + triggerBlock.Clean(); + } + } + + // + // Apply Filtering ... + if (result) + { + // + result = FilterTriggerBlock( + helper, + barAnalyser, + triggerBlock, + conditions, + filters, + barIndex, + loopback // + ); + + // + if (!result) + { + triggerBlock.Clean(); + } + } + + // + // Summarizing Result ... + result = + result && + triggerBlock.IsValid(); + + // + // Preparing Signal ... + if (result) + { + // + } + + // + // Cleanup Resources ... + + // + iBar.Clean(); + zBar.Clean(); + cBar.Clean(); + + // + if (!result) + { + triggerBlock.Clean(); + } + + // + return result; +} + +/** + * Validate a Trigger Block ... + * + * @param helper: XCX121XCatbHelper instance pointer ... + * @param barAnalyser: XCBarAnalyser instance pointer ... + * @param triggerBlock: XTriggerBlock Refrence, Trigger Block ... + * @param conditions: X121XCatbConditions Refrence, Trigger Block Conditions ... + * @param validations: XTriggerBlockValidationRules Refrence, Provides Trigger Block Validation Rules ... + * @param barIndex: int, Bar Index ... + * @param loopback: int, Loopback for Conditions reading ... + * + * @return ( bool ) + */ +bool ValidateTriggerBlock( + XCX121XCatbHelper *helper, + XCBarAnalyser *barAnalyser, + XTriggerBlock &triggerBlock, + X121XCatbConditions &conditions, + XTriggerBlockValidationRules &validations, + int barIndex = 0, + int loopback = 10 // +) +{ + // + bool result = false; + + // + // Checking Conditions ... + + // + // Normalize Args ... + conditions.Clean(); + barIndex = NormalizeInt(barIndex, 0); + loopback = NormalizeInt(loopback, 0); + + // + // Validate Args ... + result = + helper != NULL && + barAnalyser != NULL && + triggerBlock.IsValid(); + if (!result) + { + return result; + } + + // + // Reading Market Conditions ... + result = helper.GetConditions( + conditions, + barIndex, + loopback // + ); + if (!result) + { + // + conditions.Clean(); + + // + return result; + } + + // + int zIDX = 0; + int cIDX = zIDX + 1; + int pIDX = cIDX + 1; + int p2IDX = pIDX + 1; + int p3IDX = p2IDX + 1; + int p4IDX = p3IDX + 1; + + // + XOHCL iBar; + int count = 0; + int toIDX = -1; + int fromIDX = -1; + bool has = false; + bool isBullish = triggerBlock.IsBullish(); + bool isBearish = triggerBlock.IsBearish(); + double points = GetPoints(triggerBlock.ob.symbol); + ENUM_X_DIRECTION iDir = triggerBlock.GetDirection(); + + // + // Checking Conditions ... + + // + // Range Validation ... + + // + // Max Allowed OB Range ... + if (result && + validations.maxAllowedRange > 0) + { + // + double iRange = triggerBlock.ob.GetRange(); + result = iRange <= (validations.maxAllowedRange * points); + } + + // + // Min Allowed OB Range ... + if (result && + validations.minAllowedRange > 0) + { + // + double iRange = triggerBlock.ob.GetRange(); + result = iRange >= (validations.maxAllowedRange * points); + } + + // + // Has Swing ... + if (result && + validations.forceHasSwing) + { + // + bool isSwing = false; + toIDX = triggerBlock.ToIndex(); + fromIDX = triggerBlock.FromIndex(); + ENUM_X_DIRECTION swingDir = X_DIRECTION_NONE; + for (int i = toIDX; i <= fromIDX; i++) + { + // + // Initialize iBar ... + has = iBar.Init( + conditions.symbol, + conditions.period, + i // + ); + isSwing = + has && + barAnalyser + .IsSimpleSwing( + iBar, + swingDir // + ); + if (isSwing && + swingDir == iDir) + { + break; + } + + // + iBar.Clean(); + } + + // + result = + isSwing && + iBar.IsValid() && + swingDir == iDir; + if (result) + { + // + // Initialize Swing Bar ... + result = triggerBlock + .swingBar + .Init( + iBar.symbol, + iBar.period, + iBar.Index() + 2 // + ); + } + + // + iBar.Clean(); + } + + // + // Force FVG Bar Types ... + if (result && + validations.forceFVGBarType) + { + // + toIDX = triggerBlock.fvg.ToIndex(); + fromIDX = triggerBlock.fvg.FromIndex(); + for (int i = toIDX; i < fromIDX; i++) + { + // + // Initialize iBar ... + result = iBar.Init( + conditions.symbol, + conditions.period, + i // + ); + result = + result && + iDir == iBar.GetDirection(); + + // + iBar.Clean(); + + // + if (!result) + { + break; + } + } + + // + iBar.Clean(); + } + + // + // Force OB Start By InDirectional Bars ... + if (result && + validations.forceOBBarType) + { + // + count = 0; + fromIDX = triggerBlock.fvg.FromIndex() + 1; + int sIDX = fromIDX; + has = true; + while (has) + { + // + // Initialize iBar .. + has = iBar.Init( + conditions.symbol, + conditions.period, + fromIDX // + ); + has = has && + iDir == Opposit(iBar.GetDirection()); + if (has) + { + count++; + } + + // + fromIDX++; + } + + // + int required = + validations.minRequiredOBBar > 0 + ? validations.minRequiredOBBar + : 1; + + // + result = count >= required; + + // + // Update Trigger Block Box based on OB Bar Types ... + if (result) + { + // + result = iBar.Init( + conditions.symbol, + conditions.period, + sIDX // + ); + if (result) + { + // + datetime iFrom = GetBarTime( + conditions.symbol, + conditions.period, + sIDX + count // + ); + double iLL = iBar.FindLowest(count, MODE_LOW); + double iHH = iBar.FindHighest(count, MODE_HIGH); + + // + triggerBlock.trigger.from = iFrom; + triggerBlock.trigger.upper = MathMax(iHH, triggerBlock.trigger.upper); + triggerBlock.trigger.lower = MathMin(iLL, triggerBlock.trigger.lower); + } + } + + // + iBar.Clean(); + } + + // + // Force Fair Value Gap to Following Sequence ... + if (result && + validations.validateGapSequence) + { + // + XOHCL iPBar; + toIDX = triggerBlock.fvg.ToIndex(); + fromIDX = triggerBlock.fvg.FromIndex() - 1; + for (int i = toIDX; i < fromIDX; i++) + { + // + result = iBar.Init( + conditions.symbol, + conditions.period, + i // + ); + result = + result && + iBar.GetPreviousBar(iPBar); + result = + result && + (isBullish + ? iBar.low > iPBar.low + : iBar.high < iPBar.high); + if (!result) + { + break; + } + + // + iBar.Clean(); + iPBar.Clean(); + } + + // + iBar.Clean(); + iPBar.Clean(); + } + + // + // Validate OB Edge Breakeout Using Gaps End Bar ... + if (result && + validations.validateBlockEdgeBreakout) + { + // + // Initialize Gap End Bar ... + toIDX = triggerBlock.fvg.ToIndex(); + result = iBar.Init( + conditions.symbol, + conditions.period, + toIDX // + ); + + // + result = + result && + (isBullish + ? iBar.open < triggerBlock.ob.upper && + iBar.close > triggerBlock.ob.upper + : iBar.open > triggerBlock.ob.lower && + iBar.close < triggerBlock.ob.lower); + + // + // Here we Can Apply Edge Breakout Using Fibo ... + + // + iBar.Clean(); + } + + // + // Force Block to Has Liquidity ... + if (result && + validations.liquidityLoopback > 0 && + (validations.forceHasFLiquidity || + validations.forceHasRLiquidity)) + { + // + toIDX = triggerBlock.ToIndex(); + fromIDX = triggerBlock.FromIndex(); + ENUM_X_DIRECTION iLiqDir = X_DIRECTION_NONE; + for (int i = toIDX; i < fromIDX + validations.liquidityLoopback; i++) + { + // + // Initialize iBar ... + has = iBar.Init( + conditions.symbol, + conditions.period, + i // + ); + has = + has && + barAnalyser + .IsRejected( + iBar, + iLiqDir, + false, // Force Bar Type ... + true // Force Fibo Pressure ... + ); + + // + bool isFLiq = + has && + iLiqDir == iDir; + if (isFLiq && + validations.forceHasFLiquidity && + !triggerBlock.fLiquidity.IsValid()) + { + // + FillLiquidity( + iBar, + iLiqDir, + triggerBlock.fLiquidity, + triggerBlock.trigger.to // + ); + } + + // + bool isRLiq = + has && + iLiqDir == Opposit(iDir); + if (isRLiq && + validations.forceHasRLiquidity && + !triggerBlock.rLiquidity.IsValid()) + { + // + FillLiquidity( + iBar, + iLiqDir, + triggerBlock.rLiquidity, + triggerBlock.trigger.to // + ); + } + + // + // Here We Can Apply Liquidity Validations ... + ValidateTriggerBlockLiquidities( + helper, + barAnalyser, + triggerBlock, + conditions, + validations // + ); + + // + // Check Liquidities ... + has = (!validations.forceHasFLiquidity + ? true + : triggerBlock.fLiquidity.IsValid()) && + (!validations.forceHasRLiquidity + ? true + : triggerBlock.rLiquidity.IsValid()); + + // + iBar.Clean(); + + // + if (has) + { + break; + } + } + + // + // Check Result ... + result = (!validations.forceHasFLiquidity + ? true + : triggerBlock.fLiquidity.IsValid()) && + (!validations.forceHasRLiquidity + ? true + : triggerBlock.rLiquidity.IsValid()); + + // + iBar.Clean(); + } + + // + // Validating Block Length Based on Direction ... + if (result && + validations.minAllowedBlockLength) + { + // + count = 0; + fromIDX = triggerBlock.FromIndex(); + int sIDX = fromIDX; + has = true; + while (has) + { + // + // Initialize iBar ... + has = iBar.Init( + conditions.symbol, + conditions.period, + sIDX // + ); + + // + has = + has && + (isBullish + ? iBar.low > triggerBlock.trigger.lower + : iBar.high < triggerBlock.trigger.upper); + + // + if (!has) + { + break; + } + + // + sIDX++; + count++; + iBar.Clean(); + } + + // + result = + iBar.IsValid() && + count >= validations.minAllowedBlockLength; + if (result) + { + // + // Update Trigger Block ... + bool usaMinAllowedForBlockLength = false; + if (usaMinAllowedForBlockLength) + { + fromIDX = fromIDX + validations.minAllowedBlockLength; + } + else + { + fromIDX = sIDX - 1; + } + + // + triggerBlock.trigger.from = GetBarTime( + conditions.symbol, + conditions.period, + fromIDX // + ); + } + + // + iBar.Clean(); + } + + // + if (!result) + { + triggerBlock.Clean(); + } + + // + // Summarize result ... + result = triggerBlock.IsValid(); + + // + // Cleanup Resources ... + + // + iBar.Clean(); + + // + if (!result) + { + // + conditions.Clean(); + triggerBlock.Clean(); + } + + // + return result; +} + +/** + * Filter a Trigger Block ... + * + * @param helper: XCX121XCatbHelper instance pointer ... + * @param barAnalyser: XCBarAnalyser instance pointer ... + * @param triggerBlock: XTriggerBlock Refrence, Trigger Block ... + * @param conditions: X121XCatbConditions Refrence, Trigger Block Conditions ... + * @param filters: XTriggerBlockFilters Refrence, Provides Trigger Block Filters ... + * @param barIndex: int, Bar Index ... + * @param loopback: int, Loopback for Conditions reading ... + * + * @return ( bool ) + */ +bool FilterTriggerBlock( + XCX121XCatbHelper *helper, + XCBarAnalyser *barAnalyser, + XTriggerBlock &triggerBlock, + X121XCatbConditions &conditions, + XTriggerBlockFilters &filters, + int barIndex = 0, + int loopback = 10 // +) +{ + // + bool result = false; + + // + // Checking Conditions ... + + // + // Normalize Args ... + conditions.Clean(); + barIndex = NormalizeInt(barIndex, 0); + loopback = NormalizeInt(loopback, 0); + + // + // Validate Args ... + result = + helper != NULL && + barAnalyser != NULL && + triggerBlock.IsValid(); + if (!result) + { + return result; + } + + // + // Reading Market Conditions ... + result = helper.GetConditions( + conditions, + barIndex, + loopback // + ); + if (!result) + { + // + conditions.Clean(); + + // + return result; + } + + // + int zIDX = 0; + int cIDX = zIDX + 1; + int pIDX = cIDX + 1; + int p2IDX = pIDX + 1; + int p3IDX = p2IDX + 1; + int p4IDX = p3IDX + 1; + + // + XOHCL iBar; + int toIDX = -1; + int fromIDX = -1; + bool has = false; + bool isBullish = triggerBlock.IsBullish(); + bool isBearish = triggerBlock.IsBearish(); + double points = GetPoints(triggerBlock.ob.symbol); + ENUM_X_DIRECTION iDir = triggerBlock.GetDirection(); + + // + // Checking Conditions ... + + // + // Filter Based On PV ... + if (result && + filters.filterBasedOnPV) + { + // + // For PV Filtering ... + + // + // Detect BOS ... + + // + // When Loopback for BOS has Specified Value ... + // we Lookup for BOS on Specific Period ... + if (filters.bosLoopback > 0) + { + // + has = true; + int fBOSIDX = -1; + int rBOSIDX = -1; + bool isBOS = false; + bool isFBOS = false; + bool isRBOS = false; + bool isPeakOverLast = false; + bool isValeUnderLast = false; + toIDX = triggerBlock.ob.ToIndex(); + fromIDX = triggerBlock.ob.FromIndex(); + int sIDX = fromIDX; + while (has) + { + // + double iPeak = helper.GetPeak(sIDX); + double iPPeak = helper.GetPeak(sIDX + 1); + + // + double iVale = helper.GetVale(sIDX); + double iPVale = helper.GetVale(sIDX + 1); + + // + isPeakOverLast = + iPeak > 0 && + iPeak > iPPeak; + + // + isValeUnderLast = + iVale > 0 && + iVale < iPVale; + + // + isFBOS = + isBullish + ? isPeakOverLast + : isValeUnderLast; + if (isFBOS) + { + fBOSIDX = sIDX; + } + + // + isRBOS = + isBullish + ? isValeUnderLast + : isPeakOverLast; + if (isRBOS) + { + rBOSIDX = sIDX; + } + + // + isBOS = + (isBullish && + isPeakOverLast) || + (isBearish && + isValeUnderLast); + if (isBOS) + { + break; + } + + // + sIDX++; + has = !isBOS && + sIDX < fromIDX + filters.bosLoopback; + } + + // + isFBOS = IsValidIndex(fBOSIDX); + isRBOS = IsValidIndex(rBOSIDX); + + // + result = isBOS && + isFBOS && + !isRBOS; + } + + // + // When Loopback for BOS has not Specified Value ... + // we Lookup for BOS on GAP End Bar ... + if (filters.bosLoopback <= 0) + { + // + toIDX = triggerBlock.ToIndex(); + + // + // Initialize iBar ... + result = iBar.Init( + conditions.symbol, + conditions.period, + toIDX // + ); + result = + result && + (isBullish ? iBar.high > helper.GetPeak(toIDX + 1) + : iBar.low < helper.GetVale(toIDX + 1)); + } + } + + // + // Filter Based on SAR ... + if (result && + filters.filterBasedOnSar) + { + // + toIDX = triggerBlock.ToIndex(); + fromIDX = triggerBlock.FromIndex(); + + // + double iSarState = helper.GetSarState(toIDX); + double iPSarState = helper.GetSarState(toIDX + 1); + + // + double iFSarState = helper.GetSarState(fromIDX); + double iPFSarState = helper.GetSarState(fromIDX + 1); + + // + bool isSarBullish = + iSarState > 0; + + // + bool isSarBearish = + iSarState < 0; + + // + bool isFSarBullish = + iFSarState > 0; + + // + bool isFSarBearish = + iFSarState < 0; + + // + bool isSarSwitchedToBullish = + iSarState > 0 && + iPSarState <= 0; + + // + bool isSarSwitchedToBearish = + iSarState < 0 && + iPSarState >= 0; + + // + bool isFSarSwitchedToBullish = + iFSarState > 0 && + iPFSarState <= 0; + + // + bool isFSarSwitchedToBearish = + iFSarState < 0 && + iPFSarState >= 0; + + // + // Creating Filters ... + + // + bool isToFilterPassed = + !filters.forceSarSwitched + ? (isBullish + ? isSarBullish + : isSarBearish) + : (isBullish + ? isSarSwitchedToBullish + : isSarSwitchedToBearish); + + // + bool isFromFilterPassed = + !filters.forceSarSwitched + ? (isBullish + ? isFSarBullish + : isFSarBearish) + : (isBullish + ? isFSarSwitchedToBullish + : isFSarSwitchedToBearish); + + // + result = + !filters.forceSarOnBothSide + ? isToFilterPassed + : isToFilterPassed && + isFromFilterPassed; + + // + // Check Sar Has Reversal Direction inside Trigger Block ... + if (result && + filters.forceSarHasReversalSide) + { + // + toIDX = triggerBlock.ToIndex(); + fromIDX = triggerBlock.FromIndex(); + for (int i = toIDX; i < fromIDX; i++) + { + // + double iSarState = helper.GetSarState(i); + + // + has = + isBullish + ? iSarState > 0 + : iSarState < 0; + if (has) + { + break; + } + } + + // + result = has; + } + + // + // Force Sar Breakouts ... + // in this Senario Sar must in following Direction and + // there is not any Switches ... + // but must breakout Bar the last in Reversal Direction + // of Sar ... + if (result && + filters.forceSarHasBreakout) + { + // + bool isSarBullishStart = + // + ( + // + // Current SAR is Directional ... + conditions.isSarBullish && + // + // Previous InDirectional Sar Exists ... + helper.lastSarBearish.IsValid() && + // + // Current Close is Over previous Sar ... + conditions.bars[cIDX].close > helper.lastSarBearish.after && + // + // Before Close is not Over previous Sar ... + conditions.bars[pIDX].close <= helper.lastSarBearish.after + // + ) + // + ; + + // + bool isSarBearishStart = + // + ( + // + // Current SAR is Directional ... + conditions.isSarBearish && + // + // Previous InDirectional Sar Exists ... + helper.lastSarBullish.IsValid() && + // + // Current Close is Under previous ... + conditions.bars[cIDX].close < helper.lastSarBullish.after && + // + // Before Close is not Under previous ... + conditions.bars[pIDX].close >= helper.lastSarBullish.after + // + ) + // + ; + + // + result = + isBullish + ? isSarBullishStart + : isSarBearishStart; + } + } + + // + // Filter Based On RSI ... + if (result && + filters.filterBasedOnRSI) + { + // + // Here We Can Apply RSI Filters ... + // Since RSI Filters must be Check on FVG Bars ... + // we Have to Loop back Based on FVG Bars to Detect Conditions ... + double rsiTrend = (conditions.rsiOBLevel + conditions.rsiOSLevel) / 2; + + // + toIDX = triggerBlock.fvg.ToIndex(); + fromIDX = triggerBlock.fvg.FromIndex(); + + // + // Filter Using RSI Trending ... + if (result && + filters.forceHasRSITrending) + { + // + for (int i = toIDX; i < fromIDX; i++) + { + // + double iRSI = helper.GetRSI(i); + double iPRSI = helper.GetRSI(i + 1); + + // + has = + (isBullish + ? (iRSI > rsiTrend && + iRSI > iPRSI) + : (iRSI < rsiTrend && + iRSI < iPRSI)); + if (has) + { + break; + } + } + + // + result = has; + } + + // + // Filter Using RSI V Pattern ... + if (result && + filters.forceHasRSIVPattern) + { + // + for (int i = toIDX; i < fromIDX; i++) + { + // + double iRSI = helper.GetRSI(i); + double iPRSI = helper.GetRSI(i + 1); + double iP2RSI = helper.GetRSI(i + 2); + + // + bool isRSIVBullish = + iRSI > iPRSI && + iP2RSI > iPRSI; + + // + bool isRSIVBearish = + iRSI < iPRSI && + iP2RSI < iPRSI; + + // + has = + (isBullish + ? isRSIVBullish + : isRSIVBearish); + if (has) + { + break; + } + } + + // + result = has; + } + + // + // Filter Using RSI Crossing on OB/OS Levels ... + if (result && + filters.forceHasRSICrossing) + { + // + for (int i = toIDX; i < fromIDX; i++) + { + // + double iRSI = helper.GetRSI(i); + double iPRSI = helper.GetRSI(i + 1); + + // + bool isRSICrossedOverOS = + iRSI > conditions.rsiOSLevel && + iPRSI <= conditions.rsiOSLevel; + + // + bool isRSICrossedUnderOB = + iRSI < conditions.rsiOBLevel && + iPRSI >= conditions.rsiOBLevel; + + // + has = + (isBullish + ? isRSICrossedOverOS + : isRSICrossedUnderOB); + if (has) + { + break; + } + } + + // + result = has; + } + } + + // + // Filter Based On ADX ... + if (result && + filters.filterBasedOnADX) + { + // + // Here We Can Apply ADX Filters ... + // Since ADX Filters must be Check on FVG Bars ... + // we Have to Loop back Based on FVG Bars to Detect Conditions ... + + // + toIDX = triggerBlock.fvg.ToIndex(); + fromIDX = triggerBlock.fvg.FromIndex(); + + // + // Filter Using ADX Trending ... + if (result && + filters.forceHasADXTrending) + { + // + for (int i = toIDX; i < fromIDX; i++) + { + // + double iADX = helper.GetADX(i); + double iPADX = helper.GetADX(i + 1); + + // + has = iADX > conditions.adxThreshold && + iADX > iPADX; + if (has) + { + break; + } + } + + // + result = has; + } + + // + // Filter Using ADX Crossing on +DI/-DI ... + if (result && + filters.forceHasADXCrossing) + { + // + for (int i = toIDX; i < fromIDX; i++) + { + // + double iDIPlus = helper.GetADXP(i); + double iPDIPlus = helper.GetADXP(i + 1); + + // + double iDIMinus = helper.GetADXN(i); + double iPDIMinus = helper.GetADXN(i + 1); + + // + bool isADXPlusCrossedOverMinus = + iDIPlus > iDIMinus && + iPDIPlus <= iDIMinus; + + // + bool isADXMinusCrossedOverPlus = + iDIMinus > iDIPlus && + iPDIMinus <= iDIPlus; + + // + has = + isBullish + ? isADXPlusCrossedOverMinus + : isADXMinusCrossedOverPlus; + if (has) + { + break; + } + } + + // + result = has; + } + } + + // + // Filter Based On ATR Band ... + if (result && + filters.filterBasedOnATR) + { + // + // Here We Can Apply ATR Filters ... + // Since ATR Filters must be Check on OB Bars ... + // we Have to Loop back Based on OB Bars to Detect Conditions ... + + // + toIDX = triggerBlock.ob.ToIndex(); + fromIDX = triggerBlock.ob.FromIndex(); + + // + // Filter Using ATR Trending ... + if (result && + filters.forceHasATRTrending) + { + // + for (int i = toIDX; i < fromIDX; i++) + { + // + double iATRUpper = helper.GetATRUpper(i); + double iPATRUpper = helper.GetATRUpper(i + 1); + + // + double iATRLower = helper.GetATRLower(i); + double iPATRLower = helper.GetATRLower(i + 1); + + // + bool isATRUp = + iATRLower > iPATRLower; + + // + bool isATRDown = + iATRUpper < iPATRUpper; + + // + has = isBullish + ? isATRUp + : isATRDown; + if (has) + { + break; + } + } + + // + result = has; + } + + // + // Filter Using ATR Breakout ... + if (result && + filters.forceHasATRBreakout) + { + // + for (int i = toIDX; i < fromIDX; i++) + { + // + double iATRUpper = helper.GetATRUpper(i); + double iATRLower = helper.GetATRLower(i); + + // + has = isBullish + ? triggerBlock.ob.lower < iATRLower + : triggerBlock.ob.upper > iATRUpper; + if (has) + { + break; + } + } + + // + result = has; + } + } + + // + // Filter Based On Trend ... + if (result && + filters.filterBasedOnTrend) + { + // + toIDX = triggerBlock.fvg.ToIndex(); + fromIDX = triggerBlock.fvg.FromIndex(); + + // + // Filter Using Trend Direction ... + if (result && + filters.forceHasTrendDir) + { + // + result = + result && + isBullish + ? conditions.isTrendBullish + : conditions.isTrendBearish; + } + + // + // Filter Using Trend Direction On Both Side ... + if (result && + filters.forceHasTrendDirOnBothSide) + { + // + // Side To ... + result = + result && + isBullish + ? conditions.isTrendBullish + : conditions.isTrendBearish; + + // + // Side From ... + int sFIDX = triggerBlock.ob.FromIndex(); + double sFTrendState = helper.GetTrendState(sFIDX); + result = + result && + isBullish + ? sFTrendState > 0 + : sFTrendState < 0; + } + + // + // Filter Using Trend Change ... + if (result && + filters.forceHasTrendChange) + { + // + for (int i = toIDX; i < fromIDX; i++) + { + // + double iTrendState = helper.GetTrendState(i); + double iPTrendState = helper.GetTrendState(i + 1); + + // + bool isTrendSwitchedToBullish = + iTrendState > 0 && + iPTrendState <= 0; + + // + bool isTrendSwitchedToBearish = + iTrendState < 0 && + iPTrendState >= 0; + + // + has = + isBullish + ? isTrendSwitchedToBullish + : isTrendSwitchedToBearish; + if (has) + { + break; + } + } + + // + result = has; + } + + // + // Filter Using Trend Trending ... + if (result && + filters.forceHasTrendTrending) + { + // + result = + result && + (isBullish + ? conditions.trendBuffer[cIDX] > conditions.trendBuffer[pIDX] + : conditions.trendBuffer[cIDX] < conditions.trendBuffer[pIDX]); + } + + // + // Filter Using Trend Rejection ... + if (result && + filters.forceHasTrendRejection) + { + // + toIDX = triggerBlock.ob.ToIndex(); + fromIDX = triggerBlock.ob.FromIndex(); + for (int i = toIDX; i < fromIDX; i++) + { + // + // Initialize iBar ... + has = iBar.Init( + conditions.symbol, + conditions.period, + i // + ); + + // + // Read Trend Value ... + double iTrend = helper.GetTrend(i); + + // + bool isTrendBullishRejected = + has && + iBar.low < iTrend && + iBar.GetDown() > iTrend; + + // + bool isTrendBearishRejected = + has && + iBar.high > iTrend && + iBar.GetUp() < iTrend; + + // + has = + has && + (isBullish + ? isTrendBullishRejected + : isTrendBearishRejected); + if (has) + { + break; + } + } + + // + result = has; + } + + // + // Filter Using Trend Inside ... + if (result && + filters.forceHasTrendLineInside) + { + // + result = + result && + conditions.trendBuffer[cIDX] > triggerBlock.ob.lower && + conditions.trendBuffer[cIDX] < triggerBlock.ob.upper; + } + + // + // Filter Using Trend Place ... + if (result && + filters.forceHasTrendPlace) + { + // + toIDX = triggerBlock.ob.ToIndex(); + fromIDX = triggerBlock.ob.FromIndex(); + double mult = + isBullish + ? 1 + : -1; + double edge = isBullish + ? triggerBlock.ob.lower + : triggerBlock.ob.upper; + double factor = edge + (mult * (triggerBlock.ob.GetRange() / 4)); + for (int i = toIDX; i < fromIDX; i++) + { + // + double iTrend = helper.GetTrend(i); + + // + has = + isBullish + ? factor >= iTrend + : factor <= iTrend; + if (has) + { + break; + } + } + + // + result = has; + } + } + + // + // Filter Using Delta ... + if (result && + filters.filterBasedOnDelta) + { + // + toIDX = triggerBlock.ob.ToIndex(); + fromIDX = triggerBlock.ob.FromIndex(); + + // + for (int i = toIDX; i < fromIDX; i++) + { + // + double iDelta = helper.GetDelta(i); + double iPDelta = helper.GetDelta(i + 1); + + // + double iDeltaSignal = helper.GetDeltaSignal(i); + double iPDeltaSignal = helper.GetDeltaSignal(i + 1); + + // + bool isDeltaUp = + iDelta > iPDelta; + + // + bool isDeltaDown = + iDelta < iPDelta; + + // + bool isDeltaSignalUp = + iDeltaSignal > iPDeltaSignal; + + // + bool isDeltaSignalDown = + iDeltaSignal < iPDeltaSignal; + + // + bool isDeltaCrossedOverSignal = + iDelta > iDeltaSignal && + iPDelta <= iPDeltaSignal; + + // + bool isDeltaCrossedUnderSignal = + iDelta < iDeltaSignal && + iPDelta >= iPDeltaSignal; + + // + has = + isBullish + ? (isDeltaUp && + isDeltaSignalUp && + isDeltaCrossedOverSignal) + : (isDeltaDown && + isDeltaSignalDown && + isDeltaCrossedUnderSignal); + if (has) + { + break; + } + } + + // + result = has; + } + + // + // Filter Using Volume ... + if (result && + filters.filterBasedOnVolume) + { + // + toIDX = triggerBlock.ob.ToIndex(); + fromIDX = triggerBlock.ob.FromIndex(); + + // + for (int i = toIDX; i < fromIDX; i++) + { + // + double iBullVolume = helper.GetBullishVolume(i); + double iPBullVolume = helper.GetBullishVolume(i + 1); + + // + double iBullVolumeSignal = helper.GetBullishVolumeSignal(i); + double iPBullVolumeSignal = helper.GetBullishVolumeSignal(i + 1); + + // + double iBearVolume = helper.GetBearishVolume(i); + double iPBearVolume = helper.GetBearishVolume(i + 1); + + // + double iBearVolumeSignal = helper.GetBearishVolumeSignal(i); + double iPBearVolumeSignal = helper.GetBearishVolumeSignal(i + 1); + + // + bool isBullVolumeUp = + iBullVolume > iPBullVolume; + + // + bool isBullVolumeSignalUp = + iBullVolumeSignal > iPBullVolumeSignal; + + // + bool isBearVolumeUp = + iBearVolume > iPBearVolume; + + // + bool isBearVolumeSignalUp = + iBearVolumeSignal > iPBearVolumeSignal; + + // + bool isVolumeSwitchedToBullish = + iBullVolumeSignal > iBearVolumeSignal && + iPBullVolumeSignal <= iPBearVolumeSignal; + + // + bool isVolumeSwitchedToBearish = + iBearVolumeSignal > iBullVolumeSignal && + iPBearVolumeSignal <= iPBullVolumeSignal; + + // + has = + isBullish + ? (isBullVolumeUp && + isBullVolumeSignalUp && + isVolumeSwitchedToBullish) + : (isBearVolumeUp && + isBearVolumeSignalUp && + isVolumeSwitchedToBearish); + if (has) + { + break; + } + } + + // + result = has; + } + + // + // Filter Using Signal Bar ... + if (result && + filters.filterBasedOnSignalBar) + { + // + toIDX = triggerBlock.ob.ToIndex(); + fromIDX = triggerBlock.ob.FromIndex(); + + // + double iSOpen = helper.GetSBarOpen(toIDX); + double iPSOpen = helper.GetSBarOpen(toIDX + 1); + + // + double iSClose = helper.GetSBarClose(toIDX); + double iPSClose = helper.GetSBarClose(toIDX + 1); + + // + double iSPow = MathAbs(iSOpen - iSClose); + double iPSPow = MathAbs(iPSOpen - iPSClose); + + // + result = + result && + iSPow > iPSPow && + (isBullish + ? iSClose > iSOpen + : iSClose < iSOpen); + + // + // Now Looking for Dir Change ... + if (result) + { + // + for (int i = toIDX; i < fromIDX; i++) + { + // + iSOpen = helper.GetSBarOpen(toIDX); + iPSOpen = helper.GetSBarOpen(toIDX + 1); + + // + iSClose = helper.GetSBarClose(toIDX); + iPSClose = helper.GetSBarClose(toIDX + 1); + + // + bool isSBullish = + iSClose > iSOpen; + + // + bool isPSBullish = + iPSClose > iPSOpen; + + // + bool isSBearish = + iSClose < iSOpen; + + // + bool isPSBearish = + iPSClose < iPSOpen; + + // + bool isSSwitchedToBullish = + isSBullish && + !isPSBullish; + + // + bool isSSwitchedToBearish = + isSBearish && + !isPSBearish; + + // + has = + isBullish + ? isSSwitchedToBullish + : isSSwitchedToBearish; + if (has) + { + break; + } + } + + // + result = has; + } + } + + // + // Filter Using Signal Bar ... + if (result && + filters.filterBasedOnHKSignalBar) + { + // + toIDX = triggerBlock.ob.ToIndex(); + fromIDX = triggerBlock.ob.FromIndex(); + + // + double iSOpen = helper.GetHKSBarOpen(toIDX); + double iPSOpen = helper.GetHKSBarOpen(toIDX + 1); + + // + double iSClose = helper.GetHKSBarClose(toIDX); + double iPSClose = helper.GetHKSBarClose(toIDX + 1); + + // + double iSPow = MathAbs(iSOpen - iSClose); + double iPSPow = MathAbs(iPSOpen - iPSClose); + + // + result = + result && + iSPow > iPSPow && + (isBullish + ? iSClose > iSOpen + : iSClose < iSOpen); + + // + // Now Looking for Dir Change ... + if (result) + { + // + for (int i = toIDX; i < fromIDX; i++) + { + // + iSOpen = helper.GetHKSBarOpen(toIDX); + iPSOpen = helper.GetHKSBarOpen(toIDX + 1); + + // + iSClose = helper.GetHKSBarClose(toIDX); + iPSClose = helper.GetHKSBarClose(toIDX + 1); + + // + bool isSBullish = + iSClose > iSOpen; + + // + bool isPSBullish = + iPSClose > iPSOpen; + + // + bool isSBearish = + iSClose < iSOpen; + + // + bool isPSBearish = + iPSClose < iPSOpen; + + // + bool isSSwitchedToBullish = + isSBullish && + !isPSBullish; + + // + bool isSSwitchedToBearish = + isSBearish && + !isPSBearish; + + // + has = + isBullish + ? isSSwitchedToBullish + : isSSwitchedToBearish; + if (has) + { + break; + } + } + + // + result = has; + } + } + + // + if (!result) + { + triggerBlock.Clean(); + } + + // + // Summarize result ... + result = triggerBlock.IsValid(); + + // + // Cleanup Resources ... + + // + iBar.Clean(); + + // + if (!result) + { + // + conditions.Clean(); + triggerBlock.Clean(); + } + + // + return result; +} + +// +void ValidateTriggerBlockLiquidities( + XCX121XCatbHelper *helper, + XCBarAnalyser *barAnalyser, + XTriggerBlock &triggerBlock, + X121XCatbConditions &conditions, + XTriggerBlockValidationRules &validations // +) +{ + // + bool has = false; + + // + has = + helper != NULL && + barAnalyser != NULL && + triggerBlock.IsValid() && + (triggerBlock.fLiquidity.IsValid() || + triggerBlock.rLiquidity.IsValid()); + if (!has) + { + return; + } + + // + bool hasFLiq = triggerBlock.fLiquidity.IsValid(); + bool hasRLiq = triggerBlock.rLiquidity.IsValid(); + + // + // TODO: Implement Liquidity Validation ... +} + +// +bool DetectSignalZone( + XCPOIDrawer *&drawer, + XCX121XCatbHelper *helper, + XCBarAnalyser *barAnalyser, + XBoxZone &signalZone, + X121XCatbConditions &conditions, + int barIndex = 0, + int loopback = 10 // +) +{ + // + bool result = false; + + // + // Checking Conditions ... + + // + // Normalize Args ... + signalZone.Clean(); + conditions.Clean(); + barIndex = NormalizeInt(barIndex, 0); + loopback = NormalizeInt(loopback, 0); + + // + // Validate Args ... + result = helper != NULL && + barAnalyser != NULL; + if (!result) + { + return result; + } + + // + // Reading Market Conditions ... + result = helper.GetConditions( + conditions, + barIndex, + loopback // + ); + if (!result) + { + // + signalZone.Clean(); + conditions.Clean(); + + // + return result; + } + + // + int zIDX = 0; + int cIDX = zIDX + 1; + int pIDX = cIDX + 1; + int p2IDX = pIDX + 1; + int p3IDX = p2IDX + 1; + int p4IDX = p3IDX + 1; + + // + double sl = 0; + double tp = 0; + double upper = 0; + double lower = 0; + datetime to = NULL; + datetime from = NULL; + string signalProvider = NULL; + + // + // Checking Conditions ... + + // + // Detect Bar Verifications ... + + // + ENUM_X_DIRECTION iDir; + + // + // Rejected ... + bool isRejected = + barAnalyser + .IsRejected( + conditions.bars[cIDX], + iDir // + ); + bool isBullishRejected = + isRejected && + IsBullish(iDir); + bool isBearishRejected = + isRejected && + IsBearish(iDir); + + // + // Engulfed ... + bool isEngulfed = + barAnalyser + .IsEngulfed( + conditions.bars[cIDX], + iDir // + ); + bool isBullishEngulfed = + isEngulfed && + IsBullish(iDir); + bool isBearishEngulfed = + isEngulfed && + IsBearish(iDir); + + // + // Momentum ... + bool isMomentum = + barAnalyser + .IsMomentum( + conditions.bars[cIDX], + iDir // + ); + bool isBullishMomentum = + isMomentum && + IsBullish(iDir); + bool isBearishMomentum = + isMomentum && + IsBearish(iDir); + + // + bool isBarBullishPressured = + isBullishRejected || + isBullishEngulfed || + isBullishMomentum; + + // + bool isBarBearishPressured = + isBearishRejected || + isBearishEngulfed || + isBearishMomentum; + + // + // Detect Indicator Base Start Directional Movement ... + + // + // SAR ... + + // + bool isSarBullishStart = + // + ( + // + // Current SAR is Directional ... + conditions.isSarBullish && + // + // Previous InDirectional Sar Exists ... + helper.lastSarBearish.IsValid() && + // + // Current Close is Over previous Sar ... + conditions.bars[cIDX].close > helper.lastSarBearish.after && + // + // Before Close is not Over previous Sar ... + conditions.bars[pIDX].close <= helper.lastSarBearish.after + // + ) + // + ; + + // + bool isSarBearishStart = + // + ( + // + // Current SAR is Directional ... + conditions.isSarBearish && + // + // Previous InDirectional Sar Exists ... + helper.lastSarBullish.IsValid() && + // + // Current Close is Under previous ... + conditions.bars[cIDX].close < helper.lastSarBullish.after && + // + // Before Close is not Under previous ... + conditions.bars[pIDX].close >= helper.lastSarBullish.after + // + ) + // + ; + + // + // TREND ... + + // + bool isTrendBullishStart = + // + ( + // + // Current Trend is Directional ... + conditions.isTrendBullish && + // + // Previous InDirectiona; Trend Exists ... + helper.lastTrendBearish.IsValid() && + // + // Current Close is Over previous ... + conditions.bars[cIDX].close > helper.lastTrendBearish.after && + // + // Before close is not Over previous ... + conditions.bars[pIDX].close <= helper.lastTrendBearish.after + // + ) + // + ; + + // + bool isTrendBearishStart = + // + ( + // + // Current Trend is Directional ... + conditions.isTrendBearish && + // + // Previous InDirectiona; Trend Exists ... + helper.lastTrendBullish.IsValid() && + // + // Current Close is Under previous ... + conditions.bars[cIDX].close < helper.lastTrendBullish.after && + // + // Before close is not Under previous ... + conditions.bars[pIDX].close >= helper.lastTrendBullish.after + // + ) + // + ; + + // + // ADX ... + + // + bool isADXBullishStart = + // + ( + // + // ADX Value is Switched to Strong ... + conditions.adxBuffer[cIDX] > conditions.adxThreshold && + conditions.adxBuffer[pIDX] <= conditions.adxThreshold && + // + // ADX must Up ... + conditions.adxBuffer[cIDX] > conditions.adxBuffer[pIDX] && + // + // ADX +DI is Bigger than -DI ... + conditions.adxpBuffer[cIDX] > conditions.adxnBuffer[cIDX] && + // + // ADX +DI is Up ... + conditions.adxpBuffer[cIDX] > conditions.adxpBuffer[pIDX] + // + ) + // + ; + + // + bool isADXBearishStart = + // + ( + // + // ADX Value is Switched to Strong ... + conditions.adxBuffer[cIDX] > conditions.adxThreshold && + conditions.adxBuffer[pIDX] <= conditions.adxThreshold && + // + // ADX must Up ... + conditions.adxBuffer[cIDX] > conditions.adxBuffer[pIDX] && + // + // ADX -DI is Bigger than +DI ... + conditions.adxnBuffer[cIDX] > conditions.adxpBuffer[cIDX] && + // + // ADX -DI is Up ... + conditions.adxnBuffer[cIDX] > conditions.adxnBuffer[pIDX] + // + ) + // + ; + + // + // DELTA ... + + // + bool isDeltaBullishStart = + // + // Check State ... + ( + // + // Delta is Up ... + conditions.deltaBuffer[cIDX] > conditions.deltaBuffer[pIDX] && + // + // Delta Signal is Up ... + conditions.deltaSignalBuffer[cIDX] > conditions.deltaSignalBuffer[pIDX] && + // + // Delta Crossed Over Delta Signal ... + conditions.deltaBuffer[cIDX] > conditions.deltaSignalBuffer[cIDX] + // + ) + // + && + // + // Check Last InDirectional Exists ... + helper.lastDeltaBearish.IsValid() && + // + // Current Close is Over last ... + conditions.bars[cIDX].close > helper.lastDeltaBearish.after && + // + // Before Close is not Over last ... + conditions.bars[pIDX].close <= helper.lastDeltaBearish.after + // + ; + + // + bool isDeltaBearishStart = + // + // Check State ... + ( + // + // Delta is Down ... + conditions.deltaBuffer[cIDX] < conditions.deltaBuffer[pIDX] && + // + // Delta Signal is Down ... + conditions.deltaSignalBuffer[cIDX] < conditions.deltaSignalBuffer[pIDX] && + // + // Delta Crossed Under Delta Signal ... + conditions.deltaBuffer[cIDX] < conditions.deltaSignalBuffer[cIDX] + // + ) + // + && + // + // Check Last InDirectional Exists ... + helper.lastDeltaBullish.IsValid() && + // + // Current Close is Under last ... + conditions.bars[cIDX].close < helper.lastDeltaBullish.after && + // + // Before Close is not Under last ... + conditions.bars[pIDX].close >= helper.lastDeltaBullish.after + // + ; + + // + // VOLUME ... + + // + bool isVolumeBullishStart = + // + ( + // + // + // Volume is Up ... + conditions.bullishVolumeBuffer[1] > conditions.bullishVolumeBuffer[2] && + // + // Volume Signal is Up ... + conditions.bullishVolumeSignalBuffer[1] > conditions.bullishVolumeSignalBuffer[2] && + // + // Volume Signals Crossed Over ... + conditions.bullishVolumeSignalBuffer[1] > conditions.bearishVolumeSignalBuffer[1] + // + ) + // + && + // + // Check Last InDirectional Exists ... + helper.lastVolumeBearish.IsValid() && + // + // Current Close is Over last ... + conditions.bars[cIDX].close > helper.lastVolumeBearish.after && + // + // Before Close is not Over last ... + conditions.bars[pIDX].close <= helper.lastVolumeBearish.after + // + ; + + // + bool isVolumeBearishStart = + // + ( + // + // + // Volume is Up ... + conditions.bearishVolumeBuffer[1] > conditions.bearishVolumeBuffer[2] && + // + // Volume Signal is Up ... + conditions.bearishVolumeSignalBuffer[1] > conditions.bearishVolumeSignalBuffer[2] && + // + // Volume Signals Crossed Over ... + conditions.bearishVolumeSignalBuffer[1] > conditions.bullishVolumeSignalBuffer[1] + // + ) + // + && + // + // Check Last InDirectional Exists ... + helper.lastVolumeBullish.IsValid() && + // + // Current Close is Over last ... + conditions.bars[cIDX].close < helper.lastVolumeBullish.after && + // + // Before Close is not Over last ... + conditions.bars[pIDX].close >= helper.lastVolumeBullish.after + // + ; + + // + // SIGNAL Bar ... + + // + bool isSBarBullishStart = + // + ( + // + // Check Direction ... + conditions.isSBarBullish && + // + // Previous InDirectional Exists ... + helper.lastSignalBarBearish.IsValid() && + // + // Current Signal Bar close over prev ... + conditions.sBarCloseBuffer[cIDX] > helper.lastSignalBarBearish.after && + // + // Prev Signal Bar not close over prev ... + conditions.sBarCloseBuffer[pIDX] <= helper.lastSignalBarBearish.after + // + ) + // + ; + + // + bool isSBarBearishStart = + // + ( + // + // Check Direction ... + conditions.isSBarBearish && + // + // Previous InDirectional Exists ... + helper.lastSignalBarBullish.IsValid() && + // + // Current Signal Bar close over prev ... + conditions.sBarCloseBuffer[cIDX] < helper.lastSignalBarBullish.after && + // + // Prev Signal Bar not close over prev ... + conditions.sBarCloseBuffer[pIDX] >= helper.lastSignalBarBullish.after + // + ) + // + ; + + // + // HKSIGNAL Bar ... + + // + bool isHKSBarBullishStart = + // + ( + // + // Check Direction ... + conditions.isHKSBarBullish && + // + // Previous InDirectional Exists ... + helper.lastHKSignalBarBearish.IsValid() && + // + // Current Signal Bar close over prev ... + conditions.hkSBarCloseBuffer[cIDX] > helper.lastHKSignalBarBearish.after && + // + // Prev Signal Bar not close over prev ... + conditions.hkSBarCloseBuffer[pIDX] <= helper.lastHKSignalBarBearish.after + // + ) + // + ; + + // + bool isHKSBarBearishStart = + // + ( + // + // Check Direction ... + conditions.isHKSBarBearish && + // + // Previous InDirectional Exists ... + helper.lastHKSignalBarBullish.IsValid() && + // + // Current Signal Bar close over prev ... + conditions.hkSBarCloseBuffer[cIDX] < helper.lastHKSignalBarBullish.after && + // + // Prev Signal Bar not close over prev ... + conditions.hkSBarCloseBuffer[pIDX] >= helper.lastHKSignalBarBullish.after + // + ) + // + ; + + // + // Check for Vale and Peak ... + + // + bool isPeakOverLast = + // + (conditions.peakBuffer[cIDX] > conditions.peakBuffer[pIDX] && + conditions.peakBuffer[pIDX] <= conditions.peakBuffer[p2IDX] && + conditions.bars[cIDX].close > conditions.peakBuffer[pIDX]) + // + ; + + // + bool isValeUnderLast = + // + (conditions.valeBuffer[cIDX] < conditions.valeBuffer[pIDX] && + conditions.valeBuffer[pIDX] >= conditions.valeBuffer[p2IDX] && + conditions.bars[cIDX].close < conditions.valeBuffer[pIDX]) + // + ; + + // + // Start Different Conditions Implemntation ... + + // + // Condition 1: + // --------------------------- + // Descriptions: + // + // + // --------------------------- + + // + // Bullish ... + bool isCond1Bullish = false; + + // + // Bearish ... + bool isCond1Bearish = false; + + // + bool isCond1 = + isCond1Bullish || + isCond1Bearish; + if (isCond1) + { + // + // Prepare Cond1 Based Requirements ... + + // + to = NULL; + upper = 0; + lower = 0; + from = NULL; + + // + // Provider Definition ... + signalProvider = "Cond1"; + } + + // + // Try to Summarize Conditions ... + + // + bool isBullish = + // + isCond1Bullish + // + ; + + // + bool isBearish = + // + isCond1Bearish + // + ; + + // + // Summarize Result ... + result = + isBullish || + isBearish; + if (result) + { + // + // Prepare Signal Zone ... + + // + signalZone.to = to; + signalZone.from = from; + signalZone.upper = upper; + signalZone.lower = lower; + signalZone.type = signalProvider; + signalZone.symbol = conditions.symbol; + signalZone.period = conditions.period; + + // + signalZone.dir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + // Validate Signal Zone ... + result = signalZone.IsValid(); + } + + // + // Cleanup Resources ... + + // + if (!result) + { + // + signalZone.Clean(); + conditions.Clean(); + } + + // + return result; +} + +// +// Draw Specific Trigger Block ... +bool DrawTriggerBlock( + XTriggerBlock &trigger, + XCPOIDrawer *drawer, + CArrayObj &objects, + datetime to = NULL, + // + bool _drawSignals = false, + int rrZoneLength = 10, + // Styles ... + // + // Trigger Block ... + int tbWidth = 1, // Trigger Block Width + color tbBullishColor = clrAqua, // Trigger Block Bullish Color + color tbBearishColor = clrMagenta, // Trigger Block Bearish Color + ENUM_LINE_STYLE tbStyle = STYLE_DASHDOTDOT, // Trigger Block Style + // + // OB ... + int obWidth = 1, // OB Width + color obBullishColor = clrLime, // OB Bullish Color + color obBearishColor = clrRed, // OB Bearish Color + ENUM_LINE_STYLE obStyle = STYLE_DOT, // OB Style + // + // FVG ... + int fvgWidth = 2, // FVG Width + color fvgBullishColor = clrLime, // FVG Bullish Color + color fvgBearishColor = clrRed, // FVG Bearish Color + ENUM_LINE_STYLE fvgStyle = STYLE_SOLID // FVG Style +) +{ + // + bool result = false; + + // + // Validate Args ... + result = trigger.IsValid() && + drawer != NULL; + if (!result) + { + return result; + } + + // + XTriggerBlock _trigger = trigger; + + // + // Update To ... + bool canUpdateTo = IsValid(to); + if (canUpdateTo) + { + // + _trigger.trigger.to = to; + _trigger.rLiquidity.to = to; + _trigger.fLiquidity.to = to; + } + + // + bool isBullish = _trigger.IsBullish(); + + // + // Draw OB ... + if (_trigger.ob.IsValid()) + { + // + XCBoxObject *iOBObj; + result = drawer.DrawBox( + _trigger.ob, + iOBObj // + ); + if (result) + { + // + // Style Object ... + + // + color iClr = + isBullish + ? obBullishColor + : obBearishColor; + + // + iOBObj.BoxColor(iClr); + iOBObj.BoxWidth(obWidth); + iOBObj.BoxStyle(obStyle); + + // + // Store Object ... + objects.Add(iOBObj); + } + ZeroMemory(iOBObj); + + // + if (!result) + { + return result; + } + } + + // + // Draw FVG ... + if (_trigger.fvg.IsValid()) + { + // + XCBoxObject *iFVGObj; + result = drawer.DrawBox( + _trigger.fvg, + iFVGObj // + ); + if (result) + { + // + // Style Object ... + + // + color iClr = + isBullish + ? fvgBullishColor + : fvgBearishColor; + + // + iFVGObj.BoxColor(iClr); + iFVGObj.BoxWidth(fvgWidth); + iFVGObj.BoxStyle(fvgStyle); + + // + // Store Object ... + objects.Add(iFVGObj); + } + ZeroMemory(iFVGObj); + + // + if (!result) + { + return result; + } + } + + // + // Draw Trigger ... + if (_trigger.trigger.IsValid()) + { + // + XCBoxObject *iTriggerObj; + result = drawer.DrawBox( + _trigger.trigger, + iTriggerObj // + ); + if (result) + { + // + // Style Object ... + + // + color iClr = + isBullish + ? tbBullishColor + : tbBearishColor; + + // + iTriggerObj.BoxColor(iClr); + iTriggerObj.BoxWidth(tbWidth); + iTriggerObj.BoxStyle(tbStyle); + + // + // Store Object ... + objects.Add(iTriggerObj); + } + ZeroMemory(iTriggerObj); + + // + if (!result) + { + return result; + } + } + + // + // Draw Liquidities ... + + // + // Reversla Liquidity ... + if (_trigger.rLiquidity.IsValid()) + { + // + XCBoxObject *iLiqObj; + result = drawer.DrawBox( + _trigger.rLiquidity, + iLiqObj // + ); + if (result) + { + objects.Add(iLiqObj); + } + ZeroMemory(iLiqObj); + + // + if (!result) + { + return result; + } + } + + // + // Following Liquidity ... + if (_trigger.fLiquidity.IsValid()) + { + // + XCBoxObject *iLiqObj; + result = drawer.DrawBox( + _trigger.fLiquidity, + iLiqObj // + ); + if (result) + { + objects.Add(iLiqObj); + } + ZeroMemory(iLiqObj); + + // + if (!result) + { + return result; + } + } + + // + // Draw Swing Bar ... + if (_trigger.swingBar.IsValid()) + { + // + color swingColor = + _trigger.fvg.IsBullish() + ? clrAqua + : clrMagenta; + ENUM_X_PRICE swingPType = + _trigger.fvg.IsBullish() + ? X_PRICE_LOW + : X_PRICE_HIGH; + + // + XCBarArrowObject *swingObj; + result = drawer.CreateBarArrow( + _trigger.swingBar, + swingObj, + swingPType, + 159, + swingColor // + ); + if (result) + { + objects.Add(swingObj); + } + ZeroMemory(swingObj); + + // + if (!result) + { + return result; + } + } + + // + // Draw RR of Signal ... + if (_drawSignals && + _trigger.signal.IsValid() && + rrZoneLength > 0) + { + // + XCRRObject *iRRObj; + iRRObj = new XCRRObject(); + result = iRRObj.Create( + drawer.ChartIdentification(), + drawer.SubWindowIdentification(), + _trigger.signal, + rrZoneLength // + ); + if (result) + { + // + int iWidth = 2; + ENUM_LINE_STYLE iStyle = STYLE_SOLID; + + // + iRRObj.TPWidth(iWidth); + iRRObj.SLWidth(iWidth); + iRRObj.EntryWidth(iWidth); + iRRObj.TargetWidth(iWidth); + + // + iRRObj.TPStyle(iStyle); + iRRObj.SLStyle(iStyle); + iRRObj.EntryStyle(iStyle); + iRRObj.TargetStyle(iStyle); + + // + iRRObj.TPColor(clrLime); + iRRObj.SLColor(clrRed); + iRRObj.EntryColor(clrYellow); + iRRObj.TargetColor(clrLightBlue); + + // + objects.Add(iRRObj); + } + ZeroMemory(iRRObj); + + // + if (result) + { + return result; + } + } + + // + return result; +} diff --git a/XCATBEA/Libraries/xcatbea.signaller.lib.mq5 b/XCATBEA/Libraries/xcatbea.signaller.lib.mq5 index 0a335b94..9ab706f6 100644 --- a/XCATBEA/Libraries/xcatbea.signaller.lib.mq5 +++ b/XCATBEA/Libraries/xcatbea.signaller.lib.mq5 @@ -21,35 +21,53 @@ // // Imports ... -#include "../../Classes/x-saherelm.x-bar.analyser.class.mq5" -#include "../../Classes/x-saherelm.x-poi.drawer.class.mq5" -#include "../Libraries/xcatbea.lib.mq5" +#include "../../Libraries/x-saherelm.common.lib.mq5" +#include "../../Libraries/x-saherelm.x-poi.lib.mq5" +#include "../../Libraries/x-saherelm.x-trade.lib.mq5" +#include "../../Helpers/x-saherelm.x121.xcatb.helper.mq5" // -// Definiions ... +// Definitions ... // -#define XLiquidityToken "XLQ"; -#define XTriggerBlockToken "XTRG"; - -// -struct XTriggerBlock +struct XCATBEAStrategyConditions { // // Props ... - XBoxZone ob; // Order Block - XBoxZone fvg; // Fair Value Gap - XOHCL swingBar; // Swing of Trigger - XBoxZone trigger; // Trigger Block - XBoxZone rLiquidity; // Reversal Liquidity - XBoxZone fLiquidity; // Following Liquidity // - XSignal signal; // Pepared Signal + string symbol; + ENUM_TIMEFRAMES period; + + // + // Setup Props ... + + // + double sl; + double tp; + double pivot; + double point; + double entry; + double reward; + string provider; + + // + XTarget targets[]; + + // + datetime time; + datetime setupTime; + datetime triggerTime; + + // + ENUM_X_DIRECTION dir; + XBoxZone decisionZone; + ENUM_X_POSITION_TYPES type; + X121XCatbConditions conditions; // // Constructor ... - XTriggerBlock() + XCATBEAStrategyConditions() { Clean(); } @@ -57,3162 +75,199 @@ struct XTriggerBlock // // Tools ... - // - // Cleanup ... + /** + * Cleaning Up ... + */ void Clean() { // - ob.Clean(); - fvg.Clean(); - signal.Clean(); - trigger.Clean(); - swingBar.Clean(); - rLiquidity.Clean(); - fLiquidity.Clean(); + sl = 0; + tp = 0; + pivot = 0; + point = 0; + entry = 0; + reward = 0; + + // + symbol = NULL; + period = NULL; + provider = NULL; + + // + time = NULL; + setupTime = NULL; + triggerTime = NULL; + + // + Clean(targets); + + // + conditions.Clean(); + decisionZone.Clean(); + + // + dir = X_DIRECTION_NONE; + type = X_POSITION_TYPE_NONE; // ZeroMemory(this); } // - // Validate ... + // Signalling ... + + /** + * Validate ... + * + * @return ( bool ) + */ bool IsValid() { // bool result = false; // - result = ob.IsValid() && - fvg.IsValid() && - trigger.IsValid(); + result = IsSpecifiedValid(symbol) && + IsSpecifiedValid(period) && + IsSpecifiedValid(time); + + // + return result; + } + + /** + * Check Conditions Has Valid Bullish Signal ... + * + * @return ( bool ) + */ + bool HasBullishSignal() + { + // + bool result = false; + + // + result = + (sl > 0 || + tp > 0) && + IsValid() && + HasDirection(dir); + if (!result) + { + return result; + } + + // + result = + IsBullish(dir); + + // + return result; + } + + /** + * Check Conditions Has Valid Bearish Signal ... + * + * @return ( bool ) + */ + bool HasBearishSignal() + { + // + bool result = false; + + // + result = + (sl > 0 || + tp > 0) && + IsValid() && + HasDirection(dir); + if (!result) + { + return result; + } + + // + result = + IsBearish(dir); // return result; } // - bool IsBullish() - { - return IsValid() && - ob.IsBullish(); - } + // Setting Up and Triggering Up ... - // - bool IsBearish() - { - return IsValid() && - ob.IsBearish(); - } - - // - int ToIndex() - { - return trigger.ToIndex(); - } - - // - int FromIndex() - { - return trigger.FromIndex(); - } - - // - ENUM_X_DIRECTION GetDirection() + /** + * Check Condition is Setting Up ... + * + * @param dir: ENUM_X_DIRECTION member, Setting Up Direction ... + * + * @return ( bool ) + */ + bool IsSetuped() { // - ENUM_X_DIRECTION result = X_DIRECTION_NONE; + bool result = false; // - if (IsValid()) + result = IsValid(setupTime) && + HasDirection(dir); + if (!result) { - result = ob.dir; + return result; } // return result; } + /** + * Calculate Setup Age ... + * + * @return ( int ) + */ + int GetSetupAge() + { + // + int result = 0; + + // + if (!IsSetuped()) + { + return result; + } + + // + result = (int)(TimeCurrent() - setupTime) / PeriodSeconds(period); + + // + return result; + } + + /** + * Detect How we Can Trigger Signal ... + * + * @return ( bool ) + */ + bool CanTrigger() + { + // + bool result = false; + + // + result = + // + sl > 0 && + IsValid(symbol) && + IsValid(period) && + IsValid(triggerTime) && + type != X_POSITION_TYPE_ALL && + type != X_POSITION_TYPE_NONE + // + ; + + // + return result; + } + // }; - -// -// Trigger Block Validation Rules ... -struct XTriggerBlockValidationRules -{ - // - // Props ... - bool forceHasSwing; // Force Block to Has Propper Swing ... - bool forceOBBarType; // Force Order Block to Has InDirectional Bars ... - int minRequiredOBBar; // Min Required OB Bar ... - bool forceFVGBarType; // Force Fair Value Gaps Bars Type ... - int liquidityLoopback; // Liquidity Detection Loopback ... - double maxAllowedRange; // Max Allowed Order Block Range ... - double minAllowedRange; // Min Allowed Order Block Range ... - bool forceHasFLiquidity; // Force Order Block To Has Reversal Liquidity ... - bool forceHasRLiquidity; // Force Order Block to Has Following Liquidity ... - bool validateGapSequence; // Validate Fair Value Gaps Bar Sequences ... - int minAllowedBlockLength; // Min Allowed Block Length ... - bool validateBlockEdgeBreakout; // Validate Order Block Edge Breakeout ... - - // - // Constructor(s) ... - XTriggerBlockValidationRules() - { - Clean(); - } - - // - // Tools ... - - // - // Cleanup ... - void Clean() - { - // - maxAllowedRange = 0; - minAllowedRange = 0; - minRequiredOBBar = 0; - liquidityLoopback = 0; - forceHasSwing = false; - forceOBBarType = false; - forceFVGBarType = false; - minAllowedBlockLength = 0; - forceHasFLiquidity = false; - forceHasRLiquidity = false; - validateGapSequence = false; - validateBlockEdgeBreakout = false; - - // - ZeroMemory(this); - } -}; - -// -// Trigger Block Filters ... -struct XTriggerBlockFilters -{ - // - // Props ... - bool filterBasedOnPV; // Filter Based On PV ... - bool filterBasedOnSar; // Filter Based On SAR ... - bool filterBasedOnRSI; // Filter Based On RSI ... - bool filterBasedOnADX; // Filter Based On ADX ... - bool filterBasedOnATR; // Filter Based On ATR ... - bool filterBasedOnTrend; // Filter Based On Trend ... - bool filterBasedOnDelta; // Filter Based On Delta ... - bool filterBasedOnVolume; // Filter Based On Volume ... - bool filterBasedOnSignalBar; // Filter Based on Signal Bar ... - bool filterBasedOnHKSignalBar; // Filter Based On HK Signal Bar ... - - // - int bosLoopback; // PV Based Filtering BOS Lookup ... - - // - bool forceSarSwitched; // SAR Switched on Sides for Filtering ... - bool forceSarOnBothSide; // SAR Check on Both Sides for Filtering ... - bool forceSarHasBreakout; // SAR Must SAR Must Breakout ... - bool forceSarHasReversalSide; // SAR Must SAR Must Has Reversal Direction ... - - // - bool forceHasRSITrending; // RSI Must Has Trending ... - bool forceHasRSIVPattern; // RSI Must Has Pattern ... - bool forceHasRSICrossing; // RSI Must Has Crossing Levels ... - - // - bool forceHasADXTrending; // ADX Must Has Trending ... - bool forceHasADXCrossing; // ADX Must Has Crossing +DI/-DI ... - - // - bool forceHasATRTrending; // ATR Must Has Trending ... - bool forceHasATRBreakout; // ATR Must Has Breakout ... - - // - bool forceHasTrendDir; // TREND Must Has Following Direction ... - bool forceHasTrendPlace; // TREND Place Based Filtering ... - bool forceHasTrendChange; // TREND Change Filtering ... - bool forceHasTrendTrending; // TREND Must Has Trending ... - bool forceHasTrendRejection; // TREND Line Must Rejected ... - bool forceHasTrendLineInside; // TREND Line has Inside ... - bool forceHasTrendDirOnBothSide; // TREND Must Has Following Direction in Both Side ... - - // - // Constructor(s) ... - XTriggerBlockFilters() - { - Clean(); - } - - // - // Tools ... - - // - // Cleanup ... - void Clean() - { - // - filterBasedOnPV = false; - filterBasedOnSar = false; - filterBasedOnRSI = false; - filterBasedOnADX = false; - filterBasedOnATR = false; - filterBasedOnTrend = false; - filterBasedOnDelta = false; - filterBasedOnVolume = false; - filterBasedOnSignalBar = false; - filterBasedOnHKSignalBar = false; - - // - bosLoopback = 0; - - // - forceSarSwitched = false; - forceSarOnBothSide = false; - forceSarHasBreakout = false; - forceSarHasReversalSide = false; - - // - forceHasRSITrending = false; - forceHasRSIVPattern = false; - forceHasRSICrossing = false; - - // - forceHasADXTrending = false; - forceHasADXCrossing = false; - - // - forceHasATRTrending = false; - forceHasATRBreakout = false; - - // - forceHasTrendDir = false; - forceHasTrendPlace = false; - forceHasTrendChange = false; - forceHasTrendTrending = false; - forceHasTrendRejection = false; - forceHasTrendLineInside = false; - forceHasTrendDirOnBothSide = false; - - // - ZeroMemory(this); - } -}; - -// -// Extensions ... - -/** - * Detect Trigger Block ... - * - * @param helper: XCX121XCatbHelper instance pointer ... - * @param barAnalyser: XCBarAnalyser instance pointer ... - * @param triggerBlock: XTriggerBlock Refrence, holds Detected Trigger Block ... - * @param conditions: X121XCatbConditions Refrence, holds Trigger Block Conditions ... - * @param validations: XTriggerBlockValidationRules Refrence, Provides Trigger Block Validation Rules ... - * @param filters: XTriggerBlockFilters Refrence, Provides Trigger Block Filters ... - * @param barIndex: int, Bar Index ... - * @param loopback: int, Loopback for Conditions reading ... - * - * @return ( bool ) - */ -bool DetectTriggerBlock1( - XCX121XCatbHelper *helper, - XCBarAnalyser *barAnalyser, - XTriggerBlock &triggerBlock, - X121XCatbConditions &conditions, - XTriggerBlockValidationRules &validations, - XTriggerBlockFilters &filters, - int barIndex = 0, - int loopback = 10 // -) -{ - // - bool result = false; - - // - // Normalize Args ... - conditions.Clean(); - triggerBlock.Clean(); - barIndex = NormalizeInt(barIndex, 0); - loopback = NormalizeInt(loopback, 0); - - // - // Validate Args ... - result = - helper != NULL && - barAnalyser != NULL; - if (!result) - { - return result; - } - - // - int zIDX = 0; - int cIDX = zIDX + 1; - int pIDX = cIDX + 1; - int p2IDX = pIDX + 1; - int p3IDX = p2IDX + 1; - int p4IDX = p3IDX + 1; - - // - bool has = false; - string symbol = helper.GetSymbol(); - ENUM_TIMEFRAMES period = helper.GetPeriod(); - - // - // Initial Requirements ... - - // - // Required Bars ... - XOHCL zBar; - XOHCL cBar; - result = - result && - zBar.Init( - symbol, - period, - barIndex // - ); - result = - result && - zBar.GetPreviousBar(cBar); - - // - // Here we Must Detect Order Block ... - // then Detect FVG ... - // then Prepare Trigger Box ... - - // - // Select Application Bar ... - XOHCL iBar; - if (barIndex == 0) - { - iBar = cBar; - } - else if (barIndex > 0) - { - iBar = zBar; - } - iBar = cBar; - result = - result && - iBar.IsValid(); - - // - // Detect Order Block ... - result = - result && - barAnalyser - .IsOB( - iBar, - triggerBlock.ob, - false, - false // - ); - - // - // Detect Fair Value Gap ... - result = - result && - barAnalyser - .IsFVG( - iBar, - triggerBlock.fvg, - false // - ); - - // - // Check Result and Create Trigger Box based on it ... - if (result) - { - // - triggerBlock.trigger = triggerBlock.ob; - triggerBlock.trigger.type = XTriggerBlockToken; - - // - // Update Upper and Lower ... - int toIDX = triggerBlock.ob.ToIndex(); - int fromIDX = triggerBlock.ob.FromIndex(); - - // - iBar.Clean(); - result = iBar.Init( - symbol, - period, - toIDX // - ); - if (result) - { - // - double iLL = iBar.FindLowest(fromIDX - toIDX, MODE_LOW); - double iHH = iBar.FindHighest(fromIDX - toIDX, MODE_HIGH); - - // - triggerBlock.trigger.upper = MathMax(iHH, triggerBlock.trigger.upper); - triggerBlock.trigger.lower = MathMin(iLL, triggerBlock.trigger.lower); - } - - // - iBar.Clean(); - } - - // - // Apply Validations ... - if (result) - { - // - result = ValidateTriggerBlock( - helper, - barAnalyser, - triggerBlock, - conditions, - validations, - barIndex, - loopback // - ); - - // - if (!result) - { - triggerBlock.Clean(); - } - } - - // - // Apply Filtering ... - if (result) - { - // - result = FilterTriggerBlock( - helper, - barAnalyser, - triggerBlock, - conditions, - filters, - barIndex, - loopback // - ); - - // - if (!result) - { - triggerBlock.Clean(); - } - } - - // - // Summarizing Result ... - result = - result && - triggerBlock.IsValid(); - - // - // Preparing Signal ... - if (result) - { - // - } - - // - // Cleanup Resources ... - - // - iBar.Clean(); - zBar.Clean(); - cBar.Clean(); - - // - if (!result) - { - triggerBlock.Clean(); - } - - // - return result; -} - -/** - * Validate a Trigger Block ... - * - * @param helper: XCX121XCatbHelper instance pointer ... - * @param barAnalyser: XCBarAnalyser instance pointer ... - * @param triggerBlock: XTriggerBlock Refrence, Trigger Block ... - * @param conditions: X121XCatbConditions Refrence, Trigger Block Conditions ... - * @param validations: XTriggerBlockValidationRules Refrence, Provides Trigger Block Validation Rules ... - * @param barIndex: int, Bar Index ... - * @param loopback: int, Loopback for Conditions reading ... - * - * @return ( bool ) - */ -bool ValidateTriggerBlock( - XCX121XCatbHelper *helper, - XCBarAnalyser *barAnalyser, - XTriggerBlock &triggerBlock, - X121XCatbConditions &conditions, - XTriggerBlockValidationRules &validations, - int barIndex = 0, - int loopback = 10 // -) -{ - // - bool result = false; - - // - // Checking Conditions ... - - // - // Normalize Args ... - conditions.Clean(); - barIndex = NormalizeInt(barIndex, 0); - loopback = NormalizeInt(loopback, 0); - - // - // Validate Args ... - result = - helper != NULL && - barAnalyser != NULL && - triggerBlock.IsValid(); - if (!result) - { - return result; - } - - // - // Reading Market Conditions ... - result = helper.GetConditions( - conditions, - barIndex, - loopback // - ); - if (!result) - { - // - conditions.Clean(); - - // - return result; - } - - // - int zIDX = 0; - int cIDX = zIDX + 1; - int pIDX = cIDX + 1; - int p2IDX = pIDX + 1; - int p3IDX = p2IDX + 1; - int p4IDX = p3IDX + 1; - - // - XOHCL iBar; - int count = 0; - int toIDX = -1; - int fromIDX = -1; - bool has = false; - bool isBullish = triggerBlock.IsBullish(); - bool isBearish = triggerBlock.IsBearish(); - double points = GetPoints(triggerBlock.ob.symbol); - ENUM_X_DIRECTION iDir = triggerBlock.GetDirection(); - - // - // Checking Conditions ... - - // - // Range Validation ... - - // - // Max Allowed OB Range ... - if (result && - validations.maxAllowedRange > 0) - { - // - double iRange = triggerBlock.ob.GetRange(); - result = iRange <= (validations.maxAllowedRange * points); - } - - // - // Min Allowed OB Range ... - if (result && - validations.minAllowedRange > 0) - { - // - double iRange = triggerBlock.ob.GetRange(); - result = iRange >= (validations.maxAllowedRange * points); - } - - // - // Has Swing ... - if (result && - validations.forceHasSwing) - { - // - bool isSwing = false; - toIDX = triggerBlock.ToIndex(); - fromIDX = triggerBlock.FromIndex(); - ENUM_X_DIRECTION swingDir = X_DIRECTION_NONE; - for (int i = toIDX; i <= fromIDX; i++) - { - // - // Initialize iBar ... - has = iBar.Init( - conditions.symbol, - conditions.period, - i // - ); - isSwing = - has && - barAnalyser - .IsSimpleSwing( - iBar, - swingDir // - ); - if (isSwing && - swingDir == iDir) - { - break; - } - - // - iBar.Clean(); - } - - // - result = - isSwing && - iBar.IsValid() && - swingDir == iDir; - if (result) - { - // - // Initialize Swing Bar ... - result = triggerBlock - .swingBar - .Init( - iBar.symbol, - iBar.period, - iBar.Index() + 2 // - ); - } - - // - iBar.Clean(); - } - - // - // Force FVG Bar Types ... - if (result && - validations.forceFVGBarType) - { - // - toIDX = triggerBlock.fvg.ToIndex(); - fromIDX = triggerBlock.fvg.FromIndex(); - for (int i = toIDX; i < fromIDX; i++) - { - // - // Initialize iBar ... - result = iBar.Init( - conditions.symbol, - conditions.period, - i // - ); - result = - result && - iDir == iBar.GetDirection(); - - // - iBar.Clean(); - - // - if (!result) - { - break; - } - } - - // - iBar.Clean(); - } - - // - // Force OB Start By InDirectional Bars ... - if (result && - validations.forceOBBarType) - { - // - count = 0; - fromIDX = triggerBlock.fvg.FromIndex() + 1; - int sIDX = fromIDX; - has = true; - while (has) - { - // - // Initialize iBar .. - has = iBar.Init( - conditions.symbol, - conditions.period, - fromIDX // - ); - has = has && - iDir == Opposit(iBar.GetDirection()); - if (has) - { - count++; - } - - // - fromIDX++; - } - - // - int required = - validations.minRequiredOBBar > 0 - ? validations.minRequiredOBBar - : 1; - - // - result = count >= required; - - // - // Update Trigger Block Box based on OB Bar Types ... - if (result) - { - // - result = iBar.Init( - conditions.symbol, - conditions.period, - sIDX // - ); - if (result) - { - // - datetime iFrom = GetBarTime( - conditions.symbol, - conditions.period, - sIDX + count // - ); - double iLL = iBar.FindLowest(count, MODE_LOW); - double iHH = iBar.FindHighest(count, MODE_HIGH); - - // - triggerBlock.trigger.from = iFrom; - triggerBlock.trigger.upper = MathMax(iHH, triggerBlock.trigger.upper); - triggerBlock.trigger.lower = MathMin(iLL, triggerBlock.trigger.lower); - } - } - - // - iBar.Clean(); - } - - // - // Force Fair Value Gap to Following Sequence ... - if (result && - validations.validateGapSequence) - { - // - XOHCL iPBar; - toIDX = triggerBlock.fvg.ToIndex(); - fromIDX = triggerBlock.fvg.FromIndex() - 1; - for (int i = toIDX; i < fromIDX; i++) - { - // - result = iBar.Init( - conditions.symbol, - conditions.period, - i // - ); - result = - result && - iBar.GetPreviousBar(iPBar); - result = - result && - (isBullish - ? iBar.low > iPBar.low - : iBar.high < iPBar.high); - if (!result) - { - break; - } - - // - iBar.Clean(); - iPBar.Clean(); - } - - // - iBar.Clean(); - iPBar.Clean(); - } - - // - // Validate OB Edge Breakeout Using Gaps End Bar ... - if (result && - validations.validateBlockEdgeBreakout) - { - // - // Initialize Gap End Bar ... - toIDX = triggerBlock.fvg.ToIndex(); - result = iBar.Init( - conditions.symbol, - conditions.period, - toIDX // - ); - - // - result = - result && - (isBullish - ? iBar.open < triggerBlock.ob.upper && - iBar.close > triggerBlock.ob.upper - : iBar.open > triggerBlock.ob.lower && - iBar.close < triggerBlock.ob.lower); - - // - // Here we Can Apply Edge Breakout Using Fibo ... - - // - iBar.Clean(); - } - - // - // Force Block to Has Liquidity ... - if (result && - validations.liquidityLoopback > 0 && - (validations.forceHasFLiquidity || - validations.forceHasRLiquidity)) - { - // - toIDX = triggerBlock.ToIndex(); - fromIDX = triggerBlock.FromIndex(); - ENUM_X_DIRECTION iLiqDir = X_DIRECTION_NONE; - for (int i = toIDX; i < fromIDX + validations.liquidityLoopback; i++) - { - // - // Initialize iBar ... - has = iBar.Init( - conditions.symbol, - conditions.period, - i // - ); - has = - has && - barAnalyser - .IsRejected( - iBar, - iLiqDir, - false, // Force Bar Type ... - true // Force Fibo Pressure ... - ); - - // - bool isFLiq = - has && - iLiqDir == iDir; - if (isFLiq && - validations.forceHasFLiquidity && - !triggerBlock.fLiquidity.IsValid()) - { - // - FillLiquidity( - iBar, - iLiqDir, - triggerBlock.fLiquidity, - triggerBlock.trigger.to // - ); - } - - // - bool isRLiq = - has && - iLiqDir == Opposit(iDir); - if (isRLiq && - validations.forceHasRLiquidity && - !triggerBlock.rLiquidity.IsValid()) - { - // - FillLiquidity( - iBar, - iLiqDir, - triggerBlock.rLiquidity, - triggerBlock.trigger.to // - ); - } - - // - // Here We Can Apply Liquidity Validations ... - ValidateTriggerBlockLiquidities( - helper, - barAnalyser, - triggerBlock, - conditions, - validations // - ); - - // - // Check Liquidities ... - has = (!validations.forceHasFLiquidity - ? true - : triggerBlock.fLiquidity.IsValid()) && - (!validations.forceHasRLiquidity - ? true - : triggerBlock.rLiquidity.IsValid()); - - // - iBar.Clean(); - - // - if (has) - { - break; - } - } - - // - // Check Result ... - result = (!validations.forceHasFLiquidity - ? true - : triggerBlock.fLiquidity.IsValid()) && - (!validations.forceHasRLiquidity - ? true - : triggerBlock.rLiquidity.IsValid()); - - // - iBar.Clean(); - } - - // - // Validating Block Length Based on Direction ... - if (result && - validations.minAllowedBlockLength) - { - // - count = 0; - fromIDX = triggerBlock.FromIndex(); - int sIDX = fromIDX; - has = true; - while (has) - { - // - // Initialize iBar ... - has = iBar.Init( - conditions.symbol, - conditions.period, - sIDX // - ); - - // - has = - has && - (isBullish - ? iBar.low > triggerBlock.trigger.lower - : iBar.high < triggerBlock.trigger.upper); - - // - if (!has) - { - break; - } - - // - sIDX++; - count++; - iBar.Clean(); - } - - // - result = - iBar.IsValid() && - count >= validations.minAllowedBlockLength; - if (result) - { - // - // Update Trigger Block ... - bool usaMinAllowedForBlockLength = false; - if (usaMinAllowedForBlockLength) - { - fromIDX = fromIDX + validations.minAllowedBlockLength; - } - else - { - fromIDX = sIDX - 1; - } - - // - triggerBlock.trigger.from = GetBarTime( - conditions.symbol, - conditions.period, - fromIDX // - ); - } - - // - iBar.Clean(); - } - - // - if (!result) - { - triggerBlock.Clean(); - } - - // - // Summarize result ... - result = triggerBlock.IsValid(); - - // - // Cleanup Resources ... - - // - iBar.Clean(); - - // - if (!result) - { - // - conditions.Clean(); - triggerBlock.Clean(); - } - - // - return result; -} - -/** - * Filter a Trigger Block ... - * - * @param helper: XCX121XCatbHelper instance pointer ... - * @param barAnalyser: XCBarAnalyser instance pointer ... - * @param triggerBlock: XTriggerBlock Refrence, Trigger Block ... - * @param conditions: X121XCatbConditions Refrence, Trigger Block Conditions ... - * @param filters: XTriggerBlockFilters Refrence, Provides Trigger Block Filters ... - * @param barIndex: int, Bar Index ... - * @param loopback: int, Loopback for Conditions reading ... - * - * @return ( bool ) - */ -bool FilterTriggerBlock( - XCX121XCatbHelper *helper, - XCBarAnalyser *barAnalyser, - XTriggerBlock &triggerBlock, - X121XCatbConditions &conditions, - XTriggerBlockFilters &filters, - int barIndex = 0, - int loopback = 10 // -) -{ - // - bool result = false; - - // - // Checking Conditions ... - - // - // Normalize Args ... - conditions.Clean(); - barIndex = NormalizeInt(barIndex, 0); - loopback = NormalizeInt(loopback, 0); - - // - // Validate Args ... - result = - helper != NULL && - barAnalyser != NULL && - triggerBlock.IsValid(); - if (!result) - { - return result; - } - - // - // Reading Market Conditions ... - result = helper.GetConditions( - conditions, - barIndex, - loopback // - ); - if (!result) - { - // - conditions.Clean(); - - // - return result; - } - - // - int zIDX = 0; - int cIDX = zIDX + 1; - int pIDX = cIDX + 1; - int p2IDX = pIDX + 1; - int p3IDX = p2IDX + 1; - int p4IDX = p3IDX + 1; - - // - XOHCL iBar; - int toIDX = -1; - int fromIDX = -1; - bool has = false; - bool isBullish = triggerBlock.IsBullish(); - bool isBearish = triggerBlock.IsBearish(); - double points = GetPoints(triggerBlock.ob.symbol); - ENUM_X_DIRECTION iDir = triggerBlock.GetDirection(); - - // - // Checking Conditions ... - - // - // Filter Based On PV ... - if (result && - filters.filterBasedOnPV) - { - // - // For PV Filtering ... - - // - // Detect BOS ... - - // - // When Loopback for BOS has Specified Value ... - // we Lookup for BOS on Specific Period ... - if (filters.bosLoopback > 0) - { - // - has = true; - int fBOSIDX = -1; - int rBOSIDX = -1; - bool isBOS = false; - bool isFBOS = false; - bool isRBOS = false; - bool isPeakOverLast = false; - bool isValeUnderLast = false; - toIDX = triggerBlock.ob.ToIndex(); - fromIDX = triggerBlock.ob.FromIndex(); - int sIDX = fromIDX; - while (has) - { - // - double iPeak = helper.GetPeak(sIDX); - double iPPeak = helper.GetPeak(sIDX + 1); - - // - double iVale = helper.GetVale(sIDX); - double iPVale = helper.GetVale(sIDX + 1); - - // - isPeakOverLast = - iPeak > 0 && - iPeak > iPPeak; - - // - isValeUnderLast = - iVale > 0 && - iVale < iPVale; - - // - isFBOS = - isBullish - ? isPeakOverLast - : isValeUnderLast; - if (isFBOS) - { - fBOSIDX = sIDX; - } - - // - isRBOS = - isBullish - ? isValeUnderLast - : isPeakOverLast; - if (isRBOS) - { - rBOSIDX = sIDX; - } - - // - isBOS = - (isBullish && - isPeakOverLast) || - (isBearish && - isValeUnderLast); - if (isBOS) - { - break; - } - - // - sIDX++; - has = !isBOS && - sIDX < fromIDX + filters.bosLoopback; - } - - // - isFBOS = IsValidIndex(fBOSIDX); - isRBOS = IsValidIndex(rBOSIDX); - - // - result = isBOS && - isFBOS && - !isRBOS; - } - - // - // When Loopback for BOS has not Specified Value ... - // we Lookup for BOS on GAP End Bar ... - if (filters.bosLoopback <= 0) - { - // - toIDX = triggerBlock.ToIndex(); - - // - // Initialize iBar ... - result = iBar.Init( - conditions.symbol, - conditions.period, - toIDX // - ); - result = - result && - (isBullish ? iBar.high > helper.GetPeak(toIDX + 1) - : iBar.low < helper.GetVale(toIDX + 1)); - } - } - - // - // Filter Based on SAR ... - if (result && - filters.filterBasedOnSar) - { - // - toIDX = triggerBlock.ToIndex(); - fromIDX = triggerBlock.FromIndex(); - - // - double iSarState = helper.GetSarState(toIDX); - double iPSarState = helper.GetSarState(toIDX + 1); - - // - double iFSarState = helper.GetSarState(fromIDX); - double iPFSarState = helper.GetSarState(fromIDX + 1); - - // - bool isSarBullish = - iSarState > 0; - - // - bool isSarBearish = - iSarState < 0; - - // - bool isFSarBullish = - iFSarState > 0; - - // - bool isFSarBearish = - iFSarState < 0; - - // - bool isSarSwitchedToBullish = - iSarState > 0 && - iPSarState <= 0; - - // - bool isSarSwitchedToBearish = - iSarState < 0 && - iPSarState >= 0; - - // - bool isFSarSwitchedToBullish = - iFSarState > 0 && - iPFSarState <= 0; - - // - bool isFSarSwitchedToBearish = - iFSarState < 0 && - iPFSarState >= 0; - - // - // Creating Filters ... - - // - bool isToFilterPassed = - !filters.forceSarSwitched - ? (isBullish - ? isSarBullish - : isSarBearish) - : (isBullish - ? isSarSwitchedToBullish - : isSarSwitchedToBearish); - - // - bool isFromFilterPassed = - !filters.forceSarSwitched - ? (isBullish - ? isFSarBullish - : isFSarBearish) - : (isBullish - ? isFSarSwitchedToBullish - : isFSarSwitchedToBearish); - - // - result = - !filters.forceSarOnBothSide - ? isToFilterPassed - : isToFilterPassed && - isFromFilterPassed; - - // - // Check Sar Has Reversal Direction inside Trigger Block ... - if (result && - filters.forceSarHasReversalSide) - { - // - toIDX = triggerBlock.ToIndex(); - fromIDX = triggerBlock.FromIndex(); - for (int i = toIDX; i < fromIDX; i++) - { - // - double iSarState = helper.GetSarState(i); - - // - has = - isBullish - ? iSarState > 0 - : iSarState < 0; - if (has) - { - break; - } - } - - // - result = has; - } - - // - // Force Sar Breakouts ... - // in this Senario Sar must in following Direction and - // there is not any Switches ... - // but must breakout Bar the last in Reversal Direction - // of Sar ... - if (result && - filters.forceSarHasBreakout) - { - // - bool isSarBullishStart = - // - ( - // - // Current SAR is Directional ... - conditions.isSarBullish && - // - // Previous InDirectional Sar Exists ... - helper.lastSarBearish.IsValid() && - // - // Current Close is Over previous Sar ... - conditions.bars[cIDX].close > helper.lastSarBearish.after && - // - // Before Close is not Over previous Sar ... - conditions.bars[pIDX].close <= helper.lastSarBearish.after - // - ) - // - ; - - // - bool isSarBearishStart = - // - ( - // - // Current SAR is Directional ... - conditions.isSarBearish && - // - // Previous InDirectional Sar Exists ... - helper.lastSarBullish.IsValid() && - // - // Current Close is Under previous ... - conditions.bars[cIDX].close < helper.lastSarBullish.after && - // - // Before Close is not Under previous ... - conditions.bars[pIDX].close >= helper.lastSarBullish.after - // - ) - // - ; - - // - result = - isBullish - ? isSarBullishStart - : isSarBearishStart; - } - } - - // - // Filter Based On RSI ... - if (result && - filters.filterBasedOnRSI) - { - // - // Here We Can Apply RSI Filters ... - // Since RSI Filters must be Check on FVG Bars ... - // we Have to Loop back Based on FVG Bars to Detect Conditions ... - double rsiTrend = (conditions.rsiOBLevel + conditions.rsiOSLevel) / 2; - - // - toIDX = triggerBlock.fvg.ToIndex(); - fromIDX = triggerBlock.fvg.FromIndex(); - - // - // Filter Using RSI Trending ... - if (result && - filters.forceHasRSITrending) - { - // - for (int i = toIDX; i < fromIDX; i++) - { - // - double iRSI = helper.GetRSI(i); - double iPRSI = helper.GetRSI(i + 1); - - // - has = - (isBullish - ? (iRSI > rsiTrend && - iRSI > iPRSI) - : (iRSI < rsiTrend && - iRSI < iPRSI)); - if (has) - { - break; - } - } - - // - result = has; - } - - // - // Filter Using RSI V Pattern ... - if (result && - filters.forceHasRSIVPattern) - { - // - for (int i = toIDX; i < fromIDX; i++) - { - // - double iRSI = helper.GetRSI(i); - double iPRSI = helper.GetRSI(i + 1); - double iP2RSI = helper.GetRSI(i + 2); - - // - bool isRSIVBullish = - iRSI > iPRSI && - iP2RSI > iPRSI; - - // - bool isRSIVBearish = - iRSI < iPRSI && - iP2RSI < iPRSI; - - // - has = - (isBullish - ? isRSIVBullish - : isRSIVBearish); - if (has) - { - break; - } - } - - // - result = has; - } - - // - // Filter Using RSI Crossing on OB/OS Levels ... - if (result && - filters.forceHasRSICrossing) - { - // - for (int i = toIDX; i < fromIDX; i++) - { - // - double iRSI = helper.GetRSI(i); - double iPRSI = helper.GetRSI(i + 1); - - // - bool isRSICrossedOverOS = - iRSI > conditions.rsiOSLevel && - iPRSI <= conditions.rsiOSLevel; - - // - bool isRSICrossedUnderOB = - iRSI < conditions.rsiOBLevel && - iPRSI >= conditions.rsiOBLevel; - - // - has = - (isBullish - ? isRSICrossedOverOS - : isRSICrossedUnderOB); - if (has) - { - break; - } - } - - // - result = has; - } - } - - // - // Filter Based On ADX ... - if (result && - filters.filterBasedOnADX) - { - // - // Here We Can Apply ADX Filters ... - // Since ADX Filters must be Check on FVG Bars ... - // we Have to Loop back Based on FVG Bars to Detect Conditions ... - - // - toIDX = triggerBlock.fvg.ToIndex(); - fromIDX = triggerBlock.fvg.FromIndex(); - - // - // Filter Using ADX Trending ... - if (result && - filters.forceHasADXTrending) - { - // - for (int i = toIDX; i < fromIDX; i++) - { - // - double iADX = helper.GetADX(i); - double iPADX = helper.GetADX(i + 1); - - // - has = iADX > conditions.adxThreshold && - iADX > iPADX; - if (has) - { - break; - } - } - - // - result = has; - } - - // - // Filter Using ADX Crossing on +DI/-DI ... - if (result && - filters.forceHasADXCrossing) - { - // - for (int i = toIDX; i < fromIDX; i++) - { - // - double iDIPlus = helper.GetADXP(i); - double iPDIPlus = helper.GetADXP(i + 1); - - // - double iDIMinus = helper.GetADXN(i); - double iPDIMinus = helper.GetADXN(i + 1); - - // - bool isADXPlusCrossedOverMinus = - iDIPlus > iDIMinus && - iPDIPlus <= iDIMinus; - - // - bool isADXMinusCrossedOverPlus = - iDIMinus > iDIPlus && - iPDIMinus <= iDIPlus; - - // - has = - isBullish - ? isADXPlusCrossedOverMinus - : isADXMinusCrossedOverPlus; - if (has) - { - break; - } - } - - // - result = has; - } - } - - // - // Filter Based On ATR Band ... - if (result && - filters.filterBasedOnATR) - { - // - // Here We Can Apply ATR Filters ... - // Since ATR Filters must be Check on OB Bars ... - // we Have to Loop back Based on OB Bars to Detect Conditions ... - - // - toIDX = triggerBlock.ob.ToIndex(); - fromIDX = triggerBlock.ob.FromIndex(); - - // - // Filter Using ATR Trending ... - if (result && - filters.forceHasATRTrending) - { - // - for (int i = toIDX; i < fromIDX; i++) - { - // - double iATRUpper = helper.GetATRUpper(i); - double iPATRUpper = helper.GetATRUpper(i + 1); - - // - double iATRLower = helper.GetATRLower(i); - double iPATRLower = helper.GetATRLower(i + 1); - - // - bool isATRUp = - iATRLower > iPATRLower; - - // - bool isATRDown = - iATRUpper < iPATRUpper; - - // - has = isBullish - ? isATRUp - : isATRDown; - if (has) - { - break; - } - } - - // - result = has; - } - - // - // Filter Using ATR Breakout ... - if (result && - filters.forceHasATRBreakout) - { - // - for (int i = toIDX; i < fromIDX; i++) - { - // - double iATRUpper = helper.GetATRUpper(i); - double iATRLower = helper.GetATRLower(i); - - // - has = isBullish - ? triggerBlock.ob.lower < iATRLower - : triggerBlock.ob.upper > iATRUpper; - if (has) - { - break; - } - } - - // - result = has; - } - } - - // - // Filter Based On Trend ... - if (result && - filters.filterBasedOnTrend) - { - // - toIDX = triggerBlock.fvg.ToIndex(); - fromIDX = triggerBlock.fvg.FromIndex(); - - // - // Filter Using Trend Direction ... - if (result && - filters.forceHasTrendDir) - { - // - result = - result && - isBullish - ? conditions.isTrendBullish - : conditions.isTrendBearish; - } - - // - // Filter Using Trend Direction On Both Side ... - if (result && - filters.forceHasTrendDirOnBothSide) - { - // - // Side To ... - result = - result && - isBullish - ? conditions.isTrendBullish - : conditions.isTrendBearish; - - // - // Side From ... - int sFIDX = triggerBlock.ob.FromIndex(); - double sFTrendState = helper.GetTrendState(sFIDX); - result = - result && - isBullish - ? sFTrendState > 0 - : sFTrendState < 0; - } - - // - // Filter Using Trend Change ... - if (result && - filters.forceHasTrendChange) - { - // - for (int i = toIDX; i < fromIDX; i++) - { - // - double iTrendState = helper.GetTrendState(i); - double iPTrendState = helper.GetTrendState(i + 1); - - // - bool isTrendSwitchedToBullish = - iTrendState > 0 && - iPTrendState <= 0; - - // - bool isTrendSwitchedToBearish = - iTrendState < 0 && - iPTrendState >= 0; - - // - has = - isBullish - ? isTrendSwitchedToBullish - : isTrendSwitchedToBearish; - if (has) - { - break; - } - } - - // - result = has; - } - - // - // Filter Using Trend Trending ... - if (result && - filters.forceHasTrendTrending) - { - // - result = - result && - (isBullish - ? conditions.trendBuffer[cIDX] > conditions.trendBuffer[pIDX] - : conditions.trendBuffer[cIDX] < conditions.trendBuffer[pIDX]); - } - - // - // Filter Using Trend Rejection ... - if (result && - filters.forceHasTrendRejection) - { - // - toIDX = triggerBlock.ob.ToIndex(); - fromIDX = triggerBlock.ob.FromIndex(); - for (int i = toIDX; i < fromIDX; i++) - { - // - // Initialize iBar ... - has = iBar.Init( - conditions.symbol, - conditions.period, - i // - ); - - // - // Read Trend Value ... - double iTrend = helper.GetTrend(i); - - // - bool isTrendBullishRejected = - has && - iBar.low < iTrend && - iBar.GetDown() > iTrend; - - // - bool isTrendBearishRejected = - has && - iBar.high > iTrend && - iBar.GetUp() < iTrend; - - // - has = - has && - (isBullish - ? isTrendBullishRejected - : isTrendBearishRejected); - if (has) - { - break; - } - } - - // - result = has; - } - - // - // Filter Using Trend Inside ... - if (result && - filters.forceHasTrendLineInside) - { - // - result = - result && - conditions.trendBuffer[cIDX] > triggerBlock.ob.lower && - conditions.trendBuffer[cIDX] < triggerBlock.ob.upper; - } - - // - // Filter Using Trend Place ... - if (result && - filters.forceHasTrendPlace) - { - // - toIDX = triggerBlock.ob.ToIndex(); - fromIDX = triggerBlock.ob.FromIndex(); - double mult = - isBullish - ? 1 - : -1; - double edge = isBullish - ? triggerBlock.ob.lower - : triggerBlock.ob.upper; - double factor = edge + (mult * (triggerBlock.ob.GetRange() / 4)); - for (int i = toIDX; i < fromIDX; i++) - { - // - double iTrend = helper.GetTrend(i); - - // - has = - isBullish - ? factor >= iTrend - : factor <= iTrend; - if (has) - { - break; - } - } - - // - result = has; - } - } - - // - // Filter Using Delta ... - if (result && - filters.filterBasedOnDelta) - { - // - toIDX = triggerBlock.ob.ToIndex(); - fromIDX = triggerBlock.ob.FromIndex(); - - // - for (int i = toIDX; i < fromIDX; i++) - { - // - double iDelta = helper.GetDelta(i); - double iPDelta = helper.GetDelta(i + 1); - - // - double iDeltaSignal = helper.GetDeltaSignal(i); - double iPDeltaSignal = helper.GetDeltaSignal(i + 1); - - // - bool isDeltaUp = - iDelta > iPDelta; - - // - bool isDeltaDown = - iDelta < iPDelta; - - // - bool isDeltaSignalUp = - iDeltaSignal > iPDeltaSignal; - - // - bool isDeltaSignalDown = - iDeltaSignal < iPDeltaSignal; - - // - bool isDeltaCrossedOverSignal = - iDelta > iDeltaSignal && - iPDelta <= iPDeltaSignal; - - // - bool isDeltaCrossedUnderSignal = - iDelta < iDeltaSignal && - iPDelta >= iPDeltaSignal; - - // - has = - isBullish - ? (isDeltaUp && - isDeltaSignalUp && - isDeltaCrossedOverSignal) - : (isDeltaDown && - isDeltaSignalDown && - isDeltaCrossedUnderSignal); - if (has) - { - break; - } - } - - // - result = has; - } - - // - // Filter Using Volume ... - if (result && - filters.filterBasedOnVolume) - { - // - toIDX = triggerBlock.ob.ToIndex(); - fromIDX = triggerBlock.ob.FromIndex(); - - // - for (int i = toIDX; i < fromIDX; i++) - { - // - double iBullVolume = helper.GetBullishVolume(i); - double iPBullVolume = helper.GetBullishVolume(i + 1); - - // - double iBullVolumeSignal = helper.GetBullishVolumeSignal(i); - double iPBullVolumeSignal = helper.GetBullishVolumeSignal(i + 1); - - // - double iBearVolume = helper.GetBearishVolume(i); - double iPBearVolume = helper.GetBearishVolume(i + 1); - - // - double iBearVolumeSignal = helper.GetBearishVolumeSignal(i); - double iPBearVolumeSignal = helper.GetBearishVolumeSignal(i + 1); - - // - bool isBullVolumeUp = - iBullVolume > iPBullVolume; - - // - bool isBullVolumeSignalUp = - iBullVolumeSignal > iPBullVolumeSignal; - - // - bool isBearVolumeUp = - iBearVolume > iPBearVolume; - - // - bool isBearVolumeSignalUp = - iBearVolumeSignal > iPBearVolumeSignal; - - // - bool isVolumeSwitchedToBullish = - iBullVolumeSignal > iBearVolumeSignal && - iPBullVolumeSignal <= iPBearVolumeSignal; - - // - bool isVolumeSwitchedToBearish = - iBearVolumeSignal > iBullVolumeSignal && - iPBearVolumeSignal <= iPBullVolumeSignal; - - // - has = - isBullish - ? (isBullVolumeUp && - isBullVolumeSignalUp && - isVolumeSwitchedToBullish) - : (isBearVolumeUp && - isBearVolumeSignalUp && - isVolumeSwitchedToBearish); - if (has) - { - break; - } - } - - // - result = has; - } - - // - // Filter Using Signal Bar ... - if (result && - filters.filterBasedOnSignalBar) - { - // - toIDX = triggerBlock.ob.ToIndex(); - fromIDX = triggerBlock.ob.FromIndex(); - - // - double iSOpen = helper.GetSBarOpen(toIDX); - double iPSOpen = helper.GetSBarOpen(toIDX + 1); - - // - double iSClose = helper.GetSBarClose(toIDX); - double iPSClose = helper.GetSBarClose(toIDX + 1); - - // - double iSPow = MathAbs(iSOpen - iSClose); - double iPSPow = MathAbs(iPSOpen - iPSClose); - - // - result = - result && - iSPow > iPSPow && - (isBullish - ? iSClose > iSOpen - : iSClose < iSOpen); - - // - // Now Looking for Dir Change ... - if (result) - { - // - for (int i = toIDX; i < fromIDX; i++) - { - // - iSOpen = helper.GetSBarOpen(toIDX); - iPSOpen = helper.GetSBarOpen(toIDX + 1); - - // - iSClose = helper.GetSBarClose(toIDX); - iPSClose = helper.GetSBarClose(toIDX + 1); - - // - bool isSBullish = - iSClose > iSOpen; - - // - bool isPSBullish = - iPSClose > iPSOpen; - - // - bool isSBearish = - iSClose < iSOpen; - - // - bool isPSBearish = - iPSClose < iPSOpen; - - // - bool isSSwitchedToBullish = - isSBullish && - !isPSBullish; - - // - bool isSSwitchedToBearish = - isSBearish && - !isPSBearish; - - // - has = - isBullish - ? isSSwitchedToBullish - : isSSwitchedToBearish; - if (has) - { - break; - } - } - - // - result = has; - } - } - - // - // Filter Using Signal Bar ... - if (result && - filters.filterBasedOnHKSignalBar) - { - // - toIDX = triggerBlock.ob.ToIndex(); - fromIDX = triggerBlock.ob.FromIndex(); - - // - double iSOpen = helper.GetHKSBarOpen(toIDX); - double iPSOpen = helper.GetHKSBarOpen(toIDX + 1); - - // - double iSClose = helper.GetHKSBarClose(toIDX); - double iPSClose = helper.GetHKSBarClose(toIDX + 1); - - // - double iSPow = MathAbs(iSOpen - iSClose); - double iPSPow = MathAbs(iPSOpen - iPSClose); - - // - result = - result && - iSPow > iPSPow && - (isBullish - ? iSClose > iSOpen - : iSClose < iSOpen); - - // - // Now Looking for Dir Change ... - if (result) - { - // - for (int i = toIDX; i < fromIDX; i++) - { - // - iSOpen = helper.GetHKSBarOpen(toIDX); - iPSOpen = helper.GetHKSBarOpen(toIDX + 1); - - // - iSClose = helper.GetHKSBarClose(toIDX); - iPSClose = helper.GetHKSBarClose(toIDX + 1); - - // - bool isSBullish = - iSClose > iSOpen; - - // - bool isPSBullish = - iPSClose > iPSOpen; - - // - bool isSBearish = - iSClose < iSOpen; - - // - bool isPSBearish = - iPSClose < iPSOpen; - - // - bool isSSwitchedToBullish = - isSBullish && - !isPSBullish; - - // - bool isSSwitchedToBearish = - isSBearish && - !isPSBearish; - - // - has = - isBullish - ? isSSwitchedToBullish - : isSSwitchedToBearish; - if (has) - { - break; - } - } - - // - result = has; - } - } - - // - if (!result) - { - triggerBlock.Clean(); - } - - // - // Summarize result ... - result = triggerBlock.IsValid(); - - // - // Cleanup Resources ... - - // - iBar.Clean(); - - // - if (!result) - { - // - conditions.Clean(); - triggerBlock.Clean(); - } - - // - return result; -} - -// -void ValidateTriggerBlockLiquidities( - XCX121XCatbHelper *helper, - XCBarAnalyser *barAnalyser, - XTriggerBlock &triggerBlock, - X121XCatbConditions &conditions, - XTriggerBlockValidationRules &validations // -) -{ - // - bool has = false; - - // - has = - helper != NULL && - barAnalyser != NULL && - triggerBlock.IsValid() && - (triggerBlock.fLiquidity.IsValid() || - triggerBlock.rLiquidity.IsValid()); - if (!has) - { - return; - } - - // - bool hasFLiq = triggerBlock.fLiquidity.IsValid(); - bool hasRLiq = triggerBlock.rLiquidity.IsValid(); - - // - // TODO: Implement Liquidity Validation ... -} - -// -bool DetectSignalZone( - XCPOIDrawer *&drawer, - XCX121XCatbHelper *helper, - XCBarAnalyser *barAnalyser, - XBoxZone &signalZone, - X121XCatbConditions &conditions, - int barIndex = 0, - int loopback = 10 // -) -{ - // - bool result = false; - - // - // Checking Conditions ... - - // - // Normalize Args ... - signalZone.Clean(); - conditions.Clean(); - barIndex = NormalizeInt(barIndex, 0); - loopback = NormalizeInt(loopback, 0); - - // - // Validate Args ... - result = helper != NULL && - barAnalyser != NULL; - if (!result) - { - return result; - } - - // - // Reading Market Conditions ... - result = helper.GetConditions( - conditions, - barIndex, - loopback // - ); - if (!result) - { - // - signalZone.Clean(); - conditions.Clean(); - - // - return result; - } - - // - int zIDX = 0; - int cIDX = zIDX + 1; - int pIDX = cIDX + 1; - int p2IDX = pIDX + 1; - int p3IDX = p2IDX + 1; - int p4IDX = p3IDX + 1; - - // - double sl = 0; - double tp = 0; - double upper = 0; - double lower = 0; - datetime to = NULL; - datetime from = NULL; - string signalProvider = NULL; - - // - // Checking Conditions ... - - // - // Detect Bar Verifications ... - - // - ENUM_X_DIRECTION iDir; - - // - // Rejected ... - bool isRejected = - barAnalyser - .IsRejected( - conditions.bars[cIDX], - iDir // - ); - bool isBullishRejected = - isRejected && - IsBullish(iDir); - bool isBearishRejected = - isRejected && - IsBearish(iDir); - - // - // Engulfed ... - bool isEngulfed = - barAnalyser - .IsEngulfed( - conditions.bars[cIDX], - iDir // - ); - bool isBullishEngulfed = - isEngulfed && - IsBullish(iDir); - bool isBearishEngulfed = - isEngulfed && - IsBearish(iDir); - - // - // Momentum ... - bool isMomentum = - barAnalyser - .IsMomentum( - conditions.bars[cIDX], - iDir // - ); - bool isBullishMomentum = - isMomentum && - IsBullish(iDir); - bool isBearishMomentum = - isMomentum && - IsBearish(iDir); - - // - bool isBarBullishPressured = - isBullishRejected || - isBullishEngulfed || - isBullishMomentum; - - // - bool isBarBearishPressured = - isBearishRejected || - isBearishEngulfed || - isBearishMomentum; - - // - // Detect Indicator Base Start Directional Movement ... - - // - // SAR ... - - // - bool isSarBullishStart = - // - ( - // - // Current SAR is Directional ... - conditions.isSarBullish && - // - // Previous InDirectional Sar Exists ... - helper.lastSarBearish.IsValid() && - // - // Current Close is Over previous Sar ... - conditions.bars[cIDX].close > helper.lastSarBearish.after && - // - // Before Close is not Over previous Sar ... - conditions.bars[pIDX].close <= helper.lastSarBearish.after - // - ) - // - ; - - // - bool isSarBearishStart = - // - ( - // - // Current SAR is Directional ... - conditions.isSarBearish && - // - // Previous InDirectional Sar Exists ... - helper.lastSarBullish.IsValid() && - // - // Current Close is Under previous ... - conditions.bars[cIDX].close < helper.lastSarBullish.after && - // - // Before Close is not Under previous ... - conditions.bars[pIDX].close >= helper.lastSarBullish.after - // - ) - // - ; - - // - // TREND ... - - // - bool isTrendBullishStart = - // - ( - // - // Current Trend is Directional ... - conditions.isTrendBullish && - // - // Previous InDirectiona; Trend Exists ... - helper.lastTrendBearish.IsValid() && - // - // Current Close is Over previous ... - conditions.bars[cIDX].close > helper.lastTrendBearish.after && - // - // Before close is not Over previous ... - conditions.bars[pIDX].close <= helper.lastTrendBearish.after - // - ) - // - ; - - // - bool isTrendBearishStart = - // - ( - // - // Current Trend is Directional ... - conditions.isTrendBearish && - // - // Previous InDirectiona; Trend Exists ... - helper.lastTrendBullish.IsValid() && - // - // Current Close is Under previous ... - conditions.bars[cIDX].close < helper.lastTrendBullish.after && - // - // Before close is not Under previous ... - conditions.bars[pIDX].close >= helper.lastTrendBullish.after - // - ) - // - ; - - // - // ADX ... - - // - bool isADXBullishStart = - // - ( - // - // ADX Value is Switched to Strong ... - conditions.adxBuffer[cIDX] > conditions.adxThreshold && - conditions.adxBuffer[pIDX] <= conditions.adxThreshold && - // - // ADX must Up ... - conditions.adxBuffer[cIDX] > conditions.adxBuffer[pIDX] && - // - // ADX +DI is Bigger than -DI ... - conditions.adxpBuffer[cIDX] > conditions.adxnBuffer[cIDX] && - // - // ADX +DI is Up ... - conditions.adxpBuffer[cIDX] > conditions.adxpBuffer[pIDX] - // - ) - // - ; - - // - bool isADXBearishStart = - // - ( - // - // ADX Value is Switched to Strong ... - conditions.adxBuffer[cIDX] > conditions.adxThreshold && - conditions.adxBuffer[pIDX] <= conditions.adxThreshold && - // - // ADX must Up ... - conditions.adxBuffer[cIDX] > conditions.adxBuffer[pIDX] && - // - // ADX -DI is Bigger than +DI ... - conditions.adxnBuffer[cIDX] > conditions.adxpBuffer[cIDX] && - // - // ADX -DI is Up ... - conditions.adxnBuffer[cIDX] > conditions.adxnBuffer[pIDX] - // - ) - // - ; - - // - // DELTA ... - - // - bool isDeltaBullishStart = - // - // Check State ... - ( - // - // Delta is Up ... - conditions.deltaBuffer[cIDX] > conditions.deltaBuffer[pIDX] && - // - // Delta Signal is Up ... - conditions.deltaSignalBuffer[cIDX] > conditions.deltaSignalBuffer[pIDX] && - // - // Delta Crossed Over Delta Signal ... - conditions.deltaBuffer[cIDX] > conditions.deltaSignalBuffer[cIDX] - // - ) - // - && - // - // Check Last InDirectional Exists ... - helper.lastDeltaBearish.IsValid() && - // - // Current Close is Over last ... - conditions.bars[cIDX].close > helper.lastDeltaBearish.after && - // - // Before Close is not Over last ... - conditions.bars[pIDX].close <= helper.lastDeltaBearish.after - // - ; - - // - bool isDeltaBearishStart = - // - // Check State ... - ( - // - // Delta is Down ... - conditions.deltaBuffer[cIDX] < conditions.deltaBuffer[pIDX] && - // - // Delta Signal is Down ... - conditions.deltaSignalBuffer[cIDX] < conditions.deltaSignalBuffer[pIDX] && - // - // Delta Crossed Under Delta Signal ... - conditions.deltaBuffer[cIDX] < conditions.deltaSignalBuffer[cIDX] - // - ) - // - && - // - // Check Last InDirectional Exists ... - helper.lastDeltaBullish.IsValid() && - // - // Current Close is Under last ... - conditions.bars[cIDX].close < helper.lastDeltaBullish.after && - // - // Before Close is not Under last ... - conditions.bars[pIDX].close >= helper.lastDeltaBullish.after - // - ; - - // - // VOLUME ... - - // - bool isVolumeBullishStart = - // - ( - // - // - // Volume is Up ... - conditions.bullishVolumeBuffer[1] > conditions.bullishVolumeBuffer[2] && - // - // Volume Signal is Up ... - conditions.bullishVolumeSignalBuffer[1] > conditions.bullishVolumeSignalBuffer[2] && - // - // Volume Signals Crossed Over ... - conditions.bullishVolumeSignalBuffer[1] > conditions.bearishVolumeSignalBuffer[1] - // - ) - // - && - // - // Check Last InDirectional Exists ... - helper.lastVolumeBearish.IsValid() && - // - // Current Close is Over last ... - conditions.bars[cIDX].close > helper.lastVolumeBearish.after && - // - // Before Close is not Over last ... - conditions.bars[pIDX].close <= helper.lastVolumeBearish.after - // - ; - - // - bool isVolumeBearishStart = - // - ( - // - // - // Volume is Up ... - conditions.bearishVolumeBuffer[1] > conditions.bearishVolumeBuffer[2] && - // - // Volume Signal is Up ... - conditions.bearishVolumeSignalBuffer[1] > conditions.bearishVolumeSignalBuffer[2] && - // - // Volume Signals Crossed Over ... - conditions.bearishVolumeSignalBuffer[1] > conditions.bullishVolumeSignalBuffer[1] - // - ) - // - && - // - // Check Last InDirectional Exists ... - helper.lastVolumeBullish.IsValid() && - // - // Current Close is Over last ... - conditions.bars[cIDX].close < helper.lastVolumeBullish.after && - // - // Before Close is not Over last ... - conditions.bars[pIDX].close >= helper.lastVolumeBullish.after - // - ; - - // - // SIGNAL Bar ... - - // - bool isSBarBullishStart = - // - ( - // - // Check Direction ... - conditions.isSBarBullish && - // - // Previous InDirectional Exists ... - helper.lastSignalBarBearish.IsValid() && - // - // Current Signal Bar close over prev ... - conditions.sBarCloseBuffer[cIDX] > helper.lastSignalBarBearish.after && - // - // Prev Signal Bar not close over prev ... - conditions.sBarCloseBuffer[pIDX] <= helper.lastSignalBarBearish.after - // - ) - // - ; - - // - bool isSBarBearishStart = - // - ( - // - // Check Direction ... - conditions.isSBarBearish && - // - // Previous InDirectional Exists ... - helper.lastSignalBarBullish.IsValid() && - // - // Current Signal Bar close over prev ... - conditions.sBarCloseBuffer[cIDX] < helper.lastSignalBarBullish.after && - // - // Prev Signal Bar not close over prev ... - conditions.sBarCloseBuffer[pIDX] >= helper.lastSignalBarBullish.after - // - ) - // - ; - - // - // HKSIGNAL Bar ... - - // - bool isHKSBarBullishStart = - // - ( - // - // Check Direction ... - conditions.isHKSBarBullish && - // - // Previous InDirectional Exists ... - helper.lastHKSignalBarBearish.IsValid() && - // - // Current Signal Bar close over prev ... - conditions.hkSBarCloseBuffer[cIDX] > helper.lastHKSignalBarBearish.after && - // - // Prev Signal Bar not close over prev ... - conditions.hkSBarCloseBuffer[pIDX] <= helper.lastHKSignalBarBearish.after - // - ) - // - ; - - // - bool isHKSBarBearishStart = - // - ( - // - // Check Direction ... - conditions.isHKSBarBearish && - // - // Previous InDirectional Exists ... - helper.lastHKSignalBarBullish.IsValid() && - // - // Current Signal Bar close over prev ... - conditions.hkSBarCloseBuffer[cIDX] < helper.lastHKSignalBarBullish.after && - // - // Prev Signal Bar not close over prev ... - conditions.hkSBarCloseBuffer[pIDX] >= helper.lastHKSignalBarBullish.after - // - ) - // - ; - - // - // Check for Vale and Peak ... - - // - bool isPeakOverLast = - // - (conditions.peakBuffer[cIDX] > conditions.peakBuffer[pIDX] && - conditions.peakBuffer[pIDX] <= conditions.peakBuffer[p2IDX] && - conditions.bars[cIDX].close > conditions.peakBuffer[pIDX]) - // - ; - - // - bool isValeUnderLast = - // - (conditions.valeBuffer[cIDX] < conditions.valeBuffer[pIDX] && - conditions.valeBuffer[pIDX] >= conditions.valeBuffer[p2IDX] && - conditions.bars[cIDX].close < conditions.valeBuffer[pIDX]) - // - ; - - // - // Start Different Conditions Implemntation ... - - // - // Condition 1: - // --------------------------- - // Descriptions: - // - // - // --------------------------- - - // - // Bullish ... - bool isCond1Bullish = false; - - // - // Bearish ... - bool isCond1Bearish = false; - - // - bool isCond1 = - isCond1Bullish || - isCond1Bearish; - if (isCond1) - { - // - // Prepare Cond1 Based Requirements ... - - // - to = NULL; - upper = 0; - lower = 0; - from = NULL; - - // - // Provider Definition ... - signalProvider = "Cond1"; - } - - // - // Try to Summarize Conditions ... - - // - bool isBullish = - // - isCond1Bullish - // - ; - - // - bool isBearish = - // - isCond1Bearish - // - ; - - // - // Summarize Result ... - result = - isBullish || - isBearish; - if (result) - { - // - // Prepare Signal Zone ... - - // - signalZone.to = to; - signalZone.from = from; - signalZone.upper = upper; - signalZone.lower = lower; - signalZone.type = signalProvider; - signalZone.symbol = conditions.symbol; - signalZone.period = conditions.period; - - // - signalZone.dir = - isBullish - ? X_DIRECTION_BULLISH - : X_DIRECTION_BEARISH; - - // - // Validate Signal Zone ... - result = signalZone.IsValid(); - } - - // - // Cleanup Resources ... - - // - if (!result) - { - // - signalZone.Clean(); - conditions.Clean(); - } - - // - return result; -} - -// -// Draw Specific Trigger Block ... -bool DrawTriggerBlock( - XTriggerBlock &trigger, - XCPOIDrawer *drawer, - CArrayObj &objects, - datetime to = NULL, - // - bool _drawSignals = false, - int rrZoneLength = 10, - // Styles ... - // - // Trigger Block ... - int tbWidth = 1, // Trigger Block Width - color tbBullishColor = clrAqua, // Trigger Block Bullish Color - color tbBearishColor = clrMagenta, // Trigger Block Bearish Color - ENUM_LINE_STYLE tbStyle = STYLE_DASHDOTDOT, // Trigger Block Style - // - // OB ... - int obWidth = 1, // OB Width - color obBullishColor = clrLime, // OB Bullish Color - color obBearishColor = clrRed, // OB Bearish Color - ENUM_LINE_STYLE obStyle = STYLE_DOT, // OB Style - // - // FVG ... - int fvgWidth = 2, // FVG Width - color fvgBullishColor = clrLime, // FVG Bullish Color - color fvgBearishColor = clrRed, // FVG Bearish Color - ENUM_LINE_STYLE fvgStyle = STYLE_SOLID // FVG Style -) -{ - // - bool result = false; - - // - // Validate Args ... - result = trigger.IsValid() && - drawer != NULL; - if (!result) - { - return result; - } - - // - XTriggerBlock _trigger = trigger; - - // - // Update To ... - bool canUpdateTo = IsValid(to); - if (canUpdateTo) - { - // - _trigger.trigger.to = to; - _trigger.rLiquidity.to = to; - _trigger.fLiquidity.to = to; - } - - // - bool isBullish = _trigger.IsBullish(); - - // - // Draw OB ... - if (_trigger.ob.IsValid()) - { - // - XCBoxObject *iOBObj; - result = drawer.DrawBox( - _trigger.ob, - iOBObj // - ); - if (result) - { - // - // Style Object ... - - // - color iClr = - isBullish - ? obBullishColor - : obBearishColor; - - // - iOBObj.BoxColor(iClr); - iOBObj.BoxWidth(obWidth); - iOBObj.BoxStyle(obStyle); - - // - // Store Object ... - objects.Add(iOBObj); - } - ZeroMemory(iOBObj); - - // - if (!result) - { - return result; - } - } - - // - // Draw FVG ... - if (_trigger.fvg.IsValid()) - { - // - XCBoxObject *iFVGObj; - result = drawer.DrawBox( - _trigger.fvg, - iFVGObj // - ); - if (result) - { - // - // Style Object ... - - // - color iClr = - isBullish - ? fvgBullishColor - : fvgBearishColor; - - // - iFVGObj.BoxColor(iClr); - iFVGObj.BoxWidth(fvgWidth); - iFVGObj.BoxStyle(fvgStyle); - - // - // Store Object ... - objects.Add(iFVGObj); - } - ZeroMemory(iFVGObj); - - // - if (!result) - { - return result; - } - } - - // - // Draw Trigger ... - if (_trigger.trigger.IsValid()) - { - // - XCBoxObject *iTriggerObj; - result = drawer.DrawBox( - _trigger.trigger, - iTriggerObj // - ); - if (result) - { - // - // Style Object ... - - // - color iClr = - isBullish - ? tbBullishColor - : tbBearishColor; - - // - iTriggerObj.BoxColor(iClr); - iTriggerObj.BoxWidth(tbWidth); - iTriggerObj.BoxStyle(tbStyle); - - // - // Store Object ... - objects.Add(iTriggerObj); - } - ZeroMemory(iTriggerObj); - - // - if (!result) - { - return result; - } - } - - // - // Draw Liquidities ... - - // - // Reversla Liquidity ... - if (_trigger.rLiquidity.IsValid()) - { - // - XCBoxObject *iLiqObj; - result = drawer.DrawBox( - _trigger.rLiquidity, - iLiqObj // - ); - if (result) - { - objects.Add(iLiqObj); - } - ZeroMemory(iLiqObj); - - // - if (!result) - { - return result; - } - } - - // - // Following Liquidity ... - if (_trigger.fLiquidity.IsValid()) - { - // - XCBoxObject *iLiqObj; - result = drawer.DrawBox( - _trigger.fLiquidity, - iLiqObj // - ); - if (result) - { - objects.Add(iLiqObj); - } - ZeroMemory(iLiqObj); - - // - if (!result) - { - return result; - } - } - - // - // Draw Swing Bar ... - if (_trigger.swingBar.IsValid()) - { - // - color swingColor = - _trigger.fvg.IsBullish() - ? clrAqua - : clrMagenta; - ENUM_X_PRICE swingPType = - _trigger.fvg.IsBullish() - ? X_PRICE_LOW - : X_PRICE_HIGH; - - // - XCBarArrowObject *swingObj; - result = drawer.CreateBarArrow( - _trigger.swingBar, - swingObj, - swingPType, - 159, - swingColor // - ); - if (result) - { - objects.Add(swingObj); - } - ZeroMemory(swingObj); - - // - if (!result) - { - return result; - } - } - - // - // Draw RR of Signal ... - if (_drawSignals && - _trigger.signal.IsValid() && - rrZoneLength > 0) - { - // - XCRRObject *iRRObj; - iRRObj = new XCRRObject(); - result = iRRObj.Create( - drawer.ChartIdentification(), - drawer.SubWindowIdentification(), - _trigger.signal, - rrZoneLength // - ); - if (result) - { - // - int iWidth = 2; - ENUM_LINE_STYLE iStyle = STYLE_SOLID; - - // - iRRObj.TPWidth(iWidth); - iRRObj.SLWidth(iWidth); - iRRObj.EntryWidth(iWidth); - iRRObj.TargetWidth(iWidth); - - // - iRRObj.TPStyle(iStyle); - iRRObj.SLStyle(iStyle); - iRRObj.EntryStyle(iStyle); - iRRObj.TargetStyle(iStyle); - - // - iRRObj.TPColor(clrLime); - iRRObj.SLColor(clrRed); - iRRObj.EntryColor(clrYellow); - iRRObj.TargetColor(clrLightBlue); - - // - objects.Add(iRRObj); - } - ZeroMemory(iRRObj); - - // - if (result) - { - return result; - } - } - - // - return result; -}