//////////////////////////////////////////////////////////// // // SaherElm IT Center MQL5 XTF Signal Provider Library // -------------------------------------------------------- // Name: XTFSignalProvider // Description: XTF 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 XTFProviderName "XTF" // // START Inputs ... // #include "x-saherelm.xtf.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 *xTFTrader; XCAccountInfo xTFAccountInfo; // #include "x-saherelm.xtf.provider.indicators.lib.mq5" // double xTFDeposit = 0; double xTFBalance = 0; double xTFFreeMargin = 0; double xTFRiskFreeTrades = 0; double xTFMinRewardPerTrade = 0; double xTFBalanceForOpenTrades = 0; double xTFFreeMarginForOpenTrades = 0; double xTFMinRewardPerSupportTrades = 0; double xTFSupportTradesPriceDistance = 0; double xTFMaxAllowedDrawDownPerTrades = 0; // // END Global Definitions: Variables, Properties and etc ... // // // START Provided Functions ... // // // Initial Library if required ... bool XTFInitSignalProviderLibrary() { // bool result = false; // // Validate Inputs ... result = XTFValidateInputs(); if (!result) { return result; } // // Init Indicators ... result = XTFInitIndicators(); if (!result) { return result; } // // Calculate Account Deposit ... xTFDeposit = xTFAccountInfo.GetInitialBalance(); // // Calculate RiskFree Price Distance ... if (xTFRiskFreeTradesInPips > 0 && xTFRiskFreeRate > 0) { xTFRiskFreeTrades = PipsToPrice(xTFRiskFreeTradesInPips); } // // Calculate xTFMinRewardPerTrade ... if (xTFMinRewardPerTradeInPips > 0) { xTFMinRewardPerTrade = PipsToPrice(xTFMinRewardPerTradeInPips); } // // Calculate Min Balance for Trades ... if (xTFBalanceFactorForOpenTrades > 0) { xTFBalanceForOpenTrades = xTFBalanceFactorForOpenTrades * xTFDeposit; } // // Claculate Min Free Marging for Trades ... if (xTFFreeMarginFactorForOpenTrades > 0) { xTFFreeMarginForOpenTrades = xTFFreeMarginFactorForOpenTrades * xTFDeposit; } // // Calculate xTFSupportTradesPriceDistance ... if (xTFMaxAllowedSupportTrades > 0 && xTFSupportTradesPriceDistanceInPips > 0 && xTFMinRewardPerSupportTradesInPips > 0) { xTFMinRewardPerSupportTrades = PipsToPrice(xTFMinRewardPerSupportTradesInPips); xTFSupportTradesPriceDistance = PipsToPrice(xTFSupportTradesPriceDistanceInPips); } // // Calculate xTFMaxAllowedDrawDownPerTrade ... if (xTFMaxAllowedDrawDownPerTradesInPips > 0) { // xTFMaxAllowedDrawDownPerTrades = PipsToPrice(xTFMaxAllowedDrawDownPerTradesInPips); // LogMessage("Max Allowed DrawDown per Trade: " + (string)xTFMaxAllowedDrawDownPerTrades); } // // Make XCTrader instance ... xTFTrader = new XCTrade( XTFProviderName, _Symbol, xTFSlippage, xTFMagicNumber, xTFMaxAllowedTrades, xTFMaxAllowedSupportTrades, xTFMinRewardPerTradeInPips, xTFSupportTradesPriceDistanceInPips, xTFFreeMarginForOpenTrades, xTFBalanceForOpenTrades); // result = true; // // Logging State ... XTFIssueInitializationSucceedAlert(); // return result; } // // DeInitial Library if required ... void XTFDeinitSignalProviderLibrary( const int reason) { // // Release Handlers ... XTFReleaseIndicators(); // // Logging State ... XTFIssueDeinitializationSucceedAlert(); } // // this is a Globally Function which do all of // checkings and positions handling ... void XTFSignalProviderHandleTick() { // // Update account Balance ... xTFBalance = xTFAccountInfo.GetBalance(); xTFFreeMargin = xTFAccountInfo.GetFreeMargin(); // // Check Provider is Enable or Not ... if (!xTFEnableProvider) { return; } // // Reading Indicator Buffers ... XTFHandleReadingBuffers(); if (xTFCalculatedBars < xTFMaxLengthOfInputs) { return; } // // Handle Open Trades ... XTFHandleOpenTrades(); // // Handle Close Trades ... XTFHandleCloseTrades(); // // Handle Support Trades ... XTFHandleSupportTrades(); } // // Handle Open Trades ... void XTFHandleOpenTrades() { // // Check Can Trade ... bool canTrade = xTFAllowLongTrades || xTFAllowShortTrades; if (!canTrade) { return; } // // Check Max Open Trades ... int openPositions = xTFTrader.Count(); int openTradeKinds = xTFTrader.CountByKind( X_SIGNAL_UNKNOWN, X_KIND_TRADE); bool canOpenPositions = openTradeKinds < xTFMaxAllowedTrades; if (!canOpenPositions) { return; } // // Check Signals Exists ... XTF_SIGNAL longInfo = {}; double longsForceVolume = 0; XTF_SIGNAL shortInfo = {}; double shortsForceVolume = 0; bool hasLongSignal = XTFCanOpenLongTrade( longsForceVolume, longInfo); bool hasShortSignal = XTFCanOpenShortTrade( shortsForceVolume, shortInfo); if (!hasLongSignal && !hasShortSignal) { return; } // // Open Long Trades ... if ( // hasLongSignal && xTFAllowLongTrades) { // bool isOpened = XTFOpenLongPosition( longInfo, longsForceVolume); } // // Open Short Trades ... if ( // hasShortSignal && xTFAllowShortTrades) { // bool isOpened = XTFOpenShortPosition( shortInfo, shortsForceVolume); } } // // Handle Close Trades ... void XTFHandleCloseTrades() { // // All Close Mechanism Handles Here ... // - Force Close; // - Partial Close; // - Risk Free Close; // - Virtual TP/SL Close; // // Force Close Long Trades ... bool canCloseLongTrades = XTFCanCloseLongTrade(); if (xTFAllowLongTrades && canCloseLongTrades) { // ENUM_X_SIGNAL_TYPE type = X_SIGNAL_LONG; // XSignal closed[]; xTFTrader.ClosePositionsByType( type, closed); // bool isClosed = ArraySize(closed) > 0; if (isClosed) { XTFIssueForceCloseTradesAlert(type); } } // // Force Close Short Trades ... bool canCloseShortTrades = XTFCanCloseShortTrade(); if (xTFAllowShortTrades && canCloseShortTrades) { // ENUM_X_SIGNAL_TYPE type = X_SIGNAL_SHORT; // XSignal closed[]; xTFTrader.ClosePositionsByType( type, closed); // bool isClosed = ArraySize(closed) > 0; if (isClosed) { XTFIssueForceCloseTradesAlert(type); } } // // Close Risk Free Trades ... bool canRiskFree = xTFRiskFreeTradesInPips > 0 && xTFRiskFreeTrades > 0 && xTFRiskFreeRate > 0; if (canRiskFree) { XSignal riskFrees[]; xTFTrader.RiskFreeSignals(riskFrees); bool isRiskFree = ArraySize(riskFrees) > 0; if (isRiskFree) { XTFIssueRiskFreeTradesAlert(); } } // XTFHandleCloseMaxDrawDownTrades(); // XTFHandleCloseTooOldTrades(); } // // Handle Supported Trades ... void XTFHandleSupportTrades() { // bool canDoTrade = xTFMaxAllowedSupportTrades > 0 && xTFMinRewardPerSupportTradesInPips > 0 && xTFSupportTradesPriceDistanceInPips > 0; if (!canDoTrade) { return; } // XSignal supports[]; bool hasSupportTrade = XTFOpenSupportTrade(supports); if (hasSupportTrade) { } } // // Open Long Position ... bool XTFOpenLongPosition( XTF_SIGNAL &info, // Retrieve Signal Additional Info on this Object double additionalVolumeMultiplier = 0) { // bool result = false; // // Calculate Required Data for Position ... double sl = info.sl > 0 ? info.sl : 0; double tp = info.tp > 0 ? info.tp : xTFMinRewardPerTrade; double riskFree = info.tp > 0 && info.riskFree > 0 ? info.riskFree : info.tp > 0 ? 0 : xTFRiskFreeTrades; double riskFreeRate = xTFRiskFreeRate; double volume = XTFCalculateVolume(additionalVolumeMultiplier); // XSignal signal = {}; signal = xTFTrader.GenerateTradeSignal( X_SIGNAL_LONG, tp, sl, volume, riskFree, riskFreeRate); bool isValidSignal = IsValid( signal, xTFMagicNumber); if (!isValidSignal) { return result; } // int error = -1; result = xTFTrader.ExecuteSignal(signal, error); if (result) { XTFIssueSignalExecutionAlert(signal); } // return result; } // // Open Short Position ... bool XTFOpenShortPosition( XTF_SIGNAL &info, // Retrieve Signal Additional Info on this Object double additionalVolumeMultiplier = 0) { // bool result = false; // // Calculate Required Data for Position ... double sl = info.sl > 0 ? info.sl : 0; double tp = info.tp > 0 ? info.tp : xTFMinRewardPerTrade; double riskFree = info.tp > 0 && info.riskFree > 0 ? info.riskFree : info.tp > 0 ? 0 : xTFRiskFreeTrades; double riskFreeRate = xTFRiskFreeRate; double volume = XTFCalculateVolume(additionalVolumeMultiplier); // XSignal signal = {}; signal = xTFTrader.GenerateTradeSignal( X_SIGNAL_SHORT, tp, sl, volume, riskFree, riskFreeRate); bool isValidSignal = IsValid( signal, xTFMagicNumber); if (!isValidSignal) { return result; } // int error = -1; result = xTFTrader.ExecuteSignal(signal, error); if (result) { XTFIssueSignalExecutionAlert(signal); } // return result; } // // Open a Support Signal ... bool XTFOpenSupportTrade( XSignal &supports[] // Holds Result ... ) { // bool result = false; // // Check Can Trade ... result = xTFAllowLongTrades || xTFAllowShortTrades; if (!result) { return result; } // // Check Support Trades is Enable or not ... bool isSupportTradesEnabled = // xTFMaxAllowedSupportTrades > 0 && xTFMinRewardPerSupportTrades > 0 && xTFSupportTradesPriceDistance > 0 // ; if (!isSupportTradesEnabled) { return result; } // // Recieve InDD Open Trades ... XSignal inDDTrades[]; xTFTrader.GetInDrawDownTrades( xTFSupportTradesPriceDistance, X_SIGNAL_UNKNOWN, X_KIND_TRADE, inDDTrades); int inDDTradesCount = ArraySize(inDDTrades); result = inDDTradesCount > 0; if (!result) { return result; } // // Check Signals Exists ... double longsForceVolume = 0; XTF_SIGNAL longInfo = {}; double shortsForceVolume = 0; XTF_SIGNAL shortInfo = {}; bool hasLongSignal = XTFCanOpenLongTrade( longsForceVolume, longInfo); bool hasShortSignal = XTFCanOpenShortTrade( shortsForceVolume, shortInfo); 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 = XTFGenerateSupportSignal( longsForceVolume, X_SIGNAL_LONG, parent); // // Validate it ... bool isValidSupport = IsValid(sSignal, xTFMagicNumber); if (!isValidSupport) { continue; ; } // // Try To Execute Support Signal ... int error = 0; bool isExecuted = xTFTrader.ExecuteSupportSignal( sSignal, error); if (isExecuted) { // if (!result) { result = true; } // Add( sSignal, supports); // XTFIssueSignalExecutionAlert(sSignal); } // continue; } // // Check if Short Signal Happens ... if (hasShortSignal && parent.type == X_SIGNAL_SHORT) { // // Generate Support Signal ... XSignal sSignal = XTFGenerateSupportSignal( shortsForceVolume, X_SIGNAL_SHORT, parent); // // Validate it ... bool isValidSupport = IsValid(sSignal, xTFMagicNumber); if (!isValidSupport) { continue; ; } // // Try To Execute Support Signal ... int error = 0; bool isExecuted = xTFTrader.ExecuteSupportSignal( sSignal, error); if (isExecuted) { // if (!result) { result = true; } // Add( sSignal, supports); // XTFIssueSignalExecutionAlert(sSignal); } // continue; } } // return result; } // // Close All InDrawDown Trades ... void XTFHandleCloseMaxDrawDownTrades() { // if (xTFMaxAllowedDrawDownPerTrades > 0) { // XSignal closed[]; xTFTrader.CloseInDrawDownTrades( xTFMaxAllowedDrawDownPerTrades, closed); // int count = ArraySize(closed); if (count > 0) { XTFIssueLongInDrawdownTradeClosed(); } } } // // Close All Too Old Trades ... void XTFHandleCloseTooOldTrades() { // // in DrawDown Trades ... if (xTFMaxInDrawDownTradeAge > 0) { // XSignal oldTrades[]; xTFTrader.CloseLongTimeTrades( xTFMaxInDrawDownTradeAge, _Period, oldTrades); // bool hasOldClosedTrades = ArraySize(oldTrades) > 0; if (hasOldClosedTrades) { // LogMessage("Old Trade Closed ..."); } } } // // END Provided Functions ... // // // START Private Functions ... // // // Calculating Volume for Tradings ... double XTFCalculateVolume( 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 = xTFStaticVolume; // // we can count open trades and in draw down trades // then do check volume based on it for gridding ... XSignal openInProfitTrades[]; xTFTrader.GetInProfitTrades( 0, X_SIGNAL_UNKNOWN, X_KIND_TRADE, openInProfitTrades); int openTrades = ArraySize(openInProfitTrades); // // Calculate Normalized Multiplier ... double mVolumeMultiplier = xTFVolumeMultiplier <= 0 ? 1 : xTFVolumeMultiplier; double multiplier = mVolumeMultiplier; multiplier = multiplier * openTrades; if (multiplier < 1) { multiplier = 1; } // double growRate = xTFBalance / xTFDeposit; if (growRate >= 1 && multiplier == 1) { // double growDiff = growRate - 1; if (growDiff < 1) { growRate = 1 + (growDiff * mVolumeMultiplier); } // multiplier = multiplier * growRate; } // result = multiplier * xTFStaticVolume; // // Apply Force Multiplier ... if (forceMultiplier > 1) { result *= forceMultiplier; } // // Check Max Allowed Lottage ... double maxAllowedVolume = xTFMaxSupportedVolumePerTradeInLots; 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 XTFCalculateTPSL( 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(xTFMinRewardPerTradeInPips) + 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 XTFGenerateSupportSignal( 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, xTFMagicNumber); 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 = xTFRiskFreeRate > 0; // // TP ... double tp = MathAbs(parent.tp - parent.entry) / 2; // PriceToPips(MathAbs(parent.tp - parent.entry) / 2); if (tp <= xTFMinRewardPerSupportTrades) { tp = xTFMinRewardPerSupportTrades; } else if ( canRiskFree && tp > xTFMinRewardPerSupportTrades) { // // Fill Risk Free Info ... riskFreeRate = xTFRiskFreeRate; riskFreePrice = isLong ? xTFMinRewardPerSupportTrades : xTFMinRewardPerSupportTrades; } // // SL ... double sl = isLong ? 0 : 0; // // VOLUME ... int pOpenSupportCount = xTFTrader.CountSupportedPositions(parent); double volume = parent.volume * forceVolumeMultiplier; // // Check and Normalize Volume based on MaxAllowed Volume ... if (xTFMaxSupportedVolumePerTradeInLots > 0 && volume > xTFMaxSupportedVolumePerTradeInLots) { volume = xTFMaxSupportedVolumePerTradeInLots; } // // Normalize Volume ... volume = NormalizeVolume(volume); // // Generating Support Signal for Parent ... result = xTFTrader.GenerateSupportSignal( type, tp, sl, volume, riskFreePrice, riskFreeRate, parent.ticket); // // TODO: Fix this ... result.tp = parent.tp; result.sl = parent.sl; result.riskFree = 0; result.riskFreeRate = 0; // return result; } void XTFIssueInitializationSucceedAlert() { // string message = "Initializion of (" + XTFProviderName + " Provider" + " _ " + _Symbol + " _ " + EnumToString(_Period) + ") Succeeded ..."; XTFIssueAlert(message); } void XTFIssueDeinitializationSucceedAlert() { // string message = "De Initializion of (" + XTFProviderName + " Provider" + ") Succeeded ..."; XTFIssueAlert(message); } void XTFIssueForceCloseTradesAlert(ENUM_X_SIGNAL_TYPE type) { // string typeStr = GetSignalType(type); if (StringLen(typeStr) == 0) { return; } // string message = "Force Close " + typeStr + " Trades ..."; XTFIssueAlert(message); } void XTFIssueMaxAllowedTradesReachedAlert() { // string message = "reached Max Allowed Same Time Trades ..."; XTFIssueAlert(message); } void XTFIssueMaxAllowedFreeMarginReachedAlert() { // string message = "reached FreeMarigin For Open Trades ..."; XTFIssueAlert(message); } void XTFIssueMinAllowedBalanceReachedAlert() { // string message = "doesn't have Minimum Balance For Open Trades ..."; XTFIssueAlert(message); } void XTFIssueSignalExecutionAlert( XSignal &signal // Executed Signal ) { // XTFIssueAlert(signal); } void XTFIssueSignalExecutionError(int error) { // string message = GetSignalExecutionError(error); if (StringLen(message) == 0) { return; } // XTFIssueAlert(message); } void XTFIssueRiskFreeTradesAlert() { // string message = "Make Some Trades Risk Free ..."; XTFIssueAlert(message); } void XTFIssueLongInProfitTradeClosed() { // string message = "Closed Long Time in Profit Trades ..."; XTFIssueAlert(message); } void XTFIssueLongInDrawdownTradeClosed() { // string message = "Closed Long Time in Profit Trades ..."; XTFIssueAlert(message); } void XTFIssueAlert(string message) { // if (xTFEnableAlerts) { SendAlert(message); } else { LogMessage(message); } } void XTFIssueAlert(XSignal &signal) { // string signalStr = xTFTrader.ToString(signal); XTFIssueAlert(signalStr); // // // if (xTFEnableAlerts) // { // SendAlert(signal); // } // else // { // LogSignal(signal); // } } // // END Private Functions ... //