/////////////////////////////////////////////////////// // // SaherElm IT Center XST Strategy Expert Advisor // --------------------------------------------- // saherelm implementation of strategy expert advisor ... // in this EA, we try to combine multiple tools, to ashive best // results ... // // ShortName: XST // // Maintainer: // ------------ // Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) // +989121694056 // ////////////////////////////////////////////////////// // // Global Properties ... #property copyright "Copyright 2023, SaherElm IT Center" #property link "https://saherelm.ir" #property version "1.00" #property description "SaherElm XST Strategy Expert Advisor" #property strict // // START Inputs ... // // // Signal Prefixe ... input string signalPrefix = "XST_EA"; // Signal Prefix // // Signal Draw Specifications ... input string bullishSignalLabel = "X_BUY"; // Bullish Signal Label input color bullishSignalColor = clrAqua; // Bullish Signal Color // input string bearishSignalLabel = "X_SELL"; // Bearish Signal Label input color bearishSignalColor = clrFuchsia; // Bearish Signal Color // input color signalEntryColor = clrAquamarine; // Signal Entry Ptice Color input color signalSLColor = clrRed; // Signal SL Color input color signalTPColor = clrGreen; // Signal TP Color // input int candleGapBetweenSignals = 7; // How many Candle waits to new Signal from last one // // Trade ... input bool allowTrade = true; // Allow Trade Based on given Signals input bool allowLongTrades = true; // Allow Long Trades input bool allowShortTrades = true; // Allow Short Trades // // Alerts ... input bool alertEvents = true; // Alert Events input bool alertPositions = true; // Alert Positions input bool longPositionAlerts = true; // Alert Long Positions input bool shortPositionAlerts = true; // Alert Short Positions // // Alert Types ... input bool terminalAlert = false; // Terminal Alert input bool pushAlert = false; // Push Notification Alerts // // Balance and Finanical Specifications ... input double lotsPerTradePercent = 0.00001; // Lots Per Trade Percent input int maxOpenTrades = 4; // Maximum Open Trade input double maxDrawdownPercentPerPTrade = 0.1; // Maximum DrawDown Per Trade input double minBalancePercent = 0.5; // Minimum Balance for Trading input double maxEquityPercent = 0.1; // Maximum Trade Equity // // START Global Definitions: Variables, Properties and etc ... // int lastSignalledBar = 0; // // Includes our shared library ... #include "../Libraries/x-saherelm.lib.mq4" // // Includes our shared library ... #include "../Libraries/x-saherelm.signal.lib.mq4" // int maxMarketLength = 0; // // END Global Definitions: Variables, Properties and etc ... // // // Start Event Handlers ... // // // Initialization ... int OnInit() { // // Validate Inputs ... bool inputsNotValiid = // // EA ... maxOpenTrades <= 0 || maxEquityPercent < 0 || minBalancePercent < 0 || lotsPerTradePercent < 0 || maxDrawdownPercentPerPTrade < 0 ; // if (inputsNotValiid) { return INIT_PARAMETERS_INCORRECT; } // totalSignals = 0; totalLongSignals = 0; totalShortSignals = 0; // initialBalance = 0; // // START Define Array Series ... // // // END Define Array Series ... // // // here we specify logging enabled or not ... enableLogging = true; // // this is a Tag which attached to our Logger ... logTag = "XST"; // ClearSignalConditions(); // maxMarketLength = MathMax(0, GetDailyCandleCount()); // return INIT_SUCCEEDED; } // // DeInitialization ... void OnDeinit(const int reason) { } // // Ticker Event Handler ... void OnTick() { // isNewDay = IsNewDay(); if (isNewDay) { // LogMessage( StringConcatenate( "New Day ..." ) ); } // // Process Signals to Open Positions ... ProcessSignals(); // // Checking State for Signal Handling ... CheckState(); // // Process Open Positions for Trailing Stop Loss or Close ... ProcessOpenPositions(); } // // END Event Handlers ... // // // START Functions ... // // // Check State for Signal Handling ... void CheckState() { // // Here we Must to Check Market State for enable or disable // Signal Handlers and also make dection to close all long/short // trades ... } // // Calculate Signals and Process Based on Exists Signals ... void ProcessSignals() { // XSignalRequest request = {}; request.type = X_SIGNAL_NONE; request.hasSignal = false; // // Prevent Multiple Calculating on Same Bars ... isNewBar = IsNewBar(); if (isNewBar) { countedBars++; } // if (countedBars < maxMarketLength) { return; } // bool allowDoTrade = true; // // Check Balance ... if (initialBalance > 0) { // // Retrieve Account Balance ... double balance = AccountInfoDouble(ACCOUNT_BALANCE); double minimumBalanceForTrade = balance > initialBalance ? minBalancePercent * balance : minBalancePercent * initialBalance; // // Retrieve Account Equity ... double equity = AccountInfoDouble(ACCOUNT_EQUITY); double maxAllowedEquity = balance - (balance * maxEquityPercent); // // Retrieve Free Marigin ... double freeMargin = AccountFreeMargin(); double maximumMariginRisk = balance - (balance * maxEquityPercent); // if ( // // Do not Open Positions if equity not passed ... equity < maxAllowedEquity || // // Do not Open Positions if free margin not passed ... freeMargin <= maximumMariginRisk || // // Do not open positions if balance less than minimum ... balance <= minimumBalanceForTrade ) { // static bool tradingPauseAlerted; // allowDoTrade = false; // if (!tradingPauseAlerted) { // string message = StringConcatenate( "Trading Pause => ", "Balance: ", balance, ", Equity: ", equity, ", FreeMargin: ", freeMargin ); // LogMessage(message); SendAlert(message); // tradingPauseAlerted = true; } } } // // Retrieve Signal Exists ... request = GenerateSignal(0); // // Prevent doing anything else, if there is no signals ... if ( !allowDoTrade || !request.hasSignal || request.type == X_SIGNAL_NONE ) { return; } // bool hasLongSignal = request.type == X_SIGNAL_LONG; // // Check last Signalled Bar with Counted Bars ... // Prevent Multiple Signalling on Same Bar ... bool isInLastSignalledBars = false; for (int i=0; i < candleGapBetweenSignals; i++) { // isInLastSignalledBars = isInLastSignalledBars || lastSignalledBar == countedBars - i ; } if (isInLastSignalledBars) { // // Clear Signal Conditions ... if (hasLongSignal) { ClearLongSignalConditions(); } else { ClearShortSignalConditions(); } // return; } // // increase last signalled bar ... lastSignalledBar = countedBars; // // Calculate Can Trade or not ... allowDoTrade = allowTrade && ( hasLongSignal ? allowLongTrades : allowShortTrades ); // // Chack Maximum Open Positions ... int openTrades = CountOpenTrades(); if (maxOpenTrades > 0) { // if (openTrades >= maxOpenTrades) { // allowDoTrade = false; // if (!allowDoTrade) { // string message = StringConcatenate( "Trading Pause => ", "Max Open Trades (", maxOpenTrades, ") reached ..." ); // LogMessage(message); SendAlert(message); } } } // // Check Trading is Enable or not ... // nothing to do if trading is disabled ... if (!allowDoTrade) { // // Clear Signal Conditions ... if (hasLongSignal) { ClearLongSignalConditions(); } else { ClearShortSignalConditions(); } // string message = StringConcatenate( "Trading Not Allowed ..." ); // LogMessage(message); SendAlert(message); return; } // // Retrieve Signal Lots Per Trade ... double lPTradePercent = GetSignalLottage( request.signal, lotsPerTradePercent ); // bool isPositionOpened = TradeSignal( request.signal, lPTradePercent, // bullishSignalLabel, bullishSignalColor, bearishSignalLabel, bearishSignalColor ); // totalSignals++; if (hasLongSignal) { // totalLongSignals++; ClearLongSignalConditions(); } else { // totalShortSignals++; ClearShortSignalConditions(); } // if (isPositionOpened) { // bool canAlert = alertPositions && ( hasLongSignal ? longPositionAlerts : shortPositionAlerts ); // if (canAlert) { // // Alert Message ... string message = StringConcatenate( "Trade on Signal ID: ", request.signal.id, ", ProvidedBy: ", GetSignalProviderIdentifier(request.signal.provider), ", Entry: ", request.signal.entry, ", TP: ", request.signal.tp ); // // Terminal Alert ... if (terminalAlert) { Alert(message); } // // Push Alert ... if (pushAlert) { SendNotification(message); } } } } // // Process All Open Positions ... void ProcessOpenPositions() { // // XSignalling ... if (enableXSignalling) { // // Close All XXX Provided Signals on it's Specific Condition ... if (xCloseLongTrades) { // CloseAllProviderLongTrades(X_XXX_PROVIDER); // xCloseLongTrades = false; } // if (xCloseShortTrades) { // CloseAllProviderShortTrades(X_XTPW_PROVIDER); // xCloseShortTrades = false; } // // Close Maximum DrawDown Passed Trades ... // // Longs ... bool hasClosedLongInDrawDownLongTrade = CloseAllMaximumDrawDownPassedTrades( xLongMaxDrawdownPerTradePercent, X_SIGNAL_LONG, X_XXX_PROVIDER ); // // Shorts ... bool hasClosedShortInDrawDownLongTrade = CloseAllMaximumDrawDownPassedTrades( xShortMaxDrawdownPerTradePercent, X_SIGNAL_SHORT, X_XXX_PROVIDER ); // // Close All Long Time Trades based on Provider provided Length ... bool hasClosedLongTimeTrade = CloseAllLongTimeTrades( xMaximumCandlesPerTrade, X_XXX_PROVIDER ); // if ( hasClosedLongTimeTrade || hasClosedLongInDrawDownLongTrade || hasClosedShortInDrawDownLongTrade ) { xFailedSignals++; } } // // XR Signalling ... if (enableXRSignalling) { // if (xRCloseLongTrades) { // CloseAllProviderLongTrades(X_XR_PROVIDER); // xRCloseLongTrades = false; } // if (xRCloseShortTrades) { // CloseAllProviderShortTrades(X_XR_PROVIDER); // xRCloseShortTrades = false; } // // Close Maximum DrawDown Passed Trades ... // // Longs ... bool hasClosedLongInDrawDownLongTrade = CloseAllMaximumDrawDownPassedTrades( xRLongMaxDrawdownPerTradePercent, X_SIGNAL_LONG, X_XR_PROVIDER ); // // Shorts ... bool hasClosedShortInDrawDownLongTrade = CloseAllMaximumDrawDownPassedTrades( xRShortMaxDrawdownPerTradePercent, X_SIGNAL_SHORT, X_XR_PROVIDER ); // // Close All Long Time Trades based on Provider provided Length ... bool hasClosedLongTimeTrade = CloseAllLongTimeTrades( xRMaximumCandlesPerTrade, X_XR_PROVIDER ); // if ( hasClosedLongTimeTrade || hasClosedLongInDrawDownLongTrade || hasClosedShortInDrawDownLongTrade ) { xRFailedSignals++; } } // // XTPW Signalling ... if (enableXTPWSignalling) { // if (xTPWCloseLongTrades) { // CloseAllProviderLongTrades(X_XTPW_PROVIDER); // xTPWCloseLongTrades = false; } // if (xTPWCloseShortTrades) { // CloseAllProviderShortTrades(X_XTPW_PROVIDER); // xTPWCloseShortTrades = false; } // // Close Maximum DrawDown Passed Trades ... // // Longs ... bool hasClosedLongInDrawDownLongTrade = CloseAllMaximumDrawDownPassedTrades( xTPWLongMaxDrawdownPerTradePercent, X_SIGNAL_LONG, X_XTPW_PROVIDER ); // // Shorts ... bool hasClosedShortInDrawDownLongTrade = CloseAllMaximumDrawDownPassedTrades( xTPWShortMaxDrawdownPerTradePercent, X_SIGNAL_SHORT, X_XTPW_PROVIDER ); // // Close All Long Time Trades based on Provider provided Length ... bool hasClosedLongTimeTrade = CloseAllLongTimeTrades( xTPWMaximumCandlesPerTrade, X_XTPW_PROVIDER ); // if ( hasClosedLongTimeTrade || hasClosedLongInDrawDownLongTrade || hasClosedShortInDrawDownLongTrade ) { xTPWFailedSignals++; } } // // Close Maximum DrawDown Passed Trades ... // this is the Maximum Controller ... // double maxOfXPercent = enableXSignalling ? MathMax( xLongMaxDrawdownPerTradePercent, xShortMaxDrawdownPerTradePercent ) : 0 ; // double maxOfXRPercent = enableXRSignalling ? MathMax( xRLongMaxDrawdownPerTradePercent, xRShortMaxDrawdownPerTradePercent ) : 0 ; // double maxOfXTPWPercent = enableXTPWSignalling ? MathMax( xTPWLongMaxDrawdownPerTradePercent, xTPWShortMaxDrawdownPerTradePercent ) : 0 ; // double maxDrawDownPercent = MathMax( maxOfXPercent, maxOfXRPercent ); maxDrawDownPercent = MathMax( maxDrawDownPercent, maxOfXTPWPercent ); maxDrawDownPercent = MathMax( maxDrawDownPercent, maxDrawdownPercentPerPTrade ); // // we Calculate Max DrawDown Percent Per Trade ... // then try to Close based on them ... bool hasClosedInDrawDownLongTrade = CloseAllMaximumDrawDownPassedTrades( maxDrawDownPercent ); } // // Send Special Type of Alerts ... void SendAlert(string message) { // if (!alertEvents) { return; } // // Terminal Alert ... if (terminalAlert) { Alert(message); } // // Push Alert ... if (pushAlert) { SendNotification(message); } } // // END Functions ... // // // // Calculate Signal ... // in this function we calculate a signal exists in // specific bar or not ... XSignalRequest GenerateSignal( const int bar_index // Bar Index ... ) { // // create temp result ... XSignalRequest result = {}; result.hasSignal = false; result.type = X_SIGNAL_NONE; result.provider = X_UNKNOWN_PROVIDER; // bool hasSignal = false; bool hasLongSignal = false; bool hasShortSignal = false; // XSignal signal = {}; // // Define Template Signal Requests for Managing Multiple Signals ... // // X ... XSignalRequest xLongSignalRequest = {}; XSignalRequest xShortSignalRequest = {}; // // XR ... XSignalRequest xrLongSignalRequest = {}; XSignalRequest xrShortSignalRequest = {}; // // XTPW ... XSignalRequest xTPWLongSignalRequest = {}; XSignalRequest xTPWShortSignalRequest = {}; // // START XR Signal Handler ... // // if (enableXRSignalling) { // CheckXRSignalHandler( bar_index ); // // Long Trades ... if (allowTrade && allowLongTrades) { // if (xRWaitForLongSignals) { // CheckXRLongSignalConditions( bar_index ); // xrLongSignalRequest = GenerateXRSignal( X_SIGNAL_LONG, signalPrefix, bar_index ); // if (xrLongSignalRequest.hasSignal) { // // Here we can Check and Filter Signals Based On State ... bool isReady = IsReadyForXRSignals( xrLongSignalRequest.signal ); // if (isReady && xRWaitForLongSignals) { // hasLongSignal = true; signal = xrLongSignalRequest.signal; } else { ClearXRLongSignalConditions(); } } } else { ClearXRLongSignalConditions(); } } // // Short Trades ... if (allowTrade && allowShortTrades) { // if (xRWaitForShortSignals) { // CheckXRShortSignalConditions( bar_index ); // xrShortSignalRequest = GenerateXRSignal( X_SIGNAL_SHORT, signalPrefix, bar_index ); // if (xrShortSignalRequest.hasSignal) { // // Here we can Check and Filter Signals Based On State ... bool isReady = IsReadyForXRSignals( xrShortSignalRequest.signal ); // if (isReady && xRWaitForShortSignals) { // hasShortSignal = true; signal = xrShortSignalRequest.signal; } else { ClearXRShortSignalConditions(); } } } else { ClearXRShortSignalConditions(); } } } // // END XR Signal Handler ... // // // START XTPW Signal Handler ... // if (enableXTPWSignalling) { // CheckXTPWSignalHandler( bar_index ); // // Long Trades ... if (allowTrade && allowLongTrades) { // if (xTPWWaitForLongSignals) { // CheckXTPWLongSignalConditions( bar_index ); // xTPWLongSignalRequest = GenerateXTPWSignal( X_SIGNAL_LONG, signalPrefix, bar_index ); // if (xTPWLongSignalRequest.hasSignal) { // // Here we can Check and Filter Signals Based On State ... bool isReady = IsReadyForXTPWSignals( xTPWLongSignalRequest.signal ); // if (isReady && xTPWWaitForLongSignals) { // hasLongSignal = true; signal = xTPWLongSignalRequest.signal; } else { ClearXTPWLongSignalConditions(); } } } else { ClearXTPWLongSignalConditions(); } } // // Short Trades ... if (allowTrade && allowShortTrades) { // if (xTPWWaitForShortSignals) { // CheckXTPWShortSignalConditions( bar_index ); // xTPWShortSignalRequest = GenerateXTPWSignal( X_SIGNAL_SHORT, signalPrefix, bar_index ); // if (xTPWShortSignalRequest.hasSignal) { // // Here we can Check and Filter Signals Based On State ... bool isReady = IsReadyForXTPWSignals( xTPWShortSignalRequest.signal ); // if (isReady && xTPWWaitForShortSignals) { // hasShortSignal = true; signal = xTPWShortSignalRequest.signal; } else { ClearXTPWShortSignalConditions(); } } } else { ClearXTPWShortSignalConditions(); } } } // // END XTPW Signal Handler ... // // // START X Signal Handler ... // // if (enableXSignalling) { // CheckXSignalHandler( bar_index ); // // Long Trades ... if (allowTrade && allowLongTrades) { // if (xWaitForLongSignals) { // CheckXLongSignalConditions( bar_index ); // xLongSignalRequest = GenerateXSignal( X_SIGNAL_LONG, signalPrefix, bar_index ); // if (xLongSignalRequest.hasSignal) { // // Here we can Check and Filter Signals Based On State ... bool isReady = IsReadyForXSignals( xLongSignalRequest.signal ); // if (isReady && xWaitForLongSignals) { // hasLongSignal = true; signal = xLongSignalRequest.signal; } else { ClearXLongSignalConditions(); } } } else { ClearXLongSignalConditions(); } } // // Short Trades ... if (allowTrade && allowShortTrades) { // if (xWaitForShortSignals) { // CheckXShortSignalConditions( bar_index ); // xShortSignalRequest = GenerateXSignal( X_SIGNAL_SHORT, signalPrefix, bar_index ); // if (xShortSignalRequest.hasSignal) { // // Here we can Check and Filter Signals Based On State ... bool isReady = IsReadyForXSignals( xShortSignalRequest.signal ); // if (isReady && xWaitForShortSignals) { // hasShortSignal = true; signal = xShortSignalRequest.signal; } else { ClearXShortSignalConditions(); } } } else { ClearXShortSignalConditions(); } } } // // END XR Signal Handler ... // // hasSignal = hasLongSignal || hasShortSignal; // if (!hasSignal) { // signal.type = X_SIGNAL_NONE; result.type = X_SIGNAL_NONE; } // // Normalize TP, SL and Entry Price ... signal.tp = NormalizeDouble(signal.tp, _Digits); signal.sl = NormalizeDouble(signal.sl, _Digits); signal.entry = NormalizeDouble(signal.entry, _Digits); // result.signal = signal; result.type = signal.type; result.hasSignal = hasSignal; result.provider = signal.provider; // // Return Result ... return result; }