diff --git a/Experts/xcatb.test.non.tb.ea.mq5 b/Experts/xcatb.test.non.tb.ea.mq5 new file mode 100644 index 00000000..6f33692d --- /dev/null +++ b/Experts/xcatb.test.non.tb.ea.mq5 @@ -0,0 +1,1074 @@ +/////////////////////////////////////////////////////// +// +// 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-guard.class.mq5" +#include "../Classes/x-saherelm.x-volume.class.mq5" +#include "../XCATBEA/Classes/xcatbea.signaller.nontb.class.mq5" +#include "../XCATBEA/Classes/xcatbea.x-trade.manager.class.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 + +// +// 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 => (ST_04:00_08:30),(TL_10:30_12:00),(NY_16:00_20:00) +input group "Management"; +input string eaSymbols = ""; // Allowed Trading Symbols +input bool eaAllowGuards = false; // Allow Guards +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 eaReportRestrictions = true; // Report Restrictions +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 +input bool eaSaveRestrictions = false; // Save Restriction Reports + +// +// Variables ... + +// +XCAlert *eaAlert; // EA Scope Alert Handler ... +XCTrade *eaTrade; // EA Scope Trade Handler ... +XCGuard *eaGuard; // EA Scope Guard Handler ... +string eaTag = ""; // Specified Alert Tag for EA ... +XCVolume *eaVolume; // EA Scope Voluem Handler ... +XTimeTracker eaTimeTracker; // EA Scope Time Tracker ... +XCXCATBNonTBEASignaller *eaSignallers[]; // EA Signallers Collection ... +XCXCATBEATradeManager *eaTradeManager; // EA Scope Trade Manager ... + +// +// 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 + + // + delete eaAlert; + ZeroMemory(eaAlert); + + // + delete eaTrade; + ZeroMemory(eaTrade); + + // + delete eaGuard; + ZeroMemory(eaGuard); + + // + delete eaVolume; + ZeroMemory(eaVolume); + + // + eaTimeTracker.Clean(); + + // + Clean(eaSignallers); + + // + delete eaTradeManager; + ZeroMemory(eaTradeManager); + + // + DestroyTimer(); +} + +// +// On Tick Handler ... +void OnTick() +{ + // + // Time Report Handling ... + HandleTimeReport(); + + // + // Position Management / Protections Handling ... + eaTradeManager.Manage(); + + // + // Count Signallers ... + bool has = HasChild(eaSignallers); + if (!has) + { + return; + } + + // + XGuard guards[]; + XCATBEAStrategyConditions conditions[]; + + // + int count = ArraySize(eaSignallers); + for (int i = 0; i < count; i++) + { + // + // Retrieve indexed Signaller ... + XCXCATBNonTBEASignaller *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) + { + // + Copy( + iGuards, + guards, + false // Force Clean ... + ); + } + + // + // Check Triggered Conditions ... + has = iConditions.IsValid() && + iConditions.IsSetuped() && + iConditions.CanTrigger(); + if (has) + { + // + AddRef( + iConditions, + conditions // + ); + } + + // + // Cleanup Resources ... + Clean(iGuards); + Clean(iPositions); + iConditions.Clean(); + } + + // + // Do Actions Based on Provided Info ... + + // + // Guards ... + has = HasChild(guards); + if (has) + { + // + // Handle Guards Firing ... + eaGuard.DoGuards(guards); + } + + // + // Triggers ... + has = HasChild(conditions); + if (has) + { + // + // Handle Conditions Triggering ... + TriggerConditions(conditions); + } + + // + // Cleanup Resources ... + + // + Clean(guards); + Clean(conditions); +} + +// +// 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() +{ + // + // 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); + + // + // 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); + eaTradeManager.SaveRestrictions(eaSaveRestrictions); + + // + // Setting Trade Reports ... + eaTradeManager + .SetTradeReports( + eaReportTrades, + eaReportSignals, + eaReportProtector, + eaReportRestrictions, + eaReportAfterTradesBalance // + ); + + // + // Setting Trade Permissions ... + eaTradeManager + .SetTradePermissions( + eaAllowTrade, + eaAllowLongs, + eaAllowShorts // + ); + + // + // Setting Trade Restrictions ... + eaTradeManager + .SetTradeRestrictions( + eaRestrictionsPeriod, + eaMaxAllowedTPs, + eaMaxAllowedSLs, + eaMaxAllowedTrades // + ); + + // + // EA Guard Initialization ... + eaGuard = new XCGuard( + eaTrade // + ); + + // + eaGuard.SetAlertPrefix(eaTag); + eaGuard.SetAlertLogAlerts(eaLogAlerts); + eaGuard.SetAlertMailAlerts(eaMailAlerts); + eaGuard.SetAlertPushAlerts(eaPushAlerts); + eaGuard.SetAlertEnableAlerts(eaEnableAlerts); + eaGuard.SetAlertTerminalAlerts(eaTerminalAlerts); + + // + // Handle Symbols ... + + // + string symbols[]; + int symbolsCount = 0; + if (IsValid(eaSymbols)) + { + // + symbolsCount = SplitContent( + symbols, + eaSymbols, + "," // + ); + } + + // + // Adding Default Symbol, if eaSymbols not Filled ... + if (!HasChild(symbols)) + { + // + Add( + _Symbol, + symbols // + ); + + // + symbolsCount = ArraySize(symbols); + } + bool hasSymbols = HasChild(symbols); + + // + // 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]); + bool 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 Per Symbols ... + if (hasSymbols) + { + // + for (int j = 0; j < symbolsCount; j++) + { + // + eaTradeManager + .SetTradeSession( + symbols[j], + iStart, + iEnd, + iName // + ); + } + } + } + } + } + } + } + } + + // + // Initialize Signallers per Sumbol ... + if (hasSymbols) + { + // + // Prepare Signaller Inputs ... + XCATBNonTBEASignallerInputs iSignallerInputs; + + // + // Common Configs ... + + // + // Provider Name ... + iSignallerInputs.period = _Period; + iSignallerInputs.provider = "XTRGB"; + iSignallerInputs.allowGuards = eaAllowGuards; + iSignallerInputs.riskToRewardRatio = eaSignalR2R; + iSignallerInputs.allowDraws = IsRunningOnTestMode(); + iSignallerInputs.slATRMultiplier = eaSLATRMultiplier; + + // + // CATB Indicator ... + iSignallerInputs.catbInputs.Default(); + iSignallerInputs.catbInputs.Hide(); + + // + // Make Available all Requirement Buffers of XCATB indicator ... + iSignallerInputs.catbInputs.showPV = true; + iSignallerInputs.catbInputs.showKI = true; + iSignallerInputs.catbInputs.showATRBand = true; + iSignallerInputs.catbInputs.showPVGolden = true; + + // + + // + // 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 ... + XCXCATBNonTBEASignaller *iSignaller = new XCXCATBNonTBEASignaller(iSignallerInputs); + + // + // Add it to the Signallers List ... + Add( + iSignaller, + eaSignallers // + ); + + // + ZeroMemory(iSignaller); + } + } + + // + // Cleanup Resources ... + iSignallerInputs.Clean(); + } + + // +} + +/** + * 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 // + ); +} + +/** + * Convert a Triggered Conditions to Signal and + * Execute it ... + */ +void TriggerConditions(XCATBEAStrategyConditions &conditions[]) +{ + // + int count = 0; + bool has = false; + + // + has = HasChild(conditions); + if (!has) + { + return; + } + + // + count = ArraySize(conditions); + for (int i = 0; i < count; i++) + { + // + // Retrieve Indexed Conditions ... + XCATBEAStrategyConditions iConditions = conditions[i]; + + // + // Prepare Signal Based on Conditions ... + XSignal iSignal; + + // + // Check if a Trigger Block Attached and Has Signal ... + // use it ... + has = + iConditions.IsValid() && + iConditions.IsSetuped() && + iConditions.CanTrigger() && + iConditions.triggerBlock.IsValid() && + iConditions.triggerBlock.signal.IsValid(); + if (has) + { + iSignal = iConditions.triggerBlock.signal; + } + + // + // if we Have any other Signalling senarios we can Handle them here ... + + // + // Validate Signal ... + has = iSignal.IsValid(); + if (has) + { + // + // Retrieve Signal Type ... + bool isLong = IsLong(iSignal.type); + + // + // Update Signal Entry ... + iSignal.entry = GetEntry( + iSignal.symbol, + iSignal.type // + ); + + // + // Update Signal Targets ... + UpdateSignalTargets(iSignal); + + // + // Handle Volume Management ... + double iVolume = eaVolume.CalculateVolume(iSignal); + has = iVolume > X_MIN_VOLUME && + iVolume != iSignal.volume; + if (has) + { + iSignal.volume = iVolume; + } + + // + // Execute Signal ... + has = eaTradeManager.Execute( + iSignal, + iConditions // + ); + } + + // + // Cleanup Resources ... + + // + iSignal.Clean(); + iConditions.Clean(); + } +} + +// \ No newline at end of file diff --git a/XCATBEA/Classes/xcatbea.signaller.class.mq5 b/XCATBEA/Classes/xcatbea.signaller.class.mq5 index 0d8cc528..623d6a8f 100644 --- a/XCATBEA/Classes/xcatbea.signaller.class.mq5 +++ b/XCATBEA/Classes/xcatbea.signaller.class.mq5 @@ -373,7 +373,7 @@ class XCXCATBEASignaller : XCBase // // Trigger Block Detection ... - result = DetectTriggerBlock1( + result = DetectTriggerBlock( helper, barAnalyser, mConditions.triggerBlock, diff --git a/XCATBEA/Classes/xcatbea.signaller.nontb.class.mq5 b/XCATBEA/Classes/xcatbea.signaller.nontb.class.mq5 new file mode 100644 index 00000000..d17cc9b0 --- /dev/null +++ b/XCATBEA/Classes/xcatbea.signaller.nontb.class.mq5 @@ -0,0 +1,854 @@ +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class +// ------------------------------------------------- +// Name: XCXCATBEASignaller ... +// Description: Class for XCATBEA Signaller ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm XCXCATBEASignaller Class" +#property strict + +// +// Imports ... +#include "../../Classes/x-saherelm.x-bar.analyser.class.mq5" +#include "../../Classes/x-saherelm.x-guard.class.mq5" +#include "../../Helpers/x-saherelm.x121.xcatb.helper.mq5" +#include "../Classes/xcatbea.x-poi.detector.class.mq5" +#include "../Classes/xcatbea.x-poi.drawer.class.mq5" +#include "../Libraries/xcatbea.lib.mq5" +#include "../Libraries/xcatbea.signaller.lib.mq5" +#include "../Libraries/xcatbea.x-poi.extensions.lib.mq5" + +// +// Definitions ... + +// +struct XCATBNonTBEASignallerInputs +{ + // + // Pros ... + string symbol; + string provider; + bool allowDraws; + bool allowGuards; + int riskToRewardRatio; + ENUM_TIMEFRAMES period; + double slATRMultiplier; + X121XCatbInputs catbInputs; + + // + // Constructor(s) ... + XCATBNonTBEASignallerInputs() + { + Clean(); + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + symbol = NULL; + period = NULL; + provider = NULL; + catbInputs.Clean(); + allowDraws = false; + allowGuards = false; + slATRMultiplier = 0; + riskToRewardRatio = 0; + + // + ZeroMemory(this); + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + IsValid(symbol) && + IsValid(period) && + IsValid(provider) && + catbInputs.IsValid() && + riskToRewardRatio > 0; + + // + return result; + } + + // +}; + +class XCXCATBNonTBEASignaller : XCBase +{ + // + // Public ... + public: + // + // Props ... + + // + bool allowDraws; // Allow Draws or not ... + bool allowGuards; // Allow Guards or not ... + int riskToRewardRatio; // Signals R2R ... + double slATRMultiplier; // SL ATR Multiplier ... + + // + XBarTracker barTraker; // Bar Tracker ... + XCX121XCatbHelper *helper; // XCATB Helper Class instance ... + XCBarAnalyser *barAnalyser; // Bar Analyser ... + XCXCATBEAPOIDrawer *drawer; // POI Drawer ... + XCXCATBEAPOIDetector *detector; // POI Detector ... + + // + XBoxZone unavailableZones[]; // Un Available Zones ... + + // + XCATBEAStrategyConditions mConditions; + XCATBEAStrategyConditions mConditionsCollection[]; + + // + // Constructor ... + XCXCATBNonTBEASignaller(XCATBNonTBEASignallerInputs &inputs) + { + Init(inputs); + } + + // + // Deconstructor ... + ~XCXCATBNonTBEASignaller() + { + DeInit(); + } + + // + // Properties ... + + // + string GetSymbol() + { + return symbol; + } + + // + string GetProvider() + { + return provider; + } + + // + ENUM_TIMEFRAMES GetPeriod() + { + return period; + } + + // + double GetR2R() + { + return riskToRewardRatio; + } + + // + // Tick Analyser ... + + /** + * Process Tick ... + */ + void ProcessTick( + XPosition &positions[], + XGuard &guards[], + XCATBEAStrategyConditions &conditions, + bool isActiveSession = true // + ) + { + // + Clean(guards); + conditions.Clean(); + + // + XOHCL bar; + int count = 0; + bool has = false; + int barIndex = 0; + + // + // Check Guards ... + has = DetectGuards( + guards, + positions, + barIndex // + ); + + // + // Check Triggered Conditions ... + has = HasChild(mConditionsCollection); + if (has) + { + // + int selectedIDX = -1; + count = ArraySize(mConditionsCollection); + for (int i = 0; i < count; i++) + { + // + // Select indexed Conditions ... + XCATBEAStrategyConditions iConditions = mConditionsCollection[i]; + + // + // Check Conditions Triggered ... + has = DetectSignalTrigger( + iConditions, + barIndex // + ); + if (has) + { + // + selectedIDX = i; + conditions = iConditions; + iConditions.Clean(); + + // + break; + } + + // + // When Setup Invalidated + // Signaller Clean Conditions ... + if (!has && + !iConditions.IsValid()) + { + // + selectedIDX = i; + break; + } + + // + // Cleanup Resources ... + iConditions.Clean(); + } + + // + // Check Can Trigger ... + has = IsValidIndex(selectedIDX) && + conditions.IsValid() && + conditions.IsSetuped() && + conditions.CanTrigger(); + if (has) + { + // + ArrayRemove( + mConditionsCollection, + selectedIDX, + 1 // + ); + } + else + { + // + // Check Selected Index for Invalid Conditions ... + if (IsValidIndex(selectedIDX)) + { + // + // Remove Invalidated Conditions ... + ArrayRemove( + mConditionsCollection, + selectedIDX, + 1 // + ); + } + + // + // Cleanup Resource ... + conditions.Clean(); + } + } + + // + // Check Bar Processing ... + if (!barTraker.CanProcessBar()) + { + return; + } + + // + // Initialize Bar ... + bar.Init( + symbol, + period, + barIndex // + ); + + // + // Detect POI(s) ... + detector.Detect(barIndex); + + // + // Validate POI(s) ... + detector.Validate( + unavailableZones, + barIndex // + ); + + // + // Draw POI(s) ... + if (allowDraws) + { + drawer.Draw(bar.time); + } + + // + // Here we Check Active Session ... + // and Prevent Moving forward if there is not + // Session actives ... + // for improvement Calculation Speeds ... + if (isActiveSession) + { + // + // Check Signal Setups ... + has = DetectSignalSetup(barIndex); + if (has) + { + // + barTraker.Waits(); + + // + AddConditionsIfNotExists(); + + // + mConditions.Clean(); + } + } + + // + // Cleanup Resources ... + bar.Clean(); + } + + // + // Signalling Tools ... + + /** + * Detect Setup Conditions based on Signalling ... + * + * @param maxAllowedSLDistanceInPoint: int, Max Allowed SL Distance in Points (if Bigger thn Zero Provided) ... + * + * @return ( bool ) + */ + bool DetectSignalSetup(int barIndex = 0) + { + // + bool result = false; + + // + // Normalize Args ... + barIndex = NormalizeInt(barIndex, 0); + + // + // Update All Required Buffers ... + helper.Update(barIndex); + + // + // Trigger Block Detection ... + // result = DetectTriggerBlock( + // helper, + // barAnalyser, + // mConditions.triggerBlock, + // mConditions.conditions, + // validations, + // filters, + // barIndex, + // 10 // Loopback ... + // ); + if (result) + { + // + // Prepare Condition ... + + // // + // // Prepare Signal ... + // mConditions.dir = + // mConditions + // .triggerBlock + // .GetDirection(); + // mConditions.symbol = symbol; + // mConditions.period = period; + // mConditions.provider = provider; + // mConditions.reward = riskToRewardRatio; + // mConditions.time = mConditions.conditions.bars[0].time; + // mConditions.setupTime = mConditions.conditions.bars[0].time; + + // // + // // Prepare Target ... + // double targets[]; + // for (int i = 1; i <= riskToRewardRatio; i++) + // { + // // + // Add( + // (double)i, + // targets // + // ); + // } + + // // + // // Calculate SL Additions ... + // double iATR = 0; + // if (barIndex > 0 && + // barIndex < ArraySize(helper.atrBuffer)) + // { + // iATR = helper.atrBuffer[barIndex]; + // } + // double slAdditional = slATRMultiplier * iATR; + + // // + // // Preparing Signal ... + // result = ToSignal( + // mConditions.triggerBlock.trigger, + // mConditions.triggerBlock.signal, + // targets, + // slAdditional // + // ); + // if (result) + // { + // // + // mConditions.triggerBlock.signal.provider = provider; + // mConditions.sl = mConditions.triggerBlock.signal.sl; + // mConditions.tp = mConditions.triggerBlock.signal.tp; + // mConditions.pivot = mConditions.triggerBlock.signal.sl; + // mConditions.entry = mConditions.triggerBlock.signal.entry; + // mConditions.point = mConditions.triggerBlock.signal.entry; + // mConditions.type = ToPositionType(mConditions.triggerBlock.signal.type); + + // // + // // Draw Trigger Block ... + // if (allowDraws) + // { + // // + // DrawTriggerBlock( + // mConditions.triggerBlock, + // drawer.drawer, + // mObjects, + // NULL, // To ... + // false // Draw Signal ... + // ); + // } + // } + } + + // + result = mConditions.IsValid() && + mConditions.IsSetuped(); + + // + // Cleanup Resource ... + + // + return result; + } + + /** + * Detect Trigger Conditions for Specified Signal ... + * + * @param conditions: XCATBEAStrategyConditions instance Reference, Specified Signal Conditions ... + * @param maxAllowedSetupAge: specified Setup Age for Expiration (if bigger than Zero) ... + * + * @return ( bool ) + */ + bool DetectSignalTrigger( + XCATBEAStrategyConditions &conditions, + int barIndex = 0 // + ) + { + // + bool result = false; + + // + // Normalize Args ... + barIndex = NormalizeInt(barIndex, 0); + + // + // Validate Setup ... + result = conditions.IsSetuped(); + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(conditions.dir); + bool isBearish = IsBearish(conditions.dir); + + // + // Validate Direction of Setuped Conditions ... + result = + result && + (isBullish || + isBearish); + + // + // Do Triggering Senario based on Trigger Block ... + if (result && + conditions.triggerBlock.IsValid()) + { + // + // Checking Score ... + double bullishScore = 0; + double bearishScore = 0; + conditions + .conditions + .GenerateScore( + bullishScore, + bearishScore // + ); + bool isScorePassed = + isBullish + ? bullishScore > bearishScore + : bearishScore > bullishScore; + + // + // Complete Conditions Here ... + if (isScorePassed) + { + conditions.triggerTime = TimeCurrent(); + } + } + + // + // Do Other Validation Senarios ... + + // + result = conditions.IsValid() && + conditions.IsSetuped() && + conditions.CanTrigger(); + + // + // Check Setup Age or Setup Validations here ... + if (!result) + { + } + + // + // Cleanup Resources ... + + // + return result; + } + + /** + * Detect Guards bsed on Signalling Class ... + * + * @param guards: XCAEAGuard instance Collection, Holds Provided Guards ... + * @param positions: XPosition instance Collection, Provides Signalling Based Positions for Apply Guards on them ... + * @param provider: X121SMCStrategySignalProviderData instance Reference, Specified Data for Cycles ... + * + * @return ( bool ) + */ + bool DetectGuards( + XGuard &guards[], + const XPosition &positions[], + int barIndex = 0 // + ) + { + // + bool result = false; + + // + // Normalize Args ... + Clean(guards); + barIndex = NormalizeInt(barIndex, 0); + + // + result = allowGuards && + HasChild(positions); + if (!result) + { + return result; + } + + // + // TODO: Implement this ... + + // + result = HasChild(guards); + + // + // Cleanup Resources ... + + // + if (!result) + { + Clean(guards); + } + + // + return result; + } + + // + // Protected ... + protected: + // + + /** + * Initialize ... + */ + void Init(XCATBNonTBEASignallerInputs &inputs) + { + // + bool has = inputs.IsValid(); + if (!has) + { + return; + } + + // + symbol = inputs.symbol; + period = inputs.period; + provider = inputs.provider; + allowDraws = inputs.allowDraws; + allowGuards = inputs.allowGuards; + slATRMultiplier = inputs.slATRMultiplier; + riskToRewardRatio = inputs.riskToRewardRatio; + + // + mObjects = new CArrayObj(); + + // + // Initialize Bar Tracker ... + has = barTraker.Init( + symbol, + period // + ); + if (!has) + { + return; + } + + // + // Initialize Bar Analyser ... + barAnalyser = new XCBarAnalyser(); + + // + // initialize Helper ... + helper = new XCX121XCatbHelper(); + has = helper.Init( + symbol, + period, + inputs.catbInputs // + ); + if (!has) + { + return; + } + + // + mConditions.Clean(); + Clean(mConditionsCollection); + + // + InitPOI(); + } + + /** + * DeInitialize ... + */ + void DeInit() + { + // + mObjects.Clear(); + delete mObjects; + ZeroMemory(mObjects); + + // + drawer.Clear(); + delete drawer; + ZeroMemory(drawer); + + // + detector.CleanPivots(); + delete detector; + ZeroMemory(detector); + + // + delete helper; + ZeroMemory(helper); + + // + delete barAnalyser; + ZeroMemory(barAnalyser); + + // + barTraker.Clean(); + } + + /** + * Add Conditions to Conditions Collection if not Exists ... + * + * @param maxAllowed: int, Specified Max Allowed Holding Conditions ... + * + * @return ( int ) + */ + int AddConditionsIfNotExists( + int maxAllowed = 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; + CArrayObj *mObjects; + 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 ... + detector.detectPeakPivots = true; + detector.detectValePivots = true; + } + + // + // Initialize POI Drawer ... + has = detector != NULL; + if (has) + { + // + drawer = new XCXCATBEAPOIDrawer(detector); + + // + // Configure ... + drawer.drawPeakPivots = true; + drawer.drawValePivots = true; + + // + XCATBPivotStyle iStyle; + + // + // Styling Peak Pivot ... + iStyle.width = 1; + iStyle.clr = clrMagenta; + iStyle.style = STYLE_SOLID; + + // + drawer.peakPivotStyle = iStyle; + + // + // Styling Vale Pivot ... + iStyle.width = 1; + iStyle.clr = clrAqua; + iStyle.style = STYLE_SOLID; + + // + drawer.valePivotStyle = iStyle; + + // + // Cleanup Resources ... + + // + iStyle.Clean(); + } + } + + // +}; \ 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 b9aac72f..150164d9 100644 --- a/XCATBEA/Classes/xcatbea.x-poi.detector.class.mq5 +++ b/XCATBEA/Classes/xcatbea.x-poi.detector.class.mq5 @@ -524,6 +524,134 @@ class XCXCATBEAPOIDetector : public XCBase int barIndex = 0 // ) { + // + barIndex = NormalizeInt(barIndex, 0); + int loopback = pivotDetectionLoopbac; + loopback = NormalizeInt(loopback, 50); + + // + int idx = -1; + int count = 0; + bool has = false; + + // + int zIDX = 0; + int cIDX = zIDX + 1; + int pIDX = cIDX + 1; + int p2IDX = pIDX + 1; + int p3IDX = p2IDX + 1; + + // + newPeakPivotDetected = false; + newValePivotDetected = false; + + // + int index = barIndex; + int start = index; + int end = index + loopback; + while (start < end) + { + // + // Retrieve Conditions ... + X121XCatbConditions conditions; + has = helper.GetConditions( + conditions, + start, + 10 // + ); + if (!has) + { + conditions.Clean(); + continue; + } + + // + // Retrieve Bars ... + XOHCL zBar; + XOHCL cBar; + XOHCL pBar; + XOHCL p2Bar; + has = zBar.Init( + conditions.symbol, + conditions.period, + start // + ); + has = + has && + zBar.GetPreviousBar(cBar); + has = + has && + cBar.GetPreviousBar(pBar); + has = + has && + pBar.GetPreviousBar(p2Bar); + if (!has) + { + // + zBar.Clean(); + cBar.Clean(); + pBar.Clean(); + p2Bar.Clean(); + conditions.Clean(); + + // + continue; + } + + // + // Checking Pivots ... + + // + // PV ... + + // + // PEAK ... + if (detectPeakPivots) + { + // + newPeakPivotDetected = DetectPeakAndValePivot( + barIndex, + X_DIRECTION_BEARISH, + zBar, + cBar, + pBar, + p2Bar, + conditions // + ); + } + + // + // VALE ... + if (detectValePivots) + { + // + newValePivotDetected = DetectPeakAndValePivot( + barIndex, + X_DIRECTION_BULLISH, + zBar, + cBar, + pBar, + p2Bar, + conditions // + ); + } + + // + // Others ... + + // + start++; + + // + zBar.Clean(); + cBar.Clean(); + pBar.Clean(); + p2Bar.Clean(); + conditions.Clean(); + } + + // + SortPivots(); } // @@ -532,6 +660,18 @@ class XCXCATBEAPOIDetector : public XCBase int barIndex = 0 // ) { + // + // Implement Validation Senarios ... + + // + // PV ... + ValidatePeakValePivots( + unavailables, + barIndex // + ); + + // + SortPivots(); } // @@ -583,7 +723,7 @@ class XCXCATBEAPOIDetector : public XCBase XOHCL &cBar, XOHCL &pBar, XOHCL &p2Bar, - XCX121XCatbHelper &conditions // + X121XCatbConditions &conditions // ) { // diff --git a/XCATBEA/Libraries/xcatbea.lib.mq5 b/XCATBEA/Libraries/xcatbea.lib.mq5 index 9df09be2..0d65d111 100644 --- a/XCATBEA/Libraries/xcatbea.lib.mq5 +++ b/XCATBEA/Libraries/xcatbea.lib.mq5 @@ -317,7 +317,7 @@ struct XTriggerBlockFilters * * @return ( bool ) */ -bool DetectTriggerBlock1( +bool DetectTriggerBlock( XCX121XCatbHelper *helper, XCBarAnalyser *barAnalyser, XTriggerBlock &triggerBlock, diff --git a/XCATBEA/Libraries/xcatbea.signaller.lib.mq5 b/XCATBEA/Libraries/xcatbea.signaller.lib.mq5 index d9b9f7aa..431d3c90 100644 --- a/XCATBEA/Libraries/xcatbea.signaller.lib.mq5 +++ b/XCATBEA/Libraries/xcatbea.signaller.lib.mq5 @@ -274,3 +274,13 @@ struct XCATBEAStrategyConditions // }; + +// +bool DetectSignalZone() +{ + // + bool result = false; + + // + return result; +} \ No newline at end of file