/////////////////////////////////////////////////////// // // SaherElm IT Center XCZone MQL5 Expert Advisor // ------------------------------------------------- // Name: XCAEA // Description: an Exper Advisor which used XCZone // // 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 XCZone indicators" #property strict // // Include Common Library ... #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 "../Libraries/x-saherelm.common.lib.mq5" #include "../XCAEA/Classes/xcaea.x-trade.manager.class.mq5" #include "../XCAEA/Helpers/xcaea.helper.mq5" #include "../XCAEA/Libraries/xcaea.trigger.block.lib.mq5" // #define ShortName "XCZONEEA" // // Inputs ... // // Common ... input group "Common"; input long eaMagicNumber = 78692110; // Magic Number input int eaSlippage = 10; // Slippgae input string eaLogSuffix = ""; // Log Suffix // // Detector ... input group "Detector"; // // Ranges ... input double eaMaxAllowedRange = 0.0; // Maximum Allowed Range input int eaMinAllowedBlockEdgeLength = 7; // Minimum Required Block Edge Length // // Validation ... input bool eaForceFVGBarType = true; // Force FVG to Has Same Type of Bars input bool eaForceHasSwingBar = true; // Force Has Propper Swing input bool eaForceOBOppositBar = true; // Force OB to Start by Opposit Bars input bool eaForceHasLiquidity = false; // Force Has Following Liquidity Zone input bool eaForceGapBarBreakout = true; // Force FVG's Gap Bar to Breakeout OB Edge Side input bool eaForceHasReversalLiquidity = true; // Force Has Reversal Liquidity Zone // // Filtering ... input bool eaFilterBasedOnSar = true; // Filter Trigger Block Based on Sar input bool eaFilterBasedOnRSI = true; // Filter Trigger Block Based on RSI input bool eaFilterBasedOnADX = true; // Filter Trigger Block Based on ADX input bool eaFilterBasedOnTrend = true; // Filter Trigger Block Based on Trend input bool eaFilterBasedOnScores = true; // Filter Trigger Block Based on Scores input bool eaFilterBasedOnVolumes = true; // Filter Trigger Block Based on Volumes // // Signals ... input group "Signals"; input double maxAllowedR2R = 2; // Max Allowed R2R input double eaSLAdditionalPoint = 0.0; // Additional SL in Point input double eaSLATRMultiplier = 0.0; // Additional SL using ATR Multiplier // // 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_NONE; // Trade Restrictions Period input int eaMaxAllowedTPs = 0; // Max Allowed TP(s) per Day input int eaMaxAllowedSLs = 0; // Max Allowed SL(s) per Day input int eaMaxAllowedTrades = 0; // 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 ... // XCAlert *eaAlert; XCTrade *eaTrade; XSignal eaSignal; XCVolume *eaVolume; XCAEAInputs eaInputs; XCXCAEAHelper *eaHelper; XBarTracker eaBarTraker; XTimeTracker eaTimeTracker; XCXCAEATradeManager *eaTradeManager; XCAEAStrategyConditions eaConditions; // XTriggerBlock eaTB; XBoxZone eaUpperRange; XBoxZone eaLowerRange; XCAEATriggerBlockConfiguration eaTBConfig; // CArrayObj *eaObjects; // string eaTag = ""; // // Event Handlers ... // // Initialization ... int OnInit() { // // Validate Inputs and Required Parameters // for EA to Works fine ... if (!ValidateInputs()) { return INIT_PARAMETERS_INCORRECT; } // // Initial Requirements ... InitRequirements(); // // Configure Detector ... ConfigureDetector(); // // 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 eaVolume; ZeroMemory(eaVolume); // eaSignal.Clean(); eaTBConfig.Clean(); eaBarTraker.Clean(); eaConditions.Clean(); eaTimeTracker.Clean(); // DestroyTimer(); } // // On Tick Handler ... void OnTick() { // HandleTimeReport(); // // Handle Position Management / Protections ... eaTradeManager.Manage(); // eaSignal.Clean(); eaConditions.Clean(); // // Check Bar Processing ... if (!eaBarTraker.CanProcessBar()) { return; } // bool has = false; // // Retrieve Bars ... XOHCL zBar; XOHCL cBar; has = zBar.Init( _Symbol, _Period, 0 // ); has = has && zBar.GetPreviousBar(cBar); if (!has) { // zBar.Clean(); cBar.Clean(); // return; } // double bid = GetBid(zBar.symbol); // // Detect Range Blocks ... double mid = 0; double range = 0; XBoxZone upperRNGB; XBoxZone lowerRNGB; bool isIn = false; has = eaHelper .barAnalyser .DetectRangeBlocks( zBar, upperRNGB, lowerRNGB, (288 * 5) // ); if (has) { // // Setting Range Boxes ... upperRNGB.to = zBar.time; lowerRNGB.to = zBar.time; eaUpperRange.to = zBar.time; eaLowerRange.to = zBar.time; // bool canSet = false; // // Set Upper Range ... canSet = !eaUpperRange.IsValid() ? true : upperRNGB.upper > eaUpperRange.upper; if (canSet) { eaUpperRange = upperRNGB; } // // Set Lower Range ... canSet = !eaLowerRange.IsValid() ? true : lowerRNGB.lower < eaLowerRange.lower; if (canSet) { eaLowerRange = lowerRNGB; } } // // Calculate Requirements ... range = eaUpperRange.lower - eaLowerRange.upper; mid = eaUpperRange.lower - (range / 2); // double price = zBar.close; // bid; // // Check Price in Upper Tange ... bool isInUpperRange = price >= eaUpperRange.lower && price <= eaUpperRange.upper; // // Check Price in Lower Range ... bool isInLowerRange = price >= eaLowerRange.lower && price <= eaLowerRange.upper; // isIn = isInUpperRange || isInLowerRange; if (isIn) { // if (isInUpperRange) { eaLowerRange = lowerRNGB; } // if (isInLowerRange) { eaUpperRange = upperRNGB; } // Print("IsIn ..."); } // // Do Detection ... has = DetectTriggerBlock( eaTB, eaHelper, eaTBConfig, zBar.Index(), 10, eaSLAdditionalPoint, eaSLATRMultiplier // ); if (has) { // bool isBullish = eaTB.trigger.IsBullish(); // has = isBullish ? zBar.close < mid : zBar.close > mid; if (!has) { eaTB.Clean(); } } // // Draws ... // // Darw Ranges ... has = eaUpperRange.IsValid() && eaLowerRange.IsValid(); if (has) { // // Draw Ranges ... // // Draw Upper Range ... XCBoxObject *iUpperObj; has = eaHelper.poiDrawer.DrawBox( eaUpperRange, iUpperObj // ); if (has) { // // Style Object ... // // Store Object ... eaObjects.Add(iUpperObj); } // // Draw Lower Range ... XCBoxObject *iLowerObj; has = eaHelper.poiDrawer.DrawBox( eaLowerRange, iLowerObj // ); if (has) { // // Style Object ... // // Store Object ... eaObjects.Add(iLowerObj); } // // Draw Fibonacchi ... } // // Draw Trigger Block ... has = eaTB.IsValid(); if (has) { // if (eaTB.signal.IsValid()) { // eaSignal = eaTB.signal; // eaConditions.symbol = eaTB.signal.symbol; eaConditions.period = eaTB.signal.period; eaConditions.conditions = eaTB.conditions; } // CArrayObj *tObjects; tObjects = new CArrayObj(); // has = DrawTriggerBlock( eaTB, tObjects, eaHelper, NULL, // zBar.time, 0 // Prevent Drawing RR Zones ... ); if (has) { AddObjects(tObjects, eaObjects); } } // // Handle Signals ... // // Check Signal Validation ... if (eaSignal.IsValid()) { // // Do What we Want ... // When we Need Waits Until Next Bar ... eaBarTraker.Waits(); // bool isLong = IsLong(eaSignal.type); // // Update Entry ... eaSignal.entry = GetEntry( eaSignal.symbol, eaSignal.type // ); // // Try to Check Liquidity ... if (eaTB.rLiquidity.IsValid()) { // double irLQRange = eaTB.rLiquidity.GetRange(); eaSignal.sl = isLong ? eaSignal.sl - irLQRange : eaSignal.sl + irLQRange; } // // Apply Signal Targets ... ApplySignalTargets(eaSignal); // // 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 // ); } // // Cleanup Resources ... // eaTB.Clean(); zBar.Clean(); cBar.Clean(); 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; // // Initial Bar Tracker ... eaBarTraker.Init( _Symbol, _Period // ); // // Objects ... eaObjects = new CArrayObj(); // // Configure XCA ... eaInputs.Default(); // // Hide all Visible Buffers ... eaInputs.Hide(); // // we Can make Show all requirements here ... eaInputs.caInputs.showSar = false; // eaHelper = new XCXCAEAHelper(); bool isInited = eaHelper.Init( _Symbol, _Period, eaInputs // ); // // 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 // ); } // void ConfigureDetector() { // // Configure Detector ... // // Validation ... eaTBConfig.maxAllowedRange = eaMaxAllowedRange; eaTBConfig.minAllowedBlockEdgeLength = eaMinAllowedBlockEdgeLength; // // Validation ... eaTBConfig.forceFVGBarType = eaForceFVGBarType; eaTBConfig.forceHasSwingBar = eaForceHasSwingBar; eaTBConfig.forceOBOppositBar = eaForceOBOppositBar; eaTBConfig.forceHasLiquidity = eaForceHasLiquidity; eaTBConfig.forceGapBarBreakout = eaForceGapBarBreakout; eaTBConfig.forceHasReversalLiquidity = eaForceHasReversalLiquidity; // // Filters ... eaTBConfig.filterBasedOnSar = eaFilterBasedOnSar; eaTBConfig.filterBasedOnADX = eaFilterBasedOnADX; eaTBConfig.filterBasedOnRSI = eaFilterBasedOnRSI; eaTBConfig.filterBasedOnTrend = eaFilterBasedOnTrend; eaTBConfig.filterBasedOnScores = eaFilterBasedOnScores; eaTBConfig.filterBasedOnVolumes = eaFilterBasedOnVolumes; // // Targets ... double targets[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, }; Copy( targets, eaTBConfig.targets // ); } /** * 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); } } // // Apply Signal Targets ... void ApplySignalTargets(XSignal &signal) { // bool has = signal.IsValid(); if (!has) { return; } // // Clean Signal Targets ... Clean(signal.targets); // // Calculate Requirements ... double r2r = maxAllowedR2R > 0 ? maxAllowedR2R : 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 // ); }