/////////////////////////////////////////////////////// // // SaherElm IT Center XTest MQL5 Expert Advisor // ------------------------------------------------- // Name: XBackTester // Description: a Backtest Tools Strategy Tester // // Maintainer: // ------------ // Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) // //////////////////////////////////////////////////////x // // Global Properties ... #property copyright "Copyright 2023, SaherElm IT Center" #property link "https://saherelm.ir" #property version "1.00" #property description "SaherElm XBackTester" #property strict // #define ShortName "XBackTester" // // Imports ... #include "../Classes/x-saherelm.x-backtester.expert.class.mq5" #include "../Classes/x-saherelm.x-market.pattern.class.mq5" #include "../Helpers/x-saherelm.xom1.helper.mq5" // // Definitions ... // // Inputs ... // // Common ... input group "Common"; input long eaMagicNumber = 78692110; // Magic Number input int eaSlippage = 10; // Slippgae input string eaLogSuffix = ""; // Log Suffix // // 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 // // Indicator Inputs ... // input group "Calculation"; // // Short ... input ENUM_X_PERIOD_METHOD scMethod = X_PERIOD_AUTO; // How to Find Short Period input ENUM_TIMEFRAMES scPeriod = NULL; // Short Period // // Medium ... input ENUM_X_PERIOD_METHOD mcMethod = X_PERIOD_AUTO; // How to Find Medium Period input ENUM_TIMEFRAMES mcPeriod = NULL; // Medium Period // // Long ... input ENUM_X_PERIOD_METHOD lcMethod = X_PERIOD_AUTO; // How to Find Long Period input ENUM_TIMEFRAMES lcPeriod = NULL; // Long Period // // Hind ... input ENUM_X_PERIOD_METHOD hcMethod = X_PERIOD_AUTO; // How to Find Hind Period input ENUM_TIMEFRAMES hcPeriod = NULL; // Hind Period // // PV ... input ENUM_SERIESMODE upperMode = MODE_HIGH; // Peak Method input ENUM_SERIESMODE lowerMode = MODE_LOW; // Vale Method // // Others ... input ENUM_X_FIBO_LEVELS upperZoneLevel = X_FIBO_LEVEL_618; // Upper Zone Level input ENUM_X_FIBO_LEVELS lowerZoneLevel = X_FIBO_LEVEL_382; // Lower Zone Level input double sarStep = 0.02; // SAR Step input double sarMax = 0.2; // SAR Maximum input ENUM_MA_METHOD maMethod = MODE_EMA; // MA Method input ENUM_APPLIED_PRICE maAppliedTo = PRICE_CLOSE; // MA Applied To input int maFastLength = 7; // Fast MA Length input int maSlowLength = 20; // Slow MA Length // input group "Bar Timer"; input int barTimeFontSize = 10; // Font Size input string barTimeFont = "Arial"; // Font input color barTimeColor = clrYellow; // Text Color input ENUM_BASE_CORNER barTimeCorner = CORNER_RIGHT_LOWER; // Text Position // // Presentation ... input group "Presentation"; input bool showPV = true; // Show PV input bool showSAR = true; // Show Sar input bool showMAFast = true; // Show MA Fast input bool showMASlow = true; // Show MA Slow input bool showBarTime = true; // Show Bar Time input bool showFiboZone = false; // Show Fibo Zone // input int startCalculationForLastBars = 1500; // Calculate Last n Bars // input int sarArrowCode = 159; // Parabolic Sar Arrow Code input int peakArrowCode = 159; // Peaks Arrow Code input int valeArrowCode = 159; // Vales Arrow Code // // Define Local Variables ... // string eaLogTag; // EA Log Prefix ... XCBackTesterEA *eaExpert; // EA Expert ... XCMarketPatternDetector *eaPatternDetector; // EA Pattern Detector ... // XBarTracker eaBarTracker; // EA Bar Traker ... // int eaHandler = INVALID_HANDLE; // Indicator Handler ... int eaCTHandler = INVALID_HANDLE; // Candle Timer Handler ... // // Define Indicators Here ... // // Event Handlers ... // // Initialization ... int OnInit() { // // Preparing Tags ... string eaTag = (IsValid(eaLogSuffix) ? eaLogSuffix + "_" : "") + ShortName; // // Validate Inputs and Required Parameters // for EA to Works fine ... if (!ValidateInputs()) { return INIT_PARAMETERS_INCORRECT; } // // Initialize Timer ... if (!InitTimer()) { return INIT_FAILED; } // // Configure EA Expert Class ... eaExpert = new XCBackTesterEA(); // // Symbol / Period ... eaExpert.symbol = _Symbol; eaExpert.period = _Period; // // Common ... eaExpert.eaMagicNumber = eaMagicNumber; eaExpert.eaSlippage = eaSlippage; eaExpert.eaLogSuffix = eaTag; // // Alert ... eaExpert.eaEnableAlerts = eaEnableAlerts; eaExpert.eaLogAlerts = eaLogAlerts; eaExpert.eaMailAlerts = eaMailAlerts; eaExpert.eaPushAlerts = eaPushAlerts; eaExpert.eaTerminalAlerts = eaTerminalAlerts; // // Attach Event Handlers ... eaExpert.AddOnDealsChangedEventHandler(OnDealsChanged); eaExpert.AddOnStopLossEventHandler(OnStopLossTriggered); eaExpert.AddOnOrdersChangedEventHandler(OnOrdersChanged); eaExpert.AddOnTakeProfitEventHandler(OnTakeProfitTriggered); eaExpert.AddOnModifyPositionEventHandler(OnPositionModified); eaExpert.AddOnPositionsChangedEventHandler(OnPositionsChanged); eaExpert.AddOnTradeStateChangedEventHandler(OnTradeStateChanged); eaExpert.AddOnForceClosePositionEventHandler(OnPositionForceClosed); eaExpert.AddOnPartialClosePositionEventHandler(OnPositionPartialClosed); // // Configure Other Requirements ... eaExpert.volume = 0.01; eaExpert.riskInPoint = 200; eaExpert.allowedTPSLStep = 10; eaExpert.riskToRewardRatio = 2; eaExpert.minAllowedRiskInPoint = 20; // // Try to Initialize eaExpert ... bool isInited = eaExpert.HandleOnInit(); if (!isInited) { // Print(ShortName, ": Initialization Failed ..."); return INIT_FAILED; } // // Initial Indicator Handler ... eaHandler = iCustom( _Symbol, _Period, "x-saherelm.xom1", "", // Calculation ... scMethod, scPeriod, mcMethod, mcPeriod, lcMethod, lcPeriod, hcMethod, hcPeriod, upperMode, lowerMode, upperZoneLevel, lowerZoneLevel, sarStep, sarMax, maMethod, maAppliedTo, maFastLength, maSlowLength, "", // Presentation ... showPV, showSAR, showMAFast, showMASlow, showFiboZone, startCalculationForLastBars, sarArrowCode, peakArrowCode, valeArrowCode // ); isInited = eaHandler != INVALID_HANDLE; if (!isInited) { // Print(ShortName, ": Initialization Failed ..."); return INIT_FAILED; } // // Initialize Candle Timer Handler ... eaCTHandler = iCustom( _Symbol, _Period, "x-saherelm.x121.xct", // // Inputs ... barTimeFontSize, // Font Size ... barTimeFont, // Font ... barTimeColor, // Text Color ... barTimeCorner, // Text Position ... // // Presentation ... "", showBarTime // Show Candle Time // ); isInited = eaCTHandler != INVALID_HANDLE; if (!isInited) { // Print(ShortName, ": Initialization Failed ..."); return INIT_FAILED; } // // Initialize Bar Tracker ... isInited = eaBarTracker.Init( _Symbol, _Period // ); if (!isInited) { // Print(ShortName, ": Initialization Failed ..."); return INIT_FAILED; } // // Instantiate Market Pattern Detector ... eaPatternDetector = new XCMarketPatternDetector(); // Print(ShortName, ": Initialized Successfully ..."); 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 // // Destroy Timer ... eaExpert.HandleOnDeInit(); // // De Init Indicator ... IndicatorRelease(eaHandler); // eaBarTracker.Clean(); // delete eaPatternDetector; ZeroMemory(eaPatternDetector); // delete eaExpert; ZeroMemory(eaExpert); } // // On Tick Handler ... void OnTick() { // eaExpert.HandleOnTick(); // bool isNewBar = eaBarTracker.IsNewBar(); if (isNewBar) { // // Initialize 1 Indexed Bar ... XOHCL cBar; bool has = cBar.Init( _Symbol, _Period, 1 // ); if (has) { // // Do Analysis ... // ENUM_X_DIRECTION iDir = X_DIRECTION_NONE; // // Checking Momentum Bar ... bool isMomentum = eaPatternDetector.IsMomentumBar( cBar, iDir // ); bool isBullishMomentum = isMomentum && IsSpecifiedBullish(iDir); bool isBearishMomentum = isMomentum && IsSpecifiedBearish(iDir); if (isMomentum) { Print(ToXString(iDir), " Momentum Bar: ", cBar.time); } // // Checking Engulfed Bar ... bool isEngulfed = eaPatternDetector.IsEngulfedBar( cBar, iDir // ); bool isBullishEngulfed = isEngulfed && IsSpecifiedBullish(iDir); bool isBearishEngulfed = isEngulfed && IsSpecifiedBearish(iDir); if (isEngulfed) { Print(ToXString(iDir), " Engulfed Bar: ", cBar.time); } // // Checking TruGaped Bar ... bool isTrueGaped = eaPatternDetector.IsTrueGapedBar( cBar, iDir // ); bool isBullishTrueGaped = isTrueGaped && IsSpecifiedBullish(iDir); bool isBearishTrueGaped = isTrueGaped && IsSpecifiedBearish(iDir); if (isTrueGaped) { Print(ToXString(iDir), " TrueGapped Bar: ", cBar.time); } // // Checking Pinned Bar ... bool isPinned = eaPatternDetector.IsPinnedBar( cBar, iDir // ); bool isBullishPinned = isPinned && IsSpecifiedBullish(iDir); bool isBearishPinned = isPinned && IsSpecifiedBearish(iDir); if (isPinned) { Print(ToXString(iDir), " Pinned Bar: ", cBar.time); } // // Checking Star Pattern ... bool isStarPattern = eaPatternDetector.IsStartPattern( cBar, iDir // ); bool isBullishStarPattern = isStarPattern && IsSpecifiedBullish(iDir); bool isBearishStarPattern = isStarPattern && IsSpecifiedBearish(iDir); if (isStarPattern) { Print(ToXString(iDir), " Star Pattern: ", cBar.time); } // // Checking Piercing Pattern ... bool isPiercingPattern = eaPatternDetector.IsPiercingPattern( cBar, iDir // ); bool isBullishPiercingPattern = isPiercingPattern && IsSpecifiedBullish(iDir); bool isBearishPiercingPattern = isPiercingPattern && IsSpecifiedBearish(iDir); if (isPiercingPattern) { Print(ToXString(iDir), " Piercing Pattern: ", cBar.time); } // // Checking Rising Pattern ... bool isRisingPattern = eaPatternDetector.IsRisingPattern( cBar, iDir // ); bool isBullishRisingPattern = isRisingPattern && IsSpecifiedBullish(iDir); bool isBearishRisingPattern = isRisingPattern && IsSpecifiedBearish(iDir); if (isRisingPattern) { Print(ToXString(iDir), " Rising Pattern: ", cBar.time); } // // Checking Flag Pattern ... XOHCL swingBar; bool isFlagPattern = eaPatternDetector.IsFlagPattern( cBar, iDir, swingBar // ); bool isBullishFlagPattern = isFlagPattern && IsSpecifiedBullish(iDir); bool isBearishFlagPattern = isFlagPattern && IsSpecifiedBearish(iDir); if (isFlagPattern) { Print(ToXString(iDir), " Flag Pattern: ", cBar.time, ", Swing: ", swingBar.time); } swingBar.Clean(); } // cBar.Clean(); } } // // Handle On Trade Event ... void OnTrade() { eaExpert.HandleOnTrade(); } // // On Timer ... void OnTimer() { eaExpert.HandleOnTimer(); } // // Chart Event Handler ... void OnChartEvent( const int id, const long &lparam, const double &dparam, const string &sparam // ) { eaExpert.HandleOnChartEvent(id, lparam, dparam, sparam); } // // Custom Functions ... /** * Validate all Inputs of Expert Adviser ... * * @return ( bool ) */ bool ValidateInputs() { // bool result = false; // string errMessage = ""; // bool isCommonValid = ( // eaSlippage > 0 && eaMagicNumber > 0 && // // Indicator Inputs ... // // MA ... maFastLength >= 2 && maSlowLength >= 2 && maSlowLength > maFastLength && // // SAR ... sarMax > 0 && sarStep > 0 && sarMax > sarStep && // // CYCLES ... (IsValid(scMethod, scPeriod) && IsValid(mcMethod, mcPeriod) && IsValid(lcMethod, lcPeriod) && IsValid(hcMethod, hcPeriod)) // ); 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(); } // // Trade Event Handlers ... /** * Handle StopLoss Triggered Positions ... * * @param deal: XDeal instance ... */ void OnStopLossTriggered(const XDeal &deal) { eaExpert.HandleOnStopLossTriggered(deal); } /** * Handle Take Profit Triggered Positions ... * * @param deal: XDeal instance ... */ void OnTakeProfitTriggered(const XDeal &deal) { eaExpert.HandleOnTakeProfitTriggered(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 // ) { // eaExpert.HandleOnPositionForceClosed( ticket, position, comment // ); } /** * Handle Deals Changes ... * * @param count: Integer, Number of Changes ... */ void OnDealsChanged(int count) { eaExpert.HandleOnDealsChanged(count); } /** * Handle Orders Changes ... * * @param count: Integer, Number of Changes ... */ void OnOrdersChanged(int count) { eaExpert.HandleOnOrdersChanged(count); } /** * Handle Positions Changes ... * * @param count: Integer, Number of Changes ... */ void OnPositionsChanged(int count) { eaExpert.HandleOnPositionsChanged(count); } /** * Handle Position Modified ... * * @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 // ) { // eaExpert.HandleOnPositionModified( ticket, profit, comment // ); } /** * Handle Position Partial Closed ... * * @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 // ) { // eaExpert.HandleOnPositionPartialClosed( ticket, profit, comment // ); } /** * Handle Trade State Changed ... * * @param state: XOnTradeHandlerState instance ... */ void OnTradeStateChanged(const XOnTradeHandlerState &state) { eaExpert.HandleOnTradeStateChanged(state); } //