/////////////////////////////////////////////////////// // // 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 bool useOSCSignalling = false; // Use XOSC Signalling input string oscSignalIdentifier = "XOSC"; // XOSC Signal Identifier // input bool useXMASignalling = false; // Use XMA Signalling input string xmaSignalIdentifier = "XMA"; // XMA Signal Identifier // input bool useXSHPSignalling = true; // Use XSHP Signalling input string xshpSignalIdentifier = "XSHP"; // XSHP Signal Identifier // input bool useXMNTMSignalling = false; // Use XMNTM Signalling input string xmntmSignalIdentifier = "XMNTM"; // XMNTM Signal Identifier // input bool useXRSISignalling = true; // Use XRSI Signalling input string xrsiSignalIdentifier = "XRSI"; // XRSI Signal Identifier // 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 // // 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.01; // Maximum DrawDown Per Trade input double minBalancePercent = 0.5; // Minimum Balance for Trading input double maxEquityPercent = 0.1; // Maximum Trade Equity input int closeAllOpenTradesAfterCandle = 504; // 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 // // OSC Inputs ... // // FastOSC ... // Short Cycle (Fast OSC) ... input int fastOSCLength = 10; // FastOSC Length input double fastOSCMultiplier = 1.0; // FastOSC Multiplier // // SlowOSC ... // Medium Cycle (Slow OSC) ... input int slowOSCLength = 30; // SlowOSC Length input double slowOSCMultiplier = 3.0; // SlowOSC Multiplier // // XMA Inputs ... // input double step = 0.02; // SAR Step input double maximum = 0.2; // SAR Maximum 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 = 500; // 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; // bool isSharpBullishHappens; bool isSharpBearishHappens; // datetime startMarketTime; // // 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 // // OSC ... || fastOSCLength < 0 || fastOSCMultiplier < 0 || slowOSCLength < 0 || slowOSCMultiplier < 0 || slowOSCLength <= fastOSCLength // // 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; // } // 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 ... // // // START Signal Related 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_NONE; // XSignal signal = {}; // if (countedBars < (longCycleSlowMultiplier * marketLength)) { return result; } // int marketArraySize = shortCycleSlowMultiplier * marketLength; ArrayResize( oscStates, marketArraySize ); ArrayResize( xmaStates, marketArraySize ); ArrayResize( cciStates, marketArraySize ); // // Retrieve Bar Index Time ... datetime barTime = iTime( _Symbol, _Period, bar_index + 1 ); // // START Retrieve Statets ... // // // Loop through Market Length ... int index = 0; for (int i = bar_index; i < bar_index + marketArraySize; i++) { // // Retrieve XMA State ... XMAState xmaState = {}; // // Short Cycle ... XMACycleState sc = GetXMASC( i, marketLength, shortCycleFastMultiplier, shortCycleSlowMultiplier ); xmaState.sc = sc; // // Medium Cycle ... XMACycleState mc = GetXMAMC( i, marketLength, mediumCycleFastMultiplier, mediumCycleSlowMultiplier ); xmaState.mc = mc; // // Long Cycle ... XMACycleState lc = GetXMAMC( i, marketLength, longCycleFastMultiplier, longCycleSlowMultiplier ); xmaState.lc = lc; // // Market Middleage ... double marketMiddle = GetXMAMM( i, marketLength, 1.5 ); xmaState.marketMiddleage = marketMiddle; // // Parabolic SAR ... double pSar = GetXMAPSAR( i, step, maximum ); xmaState.parabolicSAR = pSar; // xmaStates[index] = xmaState; // // Retrieve OSC State ... // TODO Complete this ... XMACycleState oscState = {}; // // Retriec CCI ... double cciValue = GetMarketCCI( bar_index, longCycleSlowMultiplier * marketLength, PRICE_CLOSE ); cciStates[index] = cciValue; // index++; } // // END Retrieve Statets ... // // // START States Calculations ... // // // START OSC Calculations ... // // // END OSC Calculations ... // // // START XMA Calculations ... // // // END XMA Calculations ... // // // START Momentum Calculations ... // // // END Momentum Calculations ... // // // START RSI Calculations ... // // // END RSI Calculations ... // // // START PRICE Calculations ... // RefreshRates(); // double marketLow[]; double marketOpen[]; double marketHigh[]; double marketClose[]; // double marketUp[]; double marketDown[]; // ArrayResize( marketLow, marketLength ); ArrayResize( marketOpen, marketLength ); ArrayResize( marketHigh, marketLength ); ArrayResize( marketClose, marketLength ); // ArrayResize( marketUp, marketLength ); ArrayResize( marketDown, marketLength ); // index = 0; for (int i = bar_index; i < marketLength + bar_index; i++) { // marketLow[index] = iLow( _Symbol, _Period, i ); // marketOpen[index] = iOpen( _Symbol, _Period, i ); // marketHigh[index] = iHigh( _Symbol, _Period, i ); // marketClose[index] = iClose( _Symbol, _Period, i ); // // marketUp[i] = MathMax(marketOpen[i], marketClose[i]); marketUp[index] = marketHigh[i]; // // marketDown[i] = MathMin(marketOpen[i], marketClose[i]); marketDown[index] = marketLow[i]; // index++; } // // LONG Prices ... double longEntryPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK); double longClosePrice = SymbolInfoDouble(_Symbol, SYMBOL_BID); double longPriceGap = longClosePrice - longEntryPrice; // // SHORT Prices ... double shortEntryPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID); double shortClosePrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK); double shortPriceGap = shortEntryPrice - shortClosePrice; // if (startMarketTime == 0) { startMarketTime = barTime; } // int startBarIndex = iBarShift( _Symbol, _Period, startMarketTime ); // if (startBarIndex > bar_index + marketLength) { // startBarIndex = 0; startMarketTime = 0; } // bool isSharpBullishDetected = false; bool isShareBearishDetected = false; double sharpDetectionValue = sharpDetectMultiplier * _Point; if (startBarIndex > bar_index + 1) { // double marketStartHigh = iHigh( _Symbol, _Period, startBarIndex ); double marketStartLow = iLow( _Symbol, _Period, startBarIndex ); // double prevCandleOpen = iOpen( _Symbol, _Period, bar_index + 1 ); // double prevCandleHigh = iHigh( _Symbol, _Period, bar_index + 1 ); // double prevCandleClose = iClose( _Symbol, _Period, bar_index + 1 ); // double candleOpen = iOpen( _Symbol, _Period, bar_index ); // double prevCandleComparedPrice = MathMin(prevCandleOpen, prevCandleClose); isShareBearishDetected = prevCandleHigh < marketStartHigh && prevCandleComparedPrice < marketStartHigh && marketStartHigh - prevCandleComparedPrice >= sharpDetectionValue; // // // isSharpBullishDetected = // marketStartHigh - MathMin(prevCandleOpen, prevCandleClose) >= sharpDetectionValue; } // if ( isShareBearishDetected || isSharpBullishDetected ) { startBarIndex = 0; startMarketTime = 0; } // // // END PRICE Calculations ... // // // START Capturing Signal ... // // // START LONG Signals ... // // // NOTES: // when MC Fast is Over MC Slow, // All Long Trades must be down when Market Middle is above MCSlow ... // and must be paused when Market Middle is Going Under MCSlow ... double rewardMultiplier = 1; // // OSC ... bool oscHasLongSignal = false; if (useOSCSignalling) { // // // oscHasLongSignal = // true // && ( // oscStates[0].fastOSC < 0 // ) // ; } // // XMA ... bool xmaHasLongSignal = false; if (useXMASignalling) { // // // xmaHasLongSignal = // // // // Long Cycle Trend Up ... // xmaStates[0].lcFast > xmaStates[0].lcSlow // // Lowest Low Must be Higher than lcFast ... // && xmktStates[0].lowestLow > xmaStates[0].lcFast // // // // Medium Cycle in Up Trend ... // && xmaStates[0].mcFast > xmaStates[0].mcSlow // // // // and the Medium Cycle Distance must be at least 100 Point ... // && (xmaStates[0].mcFast - xmaStates[0].mcSlow) > (100 * _Point) // // // // then looking for parabolic sar cross down market middleage ... // && xmaStates[0].parabolicSAR < xmaStates[0].marketMiddleage // && !(xmaStates[1].parabolicSAR <= xmaStates[1].marketMiddleage) // // // && xmaStates[0].scFast > xmaStates[0].marketMiddleage // // // // in crossing time Parabolic SAR must be greater than mcFast ... // && xmaStates[0].parabolicSAR > xmaStates[0].mcFast // // // // in this conditions, entry price must below than highest high, in market ... // && longEntryPrice < xmktStates[0].highestHigh // ; } // bool xshpHasLongSignal = false; if (useXSHPSignalling) { // bool condition1 = // xmaStates[0].sc.fast > xmaStates[0].sc.slow && xmaStates[0].mc.fast > xmaStates[0].mc.slow && xmaStates[0].lc.fast > xmaStates[0].lc.slow // && MathAbs(xmaStates[0].mc.fast - xmaStates[0].mc.slow) > (20 * _Point) // && ( cciStates[0] > 0 || cciStates[0] > cciStates[1] ) // && !( longEntryPrice < xmaStates[0].lc.fast && longEntryPrice > xmaStates[0].lc.slow && ( ( longEntryPrice < xmaStates[0].sc.fast && marketHigh[1] < xmaStates[0].sc.fast ) || ( longEntryPrice < xmaStates[0].lc.fast && marketHigh[1] < xmaStates[0].lc.fast ) ) ) //&& longEntryPrice < marketHigh[0] ; // xshpHasLongSignal = // isShareBearishDetected // && (condition1) ; // // Check Reward Multiplier ... if (xshpHasLongSignal) { // double prevCandleLow = iLow( _Symbol, _Period, bar_index + 1 ); // double marketLowest = GetMarketLowestLow( bar_index, marketLength ); // if ( prevCandleLow == marketLowest || marketLowest < xmaStates[0].mc.slow || MathAbs(prevCandleLow - marketLowest) < (50 * _Point) ) { rewardMultiplier = 0.3; } } } // bool xmntmHasLongSignal = false; if (useXMNTMSignalling) { } // bool xrsiHasLongSignal = false; if (useXRSISignalling) { } // bool hasLongSignal = // // OSC Signals ... oscHasLongSignal || xmaHasLongSignal || xshpHasLongSignal || xmntmHasLongSignal || xrsiHasLongSignal ; // // END LONG Signals ... // // // START SHORT Signals ... // bool hasShortSignal = false; // // END SHORT Signals ... // // // Check Signal Exists regardless of Long or Short ... bool hasSignal = hasLongSignal || hasShortSignal; // // Prevent from Going forward if there is not a Signal ... if (!hasSignal) { // result.signal = signal; return result; } // totalSignals++; // // Define Price Related Variables ... // double price = 0; double priceGap = 0; double sl = 0; double risk; double reward; double tp = 0; double r2rRatio = riskToRewardRatio; // datetime time = iTime( _Symbol, _Period, bar_index ); // // Fill Signal Related Variables ... if (hasLongSignal) { // price = longEntryPrice; priceGap = longPriceGap; // // Setting Up SL Based on Last Market Lowest ... sl = GetMarketLowestLow( bar_index, marketLength ); // risk = price - sl; reward = risk * r2rRatio; reward = reward * rewardMultiplier; tp = price + reward; // // Check TP based on Spread ... if (tp < price + priceGap) { tp = tp + priceGap; } // sl = 0; // totalLongSignals++; } else if (hasShortSignal) { // totalShortSignals++; // price = shortEntryPrice; priceGap = shortPriceGap; // risk = sl - price; reward = risk * r2rRatio; reward = reward * rewardMultiplier; tp = price - reward; } // // Normalize Prices ... price = NormalizeDouble(price, _Digits); sl = NormalizeDouble(sl, _Digits); tp = NormalizeDouble(tp, _Digits); // // Generate Signal Structure ... signal.type = hasLongSignal ? X_LONG : X_SHORT; signal.tp = tp; signal.sl = sl; signal.time = time; signal.symbol = _Symbol; signal.entryPrice = price; signal.id = totalLongSignals; // // TODO: Fill Signal Comment By Sgnal Provider signal.comment = useOSCSignalling && oscHasLongSignal ? oscSignalIdentifier : useXMASignalling && xmaHasLongSignal ? xmaSignalIdentifier : useXSHPSignalling && xshpHasLongSignal ? xshpSignalIdentifier : useXMNTMSignalling && xmntmHasLongSignal ? xmntmSignalIdentifier : useXRSISignalling && xrsiHasLongSignal ? xrsiSignalIdentifier : "" ; // // END Capturing Signal ... // // // Fill Result ... result.hasSignal = hasSignal; result.signal = signal; result.type = signal.type; // // Return Result ... return result; } // // 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 ... // // Prevent from Checking, if there is no states available ... if (ArraySize(xmaStates) == 0) { return; } // // // closeLongTrades = // xmaStates[0].parabolicSAR > xmaStates[0].marketMiddleage // && !(xmaStates[1].parabolicSAR > xmaStates[1].marketMiddleage) // ; // // // closeLongTrades = // false // ; } // // Calculate Signals and Process Based on Exists Signals ... void ProcessSignals() { // XSignalRequest request = {}; request.type = X_NONE; request.hasSignal = false; // // Prevent Multiple Calculating on Same Bars ... isNewBar = IsNewBar(); if (isNewBar) { // countedBars++; } // 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_NONE ) { return; } // bool hasLongSignal = request.type == X_LONG; // // Check For Bot State ... if ( (hasLongSignal && !waitForLongSignals) || (!hasLongSignal && !waitForShortSignals) ) { 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) { // totalSignals--; if (hasLongSignal) { totalLongSignals--; } else { totalShortSignals--; } 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) { // // // string message = StringConcatenate( // "Trading Not Allowed ..." // ); // // // LogMessage(message); // SendAlert(message); return; } // bool isPositionOpened = TradeSignal( request.signal, signalPrefix, lotsPerTradePercent, // bullishSignalLabel, bullishSignalColor, bearishSignalLabel, bearishSignalColor, // // Signal Identifiers ... oscSignalIdentifier, xmaSignalIdentifier, xshpSignalIdentifier, xmntmSignalIdentifier, xrsiSignalIdentifier ); // 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.entryPrice, ", 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) { // waitForLongSignals = false; } } // // this comes from check state ... if (closeShortTrades) { // closeShortTrades = false; // bool isAllShortTradesClosed = CloseAllShortTrades(); if (isAllShortTradesClosed) { // waitForShortSignals = false; } } // bool hasClosedLongTimeTrade = CloseAllLongTimeTrades( closeAllOpenTradesAfterCandle ); // // Close Maximum DrawDown Passed Trades ... bool hasClosedInDrawDownLongTrade = CloseAllMaximumDrawDownPassedTrades( maxDrawdownPercentPerPTrade ); // if ( hasClosedLongTimeTrade || hasClosedInDrawDownLongTrade ) { // // waitForLongSignals = false; // waitForShortSignals = 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 ... //