/////////////////////////////////////////////////////// // // 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"; // 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 // // Trade ... input bool allowTrade = true; // Allow Trade Based on given Signals input bool allowLongTrades = true; // Allow Long Trades input bool allowShortTrades = false; // Allow Short Trades // // Market Specification Inpouts ... input int marketLength = 7; // Market Length input double riskToRewardRatio = 1.5; // Risk to Reward Ratio // input double maxTPMultiplier = 1000; // Max Allowed TP // // 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.05; // Maximum DrawDown Per Trade input double minBalancePercent = 0.5; // Minimum Balance for Trading input double maxEquityPercent = 0.1; // Maximum Trade Equity input int closeAllOpenTradesAfterCandle = 408; // Close All Open Trades After Passed Candles input bool closeAllInProfitOpenTradesWhenMaxOpenTradesReached = false; // Close All In Profit Open Trades When Max Open Trades Reached and New Signal Income // // Indicators ... // // CCI Inputs ... input double step = 0.01; // SAR Step input double maximum = 0.1; // SAR Maximum // // XMA Inputs ... // input int shortCycleFastMultiplier = 2; // Short Cycle Fast Multiplier input int shortCycleSlowMultiplier = 4; // Short Cycle Slow Multiplier input int mediumCycleFastMultiplier = 6; // Medium Cycle Fast Multiplier input int mediumCycleSlowMultiplier = 12; // Medium Cycle Slow Multiplier input int longCycleFastMultiplier = 36; // Long Cycle Fast Multiplier input int longCycleSlowMultiplier = 72; // Long Cycle Slow Multiplier // // SHPD Indicator ... input double sharpDetectMultiplier = 800; // Sharp Detect Multiplier // // END Inputs ... // // // START Global Definitions: Variables, Properties and etc ... // int lastSignalledBar = 0; // bool waitForLongSignals = true; bool closeLongTrades = false; // bool waitForShortSignals = true; bool closeShortTrades = false; // // Includes our shared library ... #include "../Libraries/x-saherelm.lib.mq4" // // Includes our shared library ... #include "../Libraries/x-saherelm.signal.lib.mq4" // // END Global Definitions: Variables, Properties and etc ... // // // Start Event Handlers ... // // // Initialization ... int OnInit() { // // Validate Inputs ... bool inputsNotValiid = // // MARKET ... marketLength < 0 || riskToRewardRatio < 0 // // EA ... || lotsPerTradePercent < 0 || maxOpenTrades <= 0 || maxDrawdownPercentPerPTrade < 0 || minBalancePercent < 0 || maxEquityPercent < 0 || marketLength < 0 // // XMA ... // // Validate Short Cycle ... || shortCycleFastMultiplier <= 0 || shortCycleSlowMultiplier <= 0 || shortCycleFastMultiplier >= shortCycleSlowMultiplier // // Validate Medium Cycle ... || mediumCycleFastMultiplier <= 0 || mediumCycleSlowMultiplier <= 0 || mediumCycleFastMultiplier >= mediumCycleSlowMultiplier // // Validate Long Cycle ... || longCycleFastMultiplier <= 0 || longCycleSlowMultiplier <= 0 || longCycleFastMultiplier >= longCycleSlowMultiplier // // Validate Series of Multipliers ... || shortCycleFastMultiplier >= mediumCycleFastMultiplier || mediumCycleFastMultiplier >= longCycleFastMultiplier ; // 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"; // // // // Set Event Timer on One Seccond ... // bool isEventSet = EventSetTimer(1); // if (!isEventSet) { // LogMessage("Error: " + GetLastError()); // return INIT_FAILED; // } // ClearSignalConditions(); // return INIT_SUCCEEDED; } // // DeInitialization ... void OnDeinit(const int reason) { // // Killing Event Timer ... EventKillTimer(); } // // Ticker Event Handler ... void OnTick() { // isNewDay = IsNewDay(); if (isNewDay) { // LogMessage( StringConcatenate( "New Day: ", TimeCurrent() ) ); } // // Process Signals to Open Positions ... ProcessSignals(); // // Checking State for Signal Handling ... CheckState(); // // Process Open Positions for Trailing Stop Loss or Close ... ProcessOpenPositions(); } // // Timer Event Handler ... void OnTimer() { // CheckState(); // 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 ... // // // closeLongTrades = xCloseLongTrades; // waitForLongSignals = xWaitForLongSignals; // // // closeShortTrades = xCloseShortTrades; // waitForShortSignals = xWaitForShortSignals; // // // xCloseLongTrades = false; // xCloseShortTrades = false; } // // 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 < longCycleSlowMultiplier * marketLength) { 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 ) { // allowDoTrade = false; // // // string message = StringConcatenate( // "Trading Pause => ", // "Balance: ", balance, // ", Equity: ", equity, // ", FreeMargin: ", freeMargin // ); // // // LogMessage(message); // SendAlert(message); } } // // 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 For Bot State ... if ( (hasLongSignal && !waitForLongSignals) || (!hasLongSignal && !waitForShortSignals) ) { // // Clear Signal Conditions ... if (hasLongSignal) { ClearLongSignalConditions(); } else { ClearShortSignalConditions(); } // return; } // // Check last Signalled Bar with Counted Bars ... // Prevent Multiple Signalling on Same Bar ... bool isInLastSignalledBars = false; for (int i=0; i < marketLength; 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 (closeAllInProfitOpenTradesWhenMaxOpenTradesReached) { // // Close All In Profit Trades ... bool hasClosedInProfitTrade = CloseAllInProfitTrades(); if (hasClosedInProfitTrade) { // openTrades = CountOpenTrades(); // allowDoTrade = !(openTrades >= maxOpenTrades); } } // 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, signalPrefix, 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, ", 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() { // // this comes from check state ... if (closeLongTrades) { // closeLongTrades = false; // bool isAllLongTradesClosed = CloseAllLongTrades(); if (isAllLongTradesClosed) { } } // // this comes from check state ... if (closeShortTrades) { // closeShortTrades = false; // bool isAllShortTradesClosed = CloseAllShortTrades(); if (isAllShortTradesClosed) { } } // bool hasClosedLongTimeTrade = CloseAllLongTimeTrades( closeAllOpenTradesAfterCandle ); // // Close Maximum DrawDown Passed Trades ... bool hasClosedInDrawDownLongTrade = CloseAllMaximumDrawDownPassedTrades( maxDrawdownPercentPerPTrade ); // if ( hasClosedLongTimeTrade || hasClosedInDrawDownLongTrade ) { // // waitForLongSignals = false; } } // // 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 = {}; // // Retrieve XMA States ... // based on medium cycle slow ... XState states[]; ArrayFree(states); ArrayResize( states, marketLength ); // int index = 0; for (int i = bar_index; i < bar_index + marketLength; i++) { // states[index] = GetXState( i, marketLength, // step, maximum, // shortCycleFastMultiplier, shortCycleSlowMultiplier, mediumCycleFastMultiplier, mediumCycleSlowMultiplier, longCycleFastMultiplier, longCycleSlowMultiplier ); // index++; } // CheckXLongSignalConditions( bar_index, marketLength, states ); // CheckXShortSignalConditions( bar_index, marketLength, states ); // XSignalRequest xLongSignalRequest = GenerateXSignal( X_SIGNAL_LONG, bar_index, marketLength, riskToRewardRatio, states ); // XSignalRequest xShortSignalRequest = GenerateXSignal( X_SIGNAL_SHORT, bar_index, marketLength, riskToRewardRatio, states ); // if (xLongSignalRequest.hasSignal) { // // Here we can Check and Filter Signals Based On State ... bool isReady = IsReadyForXSignals( xLongSignalRequest.signal, states, marketLength ); // if (isReady) { // hasLongSignal = true; signal = xLongSignalRequest.signal; } else { ClearXLongSignalConditions(); } } else if (xShortSignalRequest.hasSignal) { // // Here we can Check and Filter Signals Based On State ... bool isReady = IsReadyForXSignals( xShortSignalRequest.signal, states, marketLength ); // if (isReady) { // hasShortSignal = true; signal = xShortSignalRequest.signal; } else { ClearXShortSignalConditions(); } } // 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; }