/////////////////////////////////////////////////////// // // SaherElm IT Center MQL5 Expert Advisor // ------------------------------------------------- // Name: XBaseEA // Description: Base Expert Advisor V2 ... // // 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 "2.00" #property icon "../Images/SaherElm_Logo_Color.ico" #property description "SaherElm Base Expert Advisor" #property strict // #region Imports ... #include "../Classes/x-saherelm.base.class.mq5" #include "../Classes/x-saherelm.session-detector.class.mq5" #include "../Classes/x-saherelm.x-alert.class.mq5" #include "../Classes/x-saherelm.x-chart.helper.class.mq5" #include "../Classes/x-saherelm.x-guard.class.mq5" #include "../Classes/x-saherelm.x-restrictions.class.mq5" #include "../Classes/x-saherelm.x-target.class.mq5" #include "../Classes/x-saherelm.x-trade-manager.class.mq5" #include "../Classes/x-saherelm.x-trade.class.mq5" #include "../Classes/x-saherelm.x-volume.class.mq5" // #endregion // #region Inputs ... input group "Common"; input long eaMagicNumber = 1694056; // Magic Number input int eaSlippage = 10; // Slippgae input string eaLogSuffix = ""; // Log Suffix // // Management ... input group "Management"; 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 double eaMaxAllowedDrawdownFactor = 0.3; // Max Allowed DrawDown for Trade // // Volume ... input group "Volume"; input ENUM_X_VOLUME_SELECT_TYPE eaVolumeSelect = X_VOLUME_CONSTANT; // 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 = 1; // Constant Percent of Balance Per Trade input double eaConstantBalance = 1000.0; // Constant Balance for Calculations // // Alert ... input group "Alert"; input bool eaEnableAlerts = true; // Enable Alerts input bool eaSaveAlerts = true; // Save 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 // // Reports ... 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 = true; // Save Trades input bool eaSaveSignals = true; // Save Signals input bool eaSaveWins = true; // Save Winning Conditions input bool eaSaveLosts = true; // Save Lost Conditions input bool eaSaveRestrictions = true; // Save Restriction Reports // #endregion // #region Configurable Documents ... bool eaEnableAnalysis = true; // Most Important Flag for Enable Analysis in EA ... bool processTicksOnlyOnNewBars = false; // Processing Ticks only on new Bars ... ENUM_X_SESSION_TYPE eaAllowedSessions[]; // Allowed Sessions for Analysis ... ENUM_X_SESSION_OVERLAP_TYPE eaAllowedOverlaps[]; // Allowed Overlaps for Analysis ... // #endregion // #region Global Variables ... #define ShortName "XSessionDetectorTestEA" // string eaTag; // EA Scoped Tag ... bool isEaInNewBar = false; // EA Is New Bar ... // XCAlert *eaAlert; // EA Scope Alert Handler ... XCGuard *eaGuard; // EA Scope Guard Handler ... XCTrade *eaTrader; // EA Scope Trade Handler ... XCVolume *eaVolume; // EA Scope Voluem Handler ... XCTarget *eaTarget; // EA Scope Target Handler ... XBarTracker eaBarTracker; // EA Scope Bar Tracker ... XTimeTracker eaTimeTracker; // EA Scope Time Tracker ... XCRestrictions *eaRestrictions; // EA Scope Restrictions Handler ... XCTradeManager *eaTradeManager; // EA Scope Trade Manager Handler ... XCSessionDetector *eaSessionDetector; // EA Scope Session Detector ... // #endregion // #region Global Event Handlers ... /** * Initialize EA Process ... * * @return ( int ) */ int OnInit() { // bool result = true; // if (!ValidateInputs()) { return INIT_PARAMETERS_INCORRECT; } // // Initialize Timer ... if (!InitTimer()) { return INIT_FAILED; } // // Configure Dynamic Variables ... ConfigureEA(); // result = InitializeRequirements(); if (!result) { return INIT_FAILED; } // return INIT_SUCCEEDED; } /** * Handle Tick for Processing ... */ void OnTick() { // // Perform Session Detector Process ... eaSessionDetector.Process(); // // Perform Restrictions Process ... eaRestrictions.Process(); // // Check if Is New Bar ... isEaInNewBar = eaBarTracker.IsNewBar(); // // Check Analysis Enabled ... if (eaEnableAnalysis) { // // Check Bar Tracker ... if (processTicksOnlyOnNewBars) { // // Check New Bar or not ... if (!isEaInNewBar) { return; } } // // Do Analysis ... // TODO: Implement this ... } } /** * Handle On Trade Processing ... */ void OnTrade() { // // Calling Event Handler ... eaTrader.HandleOnTrade(); } /** * Handle On Timer Processing ... */ void OnTimer() { } /** * De Initialize Expert ... * * @param reason: int, DeInitialization 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 * */ void OnDeinit(const int reason) { // // Destroy Timer ... // If Initialized ... DestroyTimer(); // // Cleaning Time Tracker ... eaTimeTracker.Clean(); // // Cleanup Resources ... ZeroMemory(eaAlert); ZeroMemory(eaGuard); ZeroMemory(eaTrader); ZeroMemory(eaVolume); ZeroMemory(eaTarget); ZeroMemory(eaTradeManager); ZeroMemory(eaRestrictions); ZeroMemory(eaSessionDetector); } /** * Handle On Chart Event Processing ... * @param id: int, Specified Event ID ... * @param lparam: long, type event parameter * @param dparam: double, type event parameter * @param sparam: string, type event parameter */ void OnChartEvent( const int id, const long &lparam, const double &dparam, const string &sparam // ) { } // #endregion // #region Custom Actions ... /** * 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; } /** * Configure EA Commons ... */ void ConfigureEA() { // // Configure Sessions ... // // Configure Overlaps ... Add( X_OVERLAP_LONDON_NEWYORK, eaAllowedOverlaps // ); // // Startup eaAnalysis State ... int sessionsCount = ArraySize(eaAllowedSessions); int overlapsCount = ArraySize(eaAllowedOverlaps); // eaEnableAnalysis = !IsValidSize(sessionsCount) && !IsValidSize(overlapsCount); } /** * Initial Requirements of EA ... * * @return ( bool ) */ bool InitializeRequirements() { // bool result = false; // // Preparing Tags ... eaTag = (IsXValid(eaLogSuffix) ? eaLogSuffix + "_" : "") + ShortName; // #region Initializing Bar Tracker ... result = eaBarTracker.Init( _Symbol, _Period // ); if (!result) { return result; } // #endregion // #region Alert ... eaAlert = new XCAlert(); eaAlert.SetPrefix(eaLogSuffix); eaAlert.SetLogAlerts(eaLogAlerts); eaAlert.SetMailAlerts(eaMailAlerts); eaAlert.SetPushAlerts(eaPushAlerts); eaAlert.SetSaveAlerts(eaSaveAlerts); eaAlert.SetEnableAlerts(eaEnableAlerts); eaAlert.SetTerminalAlerts(eaTerminalAlerts); result = eaAlert != NULL; if (!result) { return result; } // #endregion // #region Session Detector ... eaSessionDetector = new XCSessionDetector( eaAlert, // Alert ... true, // Use Server Time ... 0 // Timezone Offset ... ); // // Register Event Handlers ... eaSessionDetector.AddOnSessionStartHandler(OnSessionStartHandler); eaSessionDetector.AddOnOverlapStartHandler(OnOverlapStartHandler); eaSessionDetector.AddOnSessionStateChangeHandler(OnSessionStateChangeHandler); // #endregion // #region Volume Provider ... eaVolume = new XCVolume(); result = eaVolume.Init( eaVolumeSelect, eaStaticVoluem, eaDynamicVolumeStepBalance, eaDynamicVolumeStepVolume, eaConstantRiskBalance, eaConstantPercent, eaConstantBalance // ); if (!result) { return result; } // #endregion // #region Trader ... eaTrader = new XCTrade( eaSlippage, eaMagicNumber, 0, 0, eaMaxAllowedDrawdownFactor // ); // eaTrader.AddOnDealsChangedEventHandler(OnDealsChanged); eaTrader.AddOnStopLossEventHandler(OnStopLossTriggered); eaTrader.AddOnOrdersChangedEventHandler(OnOrdersChanged); eaTrader.AddOnTakeProfitEventHandler(OnTakeProfitTriggered); eaTrader.AddOnModifyPositionEventHandler(OnPositionModified); eaTrader.AddOnPositionsChangedEventHandler(OnPositionsChanged); eaTrader.AddOnTradeStateChangedEventHandler(OnTradeStateChanged); eaTrader.AddOnForceClosePositionEventHandler(OnPositionForceClosed); eaTrader.AddOnPartialClosePositionEventHandler(OnPositionPartialClosed); // #endregion // #region Guard ... eaGuard = new XCGuard( eaAlert, eaTrader // ); // eaGuard.onGuardEventListener = OnGuardedTriggered; // #endregion // #region Target ... eaTarget = new XCTarget( eaTrader, eaAlert); // #endregion // #region Trae Manager ... eaTradeManager = new XCTradeManager( eaAlert, eaTrader, eaVolume, eaGuard, eaTarget // ); // eaTradeManager.checkForGuardEventListener = CheckForGuardTriggered; // 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 // ); // #endregion // #region Restrictions Handler ... eaRestrictions = new XCRestrictions(); // // Configure Restrictions ... // TODO: Refactor Restrictions Configurations as Input ... eaRestrictions.SetAllowedLosesInRestrictions(2); eaRestrictions.SetAllowedTradesInRestrictions(2); eaRestrictions.SetRestrictionsPeriodMultiplier(2); eaRestrictions.SetRestrictionsPeriod(X_TRADE_RESTRICATION_DAILY); // // Register Event Handlers ... eaRestrictions.AddRestrictionsEndEventHandler(OnRestrictionsEnd); eaRestrictions.AddRestrictionsStartEventHandler(OnRestrictionsStart); // #endregion // result = eaSessionDetector != NULL; if (!result) { return result; } // 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(); } // #endregion // #region Custom Event Handlers ... /** * Check For Guard ... * XCHuard * * @param guards: XGuard, reference Collection to holds result ... * @param positions: XPosition, refrence collection to Provides Positions ... * @param barIndex: int, Specified Bar index ... * * @return ( int ) */ int CheckForGuardTriggered( XGuard &guards[], XPosition &positions[], int barIndex = 0 // ) { return 0; } /** * Handle Guard Events ... * XCHuard * * @param action: ENUM_X_GUARD_ACTIONS * @param positions: XPosition[] */ void OnGuardedTriggered( ENUM_X_GUARD_ACTIONS action, XPosition &positions[] // ) { } /** * Handle Session Start Event ... * XCSessionDetector * * @param session: ENUM_X_SESSION_TYPE * @param startTime: datetime */ void OnSessionStartHandler( ENUM_X_SESSION_TYPE session, datetime startTime // ) { Print("Session Started: ", EnumToString(session), " at ", TimeToString(startTime)); } /** * Handle Overlap Start Event ... * XCSessionDetector * * @param session: ENUM_X_SESSION_OVERLAP_TYPE * @param startTime: datetime */ void OnOverlapStartHandler( ENUM_X_SESSION_OVERLAP_TYPE overlap, datetime startTime // ) { // Print("Overlap Started: ", EnumToString(overlap), " at ", TimeToString(startTime)); // // Check Over lap Exists in eaSession Everlaps ... } /** * Handle Session State Change Event ... * XCSessionDetector * * @param session: ENUM_X_SESSION_TYPE * @param state: ENUM_X_SESSION_STATE */ void OnSessionStateChangeHandler( ENUM_X_SESSION_TYPE session, ENUM_X_SESSION_STATE state // ) { Print("Session State Changed: ", EnumToString(session), " State: ", EnumToString(state)); } /** * Handle StopLoss Triggered Positions ... * XCTrade * * @param deal: XDeal instance ... */ void OnStopLossTriggered(const XDeal &deal) { } /** * Handle Take Profit Triggered Positions ... * XCTrade * * @param deal: XDeal instance ... */ void OnTakeProfitTriggered(const XDeal &deal) { } /** * Handle Force Close a Position ... * XCTrade * * @param ticket: ULONG ... * @param position: XPosition instance ... * @param comment: String ... */ void OnPositionForceClosed( const ulong ticket, const XPosition &position, const string comment // ) { } /** * Handle Deals Changes ... * XCTrade * * @param count: Integer, Number of Changes ... */ void OnDealsChanged(int count) { } /** * Handle Orders Changes ... * XCTrade * * @param count: Integer, Number of Changes ... */ void OnOrdersChanged(int count) { } /** * Handle Positions Changes ... * XCTrade * * @param count: Integer, Number of Changes ... */ void OnPositionsChanged(int count) { } /** * Handle Position Modified ... * XCTrade * * @param ticket: ulong, Position Ticket ... * @param profit: double, Position Profit ... * @param comment: string, Comment ... */ void OnPositionModified( const ulong ticket, const double profit, const string comment // ) { } /** * Handle Position Partial Closed ... * XCTrade * * @param ticket: ulong, Position Ticket ... * @param profit: double, Position Profit ... * @param comment: string, Comment ... */ void OnPositionPartialClosed( const ulong ticket, const double profit, const string comment // ) { } /** * Handle Trade State Changed ... * XCTrade * * @param state: XOnTradeHandlerState instance ... */ void OnTradeStateChanged(const XOnTradeHandlerState &state) { } /** * Handle Restrictions Start Event ... * XCRestrictions ... */ void OnRestrictionsStart() { Print("Restrictions Start ..."); } /** * Handle Restrictions End Event ... * XCRestrictions ... */ void OnRestrictionsEnd() { Print("Restrictions End ..."); } // #endregion //