//////////////////////////////////////////////////////////// // // SaherElm IT Center MQL5 XTEST Signal Provider Library // -------------------------------------------------------- // Name: XTESTSignalProvider // Description: XTEST based signal provider ... // // // Maintainer: // ------------ // Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) // ////////////////////////////////////////////////////// // // Global Properties ... #property library #property copyright "Copyright 2023, SaherElm IT Center" #property link "https://www.saherelm.ir" #property version "1.00" #property strict #define XTESTProviderName "XTEST" // // START Inputs ... // #include "x-saherelm.xtest.provider.inputs.lib.mq5"; // // END Inputs ... // // // Include Common Library ... #include "x-saherelm.common.lib.mq5" // // Include Logger Library ... #include "x-saherelm.log.lib.mq5" // // Include Alert Library ... #include "x-saherelm.alert.lib.mq5" // // Include Draw Library ... #include "x-saherelm.draw.lib.mq5" // // Include Class Libraries ... #include "x-saherelm.class.lib.mq5" // // START Global Definitions: Variables, Properties and etc ... // // XCTrade *xTESTTrader; XCAccountInfo xTESTAccountInfo; // #include "x-saherelm.xtest.provider.indicators.lib.mq5" // double xTESTDeposit = 0; double xTESTBalance = 0; double xTESTFreeMargin = 0; double xTESTRiskFreeTrades = 0; double xTESTMinRewardPerTrade = 0; double xTESTBalanceForOpenTrades = 0; double xTESTFreeMarginForOpenTrades = 0; double xTESTMinRewardPerSupportTrades = 0; double xTESTSupportTradesPriceDistance = 0; double xTESTMaxAllowedDrawDownPerTrades = 0; // // END Global Definitions: Variables, Properties and etc ... // // // START Provided Functions ... // // // Initial Library if required ... bool XTESTInitSignalProviderLibrary() { // bool result = false; // // Validate Inputs ... result = XTESTValidateInputs(); if (!result) { return result; } // // Init Indicators ... result = XTESTInitIndicators(); if (!result) { return result; } // // Calculate Account Deposit ... xTESTDeposit = xTESTAccountInfo.GetInitialBalance(); // // Calculate RiskFree Price Distance ... if (xTESTRiskFreeTradesInPips > 0 && xTESTRiskFreeRate > 0) { xTESTRiskFreeTrades = PipsToPrice(xTESTRiskFreeTradesInPips); } // // Calculate xTESTMinRewardPerTrade ... if (xTESTMinRewardPerTradeInPips > 0) { xTESTMinRewardPerTrade = PipsToPrice(xTESTMinRewardPerTradeInPips); } // // Calculate Min Balance for Trades ... if (xTESTBalanceFactorForOpenTrades > 0) { xTESTBalanceForOpenTrades = xTESTBalanceFactorForOpenTrades * xTESTDeposit; } // // Claculate Min Free Marging for Trades ... if (xTESTFreeMarginFactorForOpenTrades > 0) { xTESTFreeMarginForOpenTrades = xTESTFreeMarginFactorForOpenTrades * xTESTDeposit; } // // Calculate xTESTSupportTradesPriceDistance ... if (xTESTMaxAllowedSupportTrades > 0 && xTESTSupportTradesPriceDistanceInPips > 0 && xTESTMinRewardPerSupportTradesInPips > 0) { xTESTMinRewardPerSupportTrades = PipsToPrice(xTESTMinRewardPerSupportTradesInPips); xTESTSupportTradesPriceDistance = PipsToPrice(xTESTSupportTradesPriceDistanceInPips); } // // Calculate xTESTMaxAllowedDrawDownPerTrade ... if (xTESTMaxAllowedDrawDownPerTradesInPips > 0) { // xTESTMaxAllowedDrawDownPerTrades = PipsToPrice(xTESTMaxAllowedDrawDownPerTradesInPips); // LogMessage("Max Allowed DrawDown per Trade: " + (string)xTESTMaxAllowedDrawDownPerTrades); } // // Make XCTrader instance ... xTESTTrader = new XCTrade( XTESTProviderName, _Symbol, xTESTSlippage, xTESTMagicNumber, xTESTMaxAllowedTrades, xTESTMaxAllowedSupportTrades, xTESTMinRewardPerTradeInPips, xTESTSupportTradesPriceDistanceInPips, xTESTFreeMarginForOpenTrades, xTESTBalanceForOpenTrades); // result = true; // // Logging State ... XTESTIssueInitializationSucceedAlert(); // return result; } // // DeInitial Library if required ... void XTESTDeinitSignalProviderLibrary( const int reason) { // // Release Handlers ... XTESTReleaseIndicators(); // // Logging State ... XTESTIssueDeinitializationSucceedAlert(); } // // this is a Globally Function which do all of // checkings and positions handling ... void XTESTSignalProviderHandleTick() { // // Update account Balance ... xTESTBalance = xTESTAccountInfo.GetBalance(); xTESTFreeMargin = xTESTAccountInfo.GetFreeMargin(); // // Check Provider is Enable or Not ... if (!xTESTEnableProvider) { return; } // // Reading Indicator Buffers ... XTESTHandleReadingBuffers(); if (xTESTCalculatedBars < xTESTMaxLengthOfInputs) { return; } // // Handle Open Trades ... XTESTHandleOpenTrades(); // // Handle Close Trades ... XTESTHandleCloseTrades(); // // Handle Support Trades ... XTESTHandleSupportTrades(); } // // Handle Open Trades ... void XTESTHandleOpenTrades() { // // Check Can Trade ... bool canTrade = xTESTAllowLongTrades || xTESTAllowShortTrades; if (!canTrade) { return; } // // Check Max Open Trades ... int openPositions = xTESTTrader.Count(); int openTradeKinds = xTESTTrader.CountByKind( X_SIGNAL_UNKNOWN, X_KIND_TRADE); bool canOpenPositions = openTradeKinds < xTESTMaxAllowedTrades; if (!canOpenPositions) { return; } // // Check Signals Exists ... double longsForceVolume = 0; double shortsForceVolume = 0; bool hasLongSignal = XTESTCanOpenLongTrade(longsForceVolume); bool hasShortSignal = XTESTCanOpenShortTrade(shortsForceVolume); if (!hasLongSignal && !hasShortSignal) { return; } // // Open Long Trades ... if ( // hasLongSignal && xTESTAllowLongTrades) { // bool isOpened = XTESTOpenLongPosition(longsForceVolume); } // // Open Short Trades ... if ( // hasShortSignal && xTESTAllowShortTrades) { // bool isOpened = XTESTOpenShortPosition(shortsForceVolume); } } // // Handle Close Trades ... void XTESTHandleCloseTrades() { // // All Close Mechanism Handles Here ... // - Force Close; // - Partial Close; // - Risk Free Close; // - Virtual TP/SL Close; // // Force Close Long Trades ... bool canCloseLongTrades = XTESTCanCloseLongTrade(); if (xTESTAllowLongTrades && canCloseLongTrades) { // ENUM_X_SIGNAL_TYPE type = X_SIGNAL_LONG; // XSignal closed[]; xTESTTrader.ClosePositionsByType( type, closed); // bool isClosed = ArraySize(closed) > 0; if (isClosed) { XTESTIssueForceCloseTradesAlert(type); } } // // Force Close Short Trades ... bool canCloseShortTrades = XTESTCanCloseShortTrade(); if (xTESTAllowShortTrades && canCloseShortTrades) { // ENUM_X_SIGNAL_TYPE type = X_SIGNAL_SHORT; // XSignal closed[]; xTESTTrader.ClosePositionsByType( type, closed); // bool isClosed = ArraySize(closed) > 0; if (isClosed) { XTESTIssueForceCloseTradesAlert(type); } } // // Close Risk Free Trades ... bool canRiskFree = xTESTRiskFreeTradesInPips > 0 && xTESTRiskFreeTrades > 0 && xTESTRiskFreeRate > 0; if (canRiskFree) { XSignal riskFrees[]; xTESTTrader.RiskFreeSignals(riskFrees); bool isRiskFree = ArraySize(riskFrees) > 0; if (isRiskFree) { XTESTIssueRiskFreeTradesAlert(); } } // XTESTHandleCloseMaxDrawDownTrades(); // XTESTHandleCloseTooOldTrades(); } // // Handle Supported Trades ... void XTESTHandleSupportTrades() { // bool canDoTrade = xTESTMaxAllowedSupportTrades > 0 && xTESTMinRewardPerSupportTradesInPips > 0 && xTESTSupportTradesPriceDistanceInPips > 0; if (!canDoTrade) { return; } // XSignal supports[]; bool hasSupportTrade = XTESTOpenSupportTrade(supports); if (hasSupportTrade) { } } // // Open Long Position ... bool XTESTOpenLongPosition(double additionalVolumeMultiplier = 0) { // bool result = false; // // Calculate Required Data for Position ... double sl = 0; double tp = xTESTMinRewardPerTrade; double riskFree = xTESTRiskFreeTrades; double riskFreeRate = xTESTRiskFreeRate; double volume = XTESTCalculateVolume(additionalVolumeMultiplier); // XSignal signal = {}; signal = xTESTTrader.GenerateTradeSignal( X_SIGNAL_LONG, tp, sl, volume, riskFree, riskFreeRate); bool isValidSignal = IsValid( signal, xTESTMagicNumber); if (!isValidSignal) { return result; } // int error = -1; result = xTESTTrader.ExecuteSignal(signal, error); if (result) { XTESTIssueSignalExecutionAlert(signal); } // return result; } // // Open Short Position ... bool XTESTOpenShortPosition(double additionalVolumeMultiplier = 0) { // bool result = false; // // Calculate Required Data for Position ... double sl = 0; double tp = xTESTMinRewardPerTrade; double riskFree = xTESTRiskFreeTrades; double riskFreeRate = xTESTRiskFreeRate; double volume = XTESTCalculateVolume(additionalVolumeMultiplier); // XSignal signal = {}; signal = xTESTTrader.GenerateTradeSignal( X_SIGNAL_SHORT, tp, sl, volume, riskFree, riskFreeRate); bool isValidSignal = IsValid( signal, xTESTMagicNumber); if (!isValidSignal) { return result; } // int error = -1; result = xTESTTrader.ExecuteSignal(signal, error); if (result) { XTESTIssueSignalExecutionAlert(signal); } // return result; } // // Open a Support Signal ... bool XTESTOpenSupportTrade( XSignal &supports[] // Holds Result ... ) { // bool result = false; // // Check Can Trade ... result = xTESTAllowLongTrades || xTESTAllowShortTrades; if (!result) { return result; } // // Check Support Trades is Enable or not ... bool isSupportTradesEnabled = // xTESTMaxAllowedSupportTrades > 0 && xTESTMinRewardPerSupportTrades > 0 && xTESTSupportTradesPriceDistance > 0 // ; if (!isSupportTradesEnabled) { return result; } // // Recieve InDD Open Trades ... XSignal inDDTrades[]; xTESTTrader.GetInDrawDownTrades( xTESTSupportTradesPriceDistance, X_SIGNAL_UNKNOWN, X_KIND_TRADE, inDDTrades); int inDDTradesCount = ArraySize(inDDTrades); result = inDDTradesCount > 0; if (!result) { return result; } // // Check Signals Exists ... double longsForceVolume = 0; double shortsForceVolume = 0; bool hasLongSignal = XTESTCanOpenLongTrade(longsForceVolume); bool hasShortSignal = XTESTCanOpenShortTrade(shortsForceVolume); result = hasLongSignal || hasShortSignal; if (!result) { return result; } // // Loop Through In DrawDown Trades ... XSignal supportedSignals[]; for (int i = 0; i < inDDTradesCount; i++) { // // Retrieve Parent Signal ... XSignal parent = inDDTrades[i]; // // Check if Long Signal Happens ... if (hasLongSignal && parent.type == X_SIGNAL_LONG) { // // Generate Support Signal ... XSignal sSignal = GenerateSupportSignal( longsForceVolume, X_SIGNAL_LONG, parent); // // Validate it ... bool isValidSupport = IsValid(sSignal, xTESTMagicNumber); if (!isValidSupport) { continue; ; } // // Try To Execute Support Signal ... int error = 0; bool isExecuted = xTESTTrader.ExecuteSupportSignal( sSignal, error); if (isExecuted) { // if (!result) { result = true; } // Add( sSignal, supports); // XTESTIssueSignalExecutionAlert(sSignal); } // continue; } // // Check if Short Signal Happens ... if (hasShortSignal && parent.type == X_SIGNAL_SHORT) { // // Generate Support Signal ... XSignal sSignal = GenerateSupportSignal( shortsForceVolume, X_SIGNAL_SHORT, parent); // // Validate it ... bool isValidSupport = IsValid(sSignal, xTESTMagicNumber); if (!isValidSupport) { continue; ; } // // Try To Execute Support Signal ... int error = 0; bool isExecuted = xTESTTrader.ExecuteSupportSignal( sSignal, error); if (isExecuted) { // if (!result) { result = true; } // Add( sSignal, supports); // XTESTIssueSignalExecutionAlert(sSignal); } // continue; } } // return result; } // // Close All InDrawDown Trades ... void XTESTHandleCloseMaxDrawDownTrades() { // if (xTESTMaxAllowedDrawDownPerTrades > 0) { // XSignal closed[]; xTESTTrader.CloseInDrawDownTrades( xTESTMaxAllowedDrawDownPerTrades, closed); // int count = ArraySize(closed); if (count > 0) { XTESTIssueLongInDrawdownTradeClosed(); } } } // // Close All Too Old Trades ... void XTESTHandleCloseTooOldTrades() { // // in DrawDown Trades ... if (xTESTMaxInDrawDownTradeAge > 0) { // XSignal oldTrades[]; xTESTTrader.CloseLongTimeTrades( xTESTMaxInDrawDownTradeAge, _Period, oldTrades); // bool hasOldClosedTrades = ArraySize(oldTrades) > 0; if (hasOldClosedTrades) { // LogMessage("Old Trade Closed ..."); } } } // // END Provided Functions ... // // // START Private Functions ... // // // Calculating Volume for Tradings ... double XTESTCalculateVolume( double forceMultiplier = 0 // some times we get more than one signal at the same time, here we increase volume using this ... ) { // // Assign default Value ... double result = xTESTStaticVolume; // // we can count open trades and in draw down trades // then do check volume based on it for gridding ... XSignal openInProfitTrades[]; xTESTTrader.GetInProfitTrades( 0, X_SIGNAL_UNKNOWN, X_KIND_TRADE, openInProfitTrades); int openTrades = ArraySize(openInProfitTrades); // // Calculate Normalized Multiplier ... double mVolumeMultiplier = xTESTVolumeMultiplier <= 0 ? 1 : xTESTVolumeMultiplier; double multiplier = mVolumeMultiplier; multiplier = multiplier * openTrades; if (multiplier < 1) { multiplier = 1; } // double growRate = xTESTBalance / xTESTDeposit; if (growRate >= 1 && multiplier == 1) { // double growDiff = growRate - 1; if (growDiff < 1) { growRate = 1 + (growDiff * mVolumeMultiplier); } // multiplier = multiplier * growRate; } // result = multiplier * xTESTStaticVolume; // // Apply Force Multiplier ... if (forceMultiplier > 1) { result *= forceMultiplier; } // // Check Max Allowed Lottage ... double maxAllowedVolume = xTESTMaxSupportedVolumePerTradeInLots; if (growRate >= 4 * mVolumeMultiplier) { maxAllowedVolume *= mVolumeMultiplier; } // if ( maxAllowedVolume > 0 && result > maxAllowedVolume) { result = maxAllowedVolume; } // // Normalize Volume ... result = NormalizeVolume(result); // return result; } // // Calculate Signal TP and SL ... XTPSL XTESTCalculateTPSL( ENUM_X_SIGNAL_TYPE type // Position Type ) { // XTPSL result = {}; // // Validate Args ... if ( type != X_SIGNAL_LONG && type != X_SIGNAL_SHORT) { return result; } // bool isLong = type == X_SIGNAL_LONG; // double ask = GetAsk(); double bid = GetBid(); double spread = GetSpread(); double entry = isLong ? ask : bid; // // TODO: Find Risk .. double risk = 0; // // Calculate Reward ... double reward = PipsToPrice(xTESTMinRewardPerTradeInPips) + spread; // // Calculate TP and SL ... double tp = isLong ? entry + reward : entry - reward; double sl = 0; // result.type = type; result.tp = tp; result.sl = sl; result.entry = entry; // // TODO: Calculate R2R ... result.r2r = 0; // return result; } // // Generate Support Signal for Specific Trade ... XSignal GenerateSupportSignal( double forceVolumeMultiplier, // how many time increase volume based on signal providers ENUM_X_SIGNAL_TYPE type, // which type of support signal issued XSignal &parent // generate support signal for which Trade Kind Position ) { // XSignal result = {}; // // Validate Type ... bool isTypeValid = type == X_SIGNAL_LONG || type == X_SIGNAL_SHORT; if (!isTypeValid) { return result; } // // Validate Parent Signal ... bool isValidSignal = IsValid(parent, xTESTMagicNumber); if (!isValidSignal) { return result; } // // Validate Parent is Kind ... bool isKindValid = parent.kind == X_KIND_TRADE; if (!isKindValid) { return result; } // // Check Parent Ticket ... bool isValidTicket = parent.ticket > 0; if (!isValidTicket) { return result; } // // Validate DrawDown ... bool isInDD = parent.profit < 0; if (!isInDD) { return result; } // // Calculate What we Want ... // bool isLong = type == X_SIGNAL_LONG; // // Entry Price ... // double entry = GetEntry(parent.symbol, type); // // Required for Calculating RiskFree Level of Support Signals ... double riskFreeRate = 0; double riskFreePrice = 0; bool canRiskFree = xTESTRiskFreeRate > 0; // // TP ... double tp = MathAbs(parent.tp - parent.entry) / 2; // PriceToPips(MathAbs(parent.tp - parent.entry) / 2); if (tp <= xTESTMinRewardPerSupportTrades) { tp = xTESTMinRewardPerSupportTrades; } else if ( canRiskFree && tp > xTESTMinRewardPerSupportTrades) { // // Fill Risk Free Info ... riskFreeRate = xTESTRiskFreeRate; riskFreePrice = isLong ? xTESTMinRewardPerSupportTrades : xTESTMinRewardPerSupportTrades; } // // SL ... double sl = isLong ? 0 : 0; // // VOLUME ... int pOpenSupportCount = xTESTTrader.CountSupportedPositions(parent); double volume = parent.volume * forceVolumeMultiplier; // // Check and Normalize Volume based on MaxAllowed Volume ... if (xTESTMaxSupportedVolumePerTradeInLots > 0 && volume > xTESTMaxSupportedVolumePerTradeInLots) { volume = xTESTMaxSupportedVolumePerTradeInLots; } // // Normalize Volume ... volume = NormalizeVolume(volume); // // Generating Support Signal for Parent ... result = xTESTTrader.GenerateSupportSignal( type, tp, sl, volume, riskFreePrice, riskFreeRate, parent.ticket); // return result; } void XTESTIssueInitializationSucceedAlert() { // string message = "Initializion of (" + XTESTProviderName + " Provider" + " _ " + _Symbol + " _ " + EnumToString(_Period) + ") Succeeded ..."; XTESTIssueAlert(message); } void XTESTIssueDeinitializationSucceedAlert() { // string message = "De Initializion of (" + XTESTProviderName + " Provider" + ") Succeeded ..."; XTESTIssueAlert(message); } void XTESTIssueForceCloseTradesAlert(ENUM_X_SIGNAL_TYPE type) { // string typeStr = GetSignalType(type); if (StringLen(typeStr) == 0) { return; } // string message = "Force Close " + typeStr + " Trades ..."; XTESTIssueAlert(message); } void XTESTIssueMaxAllowedTradesReachedAlert() { // string message = "reached Max Allowed Same Time Trades ..."; XTESTIssueAlert(message); } void XTESTIssueMaxAllowedFreeMarginReachedAlert() { // string message = "reached FreeMarigin For Open Trades ..."; XTESTIssueAlert(message); } void XTESTIssueMinAllowedBalanceReachedAlert() { // string message = "doesn't have Minimum Balance For Open Trades ..."; XTESTIssueAlert(message); } void XTESTIssueSignalExecutionAlert( XSignal &signal // Executed Signal ) { // XTESTIssueAlert(signal); } void XTESTIssueSignalExecutionError(int error) { // string message = GetSignalExecutionError(error); if (StringLen(message) == 0) { return; } // XTESTIssueAlert(message); } void XTESTIssueRiskFreeTradesAlert() { // string message = "Make Some Trades Risk Free ..."; XTESTIssueAlert(message); } void XTESTIssueLongInProfitTradeClosed() { // string message = "Closed Long Time in Profit Trades ..."; XTESTIssueAlert(message); } void XTESTIssueLongInDrawdownTradeClosed() { // string message = "Closed Long Time in Profit Trades ..."; XTESTIssueAlert(message); } void XTESTIssueAlert(string message) { // if (xTESTEnableAlerts) { SendAlert(message); } else { LogMessage(message); } } void XTESTIssueAlert(XSignal &signal) { // string signalStr = xTESTTrader.ToString(signal); XTESTIssueAlert(signalStr); // // // if (xTESTEnableAlerts) // { // SendAlert(signal); // } // else // { // LogSignal(signal); // } } // // END Private Functions ... //