/////////////////////////////////////////////////////// // // 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 = 2; // 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.0003; // Lots Per Trade Percent input int maxOpenTrades = 4; // Maximum Open Trade input double maxDrawdownPercentPerPTrade = 0.45; // 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 ... lotsPerTradePercent < 0 || maxOpenTrades <= 0 || maxDrawdownPercentPerPTrade < 0 || minBalancePercent < 0 || maxEquityPercent < 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; } // bool isPositionOpened = TradeSignal( request.signal, lotsPerTradePercent, // 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: ", GetProviderIdentifier(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; } // bool hasClosedLongTimeTrade = CloseAllLongTimeTrades( xMaximumCandlesPerTrade, X_XXX_PROVIDER ); } // // XR Signalling ... if (enableXRSignalling) { // if (xrCloseLongTrades) { // CloseAllProviderLongTrades(X_XR_PROVIDER); // xrCloseLongTrades = false; } // bool hasClosedLongTimeTrade = CloseAllLongTimeTrades( xRMaximumCandlesPerTrade, X_XR_PROVIDER ); } // // Close Maximum DrawDown Passed Trades ... bool hasClosedInDrawDownLongTrade = CloseAllMaximumDrawDownPassedTrades( maxDrawdownPercentPerPTrade ); } // // 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 = {}; // // START XR Signal Handler ... // // if (enableXRSignalling) { // CheckXRSignalHandler( bar_index ); // // Long Trades ... if (allowTrade && allowLongTrades) { // CheckXRLongSignalConditions( bar_index ); // XSignalRequest 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(); } } } // // Short Trades ... if (allowTrade && allowShortTrades) { } } // // END XR Signal Handler ... // // // START X Signal Handler ... // // if (enableXSignalling) { // CheckXSignalHandler( bar_index ); // // Long Trades ... if (allowTrade && allowLongTrades) { // if (xWaitForLongSignals) { // CheckXLongSignalConditions( bar_index ); // XSignalRequest 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 ); // XSignalRequest 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; }