/////////////////////////////////////////////////////// // // SaherElm IT Center XCAEA MQL5 Expert Advisor // ------------------------------------------------- // Name: XCAEA // Description: an Exper Advisor which used Panels // // 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 "SaherElm XCAEA EA" #property strict // // Imports ... #include "../Classes/x-saherelm.x-alert.class.mq5" #include "../Classes/x-saherelm.x-trade.class.mq5" #include "../Classes/x-saherelm.x-volume.class.mq5" #include "../XCAEA/Classes/xcaea.x-trade.manager.class.mq5" #include "../XCAEA/Signals/xcaea.signaller.class.mq5" // #define ShortName "XCAEAEA" // // Inputs ... // // Common ... input group "Common"; input long eaMagicNumber = 78692110; // Magic Number input int eaSlippage = 10; // Slippgae input string eaLogSuffix = ""; // Log Suffix input ENUM_TIMEFRAMES eaAnalysisPeriod = PERIOD_H1; // Analysis Period // // Symbols ... // // ------------------------------------------------------- // ---------- // eaSymbols: // ---------- // - if EMPTY use Current Symbol; // - for Multi Symbol use Comma Separated Symbols: // EURUSDb,XAUUSDb // // ------------------ // eaSymbolSessions: // ------------------ // - if EMPTY use WHOLE Times; // - for each Symbol use Comma Separated: // (XEURS1_02:00_14:00),(XEURS2_19:00_23:00)| // ------------------------------------------------------- input group "Symbols"; input string eaSymbols = ""; // Symbols Description input string eaSymbolSessions = ""; // Symbols Sessions // // 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 ... 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 ENUM_XCAEA_TRADE_RESTRICTION_PERIOD eaRestrictionsPeriod = XCAEA_TRADE_RESTRICATION_DAILY; // Trade Restrictions Period input int eaMaxAllowedTPs = 2; // Max Allowed TP(s) per Day input int eaMaxAllowedSLs = 2; // Max Allowed SL(s) per Day input int eaMaxAllowedTrades = 3; // Max Allowed Trades per Day 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 = false; // 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 // // Variables, Instances ... XCAlert *eaAlert; XCTrade *eaTrade; XSignal eaSignal; XCVolume *eaVolume; XTimeTracker eaTimeTracker; XCXCAEASignaller *eaSignallers[]; XCXCAEATradeManager *eaTradeManager; XCAEAStrategyConditions eaConditions; // string eaTag = ""; // // Event Handlers ... // // Initialization ... int OnInit() { // // Validate Inputs and Required Parameters // for EA to Works fine ... if (!ValidateInputs()) { return INIT_PARAMETERS_INCORRECT; } // // Initialize Timer ... if (!InitTimer()) { return INIT_FAILED; } // // Initial Requirements ... InitRequirements(); // // Initialize Volume Manger ... if (!InitVolume()) { return INIT_FAILED; } // // Init Succeed ... 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 // // ZeroMemory(eaAlert); ZeroMemory(eaTrade); ZeroMemory(eaVolume); // eaSignal.Clean(); eaConditions.Clean(); eaTimeTracker.Clean(); // int count = ArraySize(eaSignallers); for (int i = 0; i < count; i++) { // eaSignallers[i].DeInit(); ZeroMemory(eaSignallers[i]); } Clean(eaSignallers); // DestroyTimer(); } // // On Tick Handler ... void OnTick() { // int idx = -1; int count = 0; bool has = false; // HandleTimeReport(); // // Handle Position Management / Protections ... eaTradeManager.Manage(); // eaSignal.Clean(); eaConditions.Clean(); // double r2r = 4; string provider = "XCAEA"; datetime cTime = TimeCurrent(); ENUM_POSITION_TYPE type = POSITION_TYPE_BUY; ENUM_X_ORDER_MODES mode = X_ORDER_MODE_MARKET; // bool hasLong = false; bool hasShort = false; // // Checking Signallers ... has = HasChild(eaSignallers); if (!has) { return; } // int signallersCount = ArraySize(eaSignallers); for (int is = 0; is < signallersCount; is++) { // // Start Calculations ... // // Retrieve Common Data ... string symbol = eaSignallers[is].GetSymbol(); ENUM_TIMEFRAMES period = eaSignallers[is].GetPeriod(); // // Required Value For SL/TP Calculations ... double points = GetPoints(symbol); double pip = GetPipPrice(symbol); double pip2 = 2 * pip; // // Detect Signal Setups ... has = eaSignallers[is].DetectSignalSetup( r2r, 300 // Max Allowed SL Distance ... ); if (has) { // count = eaSignallers[is] .AddConditionsIfNotExists(); // eaSignallers[is].mConditions.Clean(); } // // Check Setuped Conditions Exists ... count = ArraySize(eaSignallers[is].mConditionsCollection); has = IsValidSize(count); if (!has) { continue; } // // Loop through Setuped Conditions for // Validating or Looking up Triggers ... for (int i = 0; i < count; i++) { // // Check Signal Triggered or not ... has = eaSignallers[is] .DetectSignalTrigger(eaSignallers[is] .mConditionsCollection[i]); // // If Triggered ... if (has) { // idx = i; eaConditions = eaSignallers[is].mConditionsCollection[i]; break; } // // Check Condition Validation ... has = eaSignallers[is].mConditionsCollection[i].IsValid() && eaSignallers[is].mConditionsCollection[i].IsSetuped(); if (!has) { idx = i; break; } } // // Remove Setuped Condition if provided IDX ... has = IsValidIndex(idx); if (has) { // ArrayRemove( eaSignallers[is].mConditionsCollection, idx, 1 // ); } // // Check EA Conditions is Valid or not ... has = eaConditions.IsSetuped() && eaConditions.CanTrigger(); if (!has) { // eaSignal.Clean(); eaConditions.Clean(); // continue; } // // Setting Time to Conditions ... eaConditions.time = cTime; has = ToPositionType( type, eaConditions.type // ); if (!has) { // eaSignal.Clean(); eaConditions.Clean(); // continue; } // // Checking Trigger Direction ... hasLong = eaConditions.HasBullishSignal(); hasShort = eaConditions.HasBearishSignal(); has = hasLong || hasShort; if (!has) { // eaSignal.Clean(); eaConditions.Clean(); // continue; } // // Preparing Signal ... eaSignal.mode = mode; eaSignal.type = type; eaSignal.entry = GetEntry( eaConditions.symbol, eaConditions.dir // ); eaSignal.provider = provider; eaSignal.sl = eaConditions.sl; eaSignal.tp = eaConditions.tp; eaSignal.volume = X_MIN_VOLUME; eaSignal.time = eaConditions.time; eaSignal.symbol = eaConditions.symbol; eaSignal.period = eaConditions.period; // // Handling Targets ... ApplyTargetsOnSignal( eaConditions.dir, eaConditions.targets, eaSignal // ); // // Validate Signal ... has = eaSignal.IsValid(); if (!has) { // eaSignal.Clean(); eaConditions.Clean(); // continue; } // // Handle Volume Management ... double iVolume = eaVolume.CalculateVolume(eaSignal); if (iVolume > X_MIN_VOLUME && iVolume != eaSignal.volume) { eaSignal.volume = iVolume; } // // Execute Signal ... has = eaTradeManager.Execute( eaSignal, eaConditions // ); // eaSignal.Clean(); eaConditions.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() { // // Preparing Tags ... eaTag = (IsValid(eaLogSuffix) ? eaLogSuffix + "_" : "") + ShortName; // // EA Alert ... eaAlert = new XCAlert( eaTag, eaEnableAlerts, eaLogAlerts, eaTerminalAlerts, eaMailAlerts, eaPushAlerts // ); // // 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 XCXCAEATradeManager( eaTrade // ); eaTradeManager.SaveTrades(true); eaTradeManager.SetAlertEnableAlerts(eaEnableAlerts); eaTradeManager.SetAlertPrefix(eaTag); eaTradeManager.SetAlertLogAlerts(eaLogAlerts); eaTradeManager.SetAlertMailAlerts(eaMailAlerts); eaTradeManager.SetAlertPushAlerts(eaPushAlerts); eaTradeManager.SetAlertTerminalAlerts(eaTerminalAlerts); // // 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 // ); // InitSymbolSessions(); // } /** * Initial Symbols and Active Sessions of EA ... */ void InitSymbolSessions() { // string symbols[]; string sessions[]; string iSymbol = NULL; XCXCAEASignaller *iSignaller; // // Parse Symbols ... int symbolsCount = 0; bool isMultiSymbol = IsValid(eaSymbols); if (isMultiSymbol) { // symbolsCount = SplitContent( symbols, eaSymbols // ); isMultiSymbol = IsValidSize(symbolsCount); } if (!isMultiSymbol) { // Add( _Symbol, symbols // ); // symbolsCount = 1; } // // Parse Sessions ... int sessionsCount = 0; bool hasSession = IsValid(eaSymbolSessions); if (hasSession) { // // Extract Per Symbol Sessions ... sessionsCount = SplitContent( sessions, eaSymbolSessions, "|" // ); } // // Setting Up Symbols ... bool has = false; // for (int i = 0; i < symbolsCount; i++) { // iSymbol = symbols[i]; // // EA Signaller ... iSignaller = new XCXCAEASignaller( iSymbol, _Period, eaAnalysisPeriod // Analysing Period ... ); // Add( iSignaller, eaSignallers // ); // ZeroMemory(iSignaller); } // // Setting Up Sessions ... if (hasSession) { // for (int i = 0; i < symbolsCount; i++) { // iSymbol = symbols[i]; // if (i < sessionsCount) { // // Extract Per Symbol Sessions ... string iSymbolSessionsStr[]; int iSymbolSessionsCount = SplitContent( iSymbolSessionsStr, sessions[i], "," // ); // has = IsValidSize(iSymbolSessionsCount); if (has) { // // Loop through Symbols Sessions ... for (int j = 0; j < iSymbolSessionsCount; j++) { // string iSessionDescriptorStr = ExtractString(iSymbolSessionsStr[j]); has = IsValid(iSessionDescriptorStr); if (has) { // // Extract Session Descriptor Data ... string parts[]; int partsCount = SplitContent( parts, iSessionDescriptorStr, "_" // ); has = IsValidSize(partsCount) && partsCount == 3; if (has) { // string iName = parts[0]; string iStart = parts[1]; string iEnd = parts[2]; has = IsValid(iName) && IsValid(iStart) && IsValid(iEnd); if (has) { // eaTradeManager .SetTradeSession( iSymbol, iStart, iEnd, iName // ); } } // Clean(parts); } } } // Clean(iSymbolSessionsStr); } } } // Clean(symbols); Clean(sessions); ZeroMemory(iSignaller); } /** * Handling Time Reporting ... */ void HandleTimeReport() { // // Monthly Report .... if (eaReportNewMonths && eaTimeTracker.IsNewMonth()) { // string msg = "New Month ..."; // eaAlert.Alert(msg); } // // Weekly Report .... if (eaReportNewWeeks && eaTimeTracker.IsNewWeek()) { // string msg = "New Week ..."; // eaAlert.Alert(msg); } // // Daily Report .... if (eaReportNewDays && eaTimeTracker.IsNewDay()) { // string msg = "New Day ..."; // eaAlert.Alert(msg); } // // Hourly Report .... if (eaReportNewHours && eaTimeTracker.IsNewHour()) { // string msg = "New Hour ..."; // eaAlert.Alert(msg); } } //