/////////////////////////////////////////////////////// // // 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 = 2; // 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.03; // Maximum DrawDown Per Trade input double minBalancePercent = 0.5; // Minimum Balance for Trading input double maxEquityPercent = 0.1; // Maximum Trade Equity input int closeAllOpenTradesAfterCandle = 252; // 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 shortCycleMultiplier = 2; // Short Cycle Fast Multiplier input int mediumCycleMultiplier = 6; // Medium Cycle Fast Multiplier input int longCycleMultiplier = 36; // Long Cycle Fast Multiplier // // 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 ... || shortCycleMultiplier <= 0 // // Validate Medium Cycle ... || mediumCycleMultiplier <= 0 // // Validate Long Cycle ... || longCycleMultiplier <= 0 // // Validate Series of Multipliers ... || shortCycleMultiplier >= mediumCycleMultiplier || mediumCycleMultiplier >= longCycleMultiplier ; // 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 ..." ) ); } // // 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 ... } // // 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 < longCycleMultiplier * 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, lotsPerTradePercent, // bullishSignalLabel, bullishSignalColor, bearishSignalLabel, bearishSignalColor ); // totalSignals++; if (hasLongSignal) { // totalLongSignals++; ClearLongSignalConditions(); } else { // totalShortSignals++; ClearShortSignalConditions(); } // // // if (isPositionOpened) { // // // int rangeMarketLength = marketLength * longCycleMultiplier; // XRange range = GetMarketRange( // 0, // rangeMarketLength, // marketLength // ); // // // DrawRange( // range, // 0, // 0, // signalPrefix // ); // } // // // double fibLevel = 1.618; // double fibLevelPrice = GetFibonacciLevel( // request.signal.tp, // request.signal.entry, // fibLevel, // 1 // ); // string lbl = StringConcatenate( // request.signal.tag, // "_FIB_", // fibLevel, // "_", // fibLevelPrice // ); // // // datetime time1 = iTime( // _Symbol, // _Period, // 1 // ); // // // datetime time2 = iTime( // _Symbol, // _Period, // 0 // ); // // // DrawTrendLine( // 0, // lbl, // 0, // time1, // fibLevelPrice, // time2, // fibLevelPrice, // clrYellow, // STYLE_DOT // ); // 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) { } } // // Close All XXX Provided Signals on it's Specific Condition ... if (xCloseLongTrades) { // CloseAllProviderLongTrades(X_XXX_PROVIDER); // xCloseLongTrades = false; } // 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, // shortCycleMultiplier, mediumCycleMultiplier, longCycleMultiplier ); // index++; } // CheckSignalHandler( bar_index, marketLength, states ); // CheckXLongSignalConditions( bar_index, marketLength, states ); // XSignalRequest xLongSignalRequest = GenerateXSignal( X_SIGNAL_LONG, signalPrefix, bar_index, marketLength, longCycleMultiplier, riskToRewardRatio, states ); // // // CheckXShortSignalConditions( // bar_index, // marketLength, // states // ); // // // XSignalRequest xShortSignalRequest = GenerateXSignal( // X_SIGNAL_SHORT, // signalPrefix, // bar_index, // marketLength, // longCycleMultiplier, // riskToRewardRatio, // states // ); // if (xLongSignalRequest.hasSignal) { // // Here we can Check and Filter Signals Based On State ... bool isReady = IsReadyForXSignals( xLongSignalRequest.signal, states, marketLength, // shortCycleMultiplier, mediumCycleMultiplier, longCycleMultiplier ); // if (isReady && xWaitForLongSignals) { // 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, // // // shortCycleMultiplier, // mediumCycleMultiplier, // longCycleMultiplier // ); // // // 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; }