//////////////////////////////////////////////////////////// // // SaherElm IT Center MQL5 XOBD Signal Provider Library // -------------------------------------------------------- // Name: XOBDSignalProvider // Description: XOBD 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 XOBDProviderName "XOBD" // // START Inputs ... // #include "x-saherelm.xobd.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 *xOBDTrader; XCAccountInfo xOBDAccountInfo; // #include "x-saherelm.xobd.provider.indicators.lib.mq5" // double xOBDDeposit = 0; double xOBDBalance = 0; double xOBDFreeMargin = 0; double xOBDFreeMarginForOpenTrades = 0; double xOBDBalanceForOpenTrades = 0; // // END Global Definitions: Variables, Properties and etc ... // // // START Provided Functions ... // // // Initial Library if required ... bool XOBDInitSignalProviderLibrary() { // bool result = false; // // Validate Inputs ... result = XOBDValidateInputs(); if (!result) { return result; } // // Init Indicators ... result = XOBDInitIndicators(); if (!result) { return result; } // // Calculate Account Deposit ... xOBDDeposit = xOBDAccountInfo.GetInitialBalance(); // // Calculate Min Balance for Trades ... if (xOBDBalanceFactorForOpenTrades > 0) { xOBDBalanceForOpenTrades = xOBDBalanceFactorForOpenTrades * xOBDDeposit; } // // Claculate Min Free Marging for Trades ... if (xOBDFreeMarginFactorForOpenTrades > 0) { xOBDFreeMarginForOpenTrades = xOBDFreeMarginFactorForOpenTrades * xOBDDeposit; } // // Make XCTrader instance ... xOBDTrader = new XCTrade( _Symbol, xOBDSlippage, xOBDMagicNumber); // result = true; // // Logging State ... XOBDIssueInitializationSucceedAlert(); // return result; } // // DeInitial Library if required ... void XOBDDeinitSignalProviderLibrary( const int reason) { // // Release Handlers ... XOBDReleaseIndicators(); // // Logging State ... XOBDIssueDeinitializationSucceedAlert(); } // // this is a Globally Function which do all of // checkings and positions handling ... void XOBDSignalProviderHandleTick() { // // Update account Balance ... xOBDBalance = xOBDAccountInfo.GetBalance(); xOBDFreeMargin = xOBDAccountInfo.GetFreeMargin(); // // Check Provider is Enable or Not ... if (!xOBDEnableProvider) { return; } // // Reading Indicator Buffers ... XOBDHandleReadingBuffers(); if (xOBDCalculatedBars < xOBDMaxLengthOfInputs) { return; } // // Handle Open Trades ... XOBDHandleOpenTrades(); // // Handle Close Trades ... XOBDHandleCloseTrades(); } // // Handle Open Trades ... void XOBDHandleOpenTrades() { // // Check Can Trade ... bool canTrade = xOBDAllowLongTrades || xOBDAllowShortTrades; if (!canTrade) { return; } // // First Check Signal Exists or NOt ... bool xOBDHasLongSignal = XOBDCanOpenLongTrade(); bool xOBDHasShortSignal = XOBDCanOpenShortTrade(); if (!xOBDHasLongSignal && !xOBDHasShortSignal) { return; } // // Count Max Open Trades ... if (xOBDMaxAllowedTrades > 0) { // int count = xOBDTrader.Count(); bool canOpenTrade = count < xOBDMaxAllowedTrades; if (!canOpenTrade) { // XOBDIssueMaxAllowedTradesReachedAlert(); // return; } } // // Check Free Margin ... if (xOBDFreeMargin <= xOBDFreeMarginForOpenTrades) { // XOBDIssueMaxAllowedFreeMarginReachedAlert(); // return; } // // Check Account Balance ... if (xOBDBalance <= xOBDBalanceForOpenTrades) { // XOBDIssueMinAllowedBalanceReachedAlert(); // return; } // // Primary Long Trade ... if ( xOBDHasLongSignal && xOBDAllowLongTrades) { // bool isLongSignalExecuted = XOBDOpenLongPosition(); if (isLongSignalExecuted) { } } // // Primary Short Trade ... if ( xOBDHasShortSignal && xOBDAllowShortTrades) { // bool isShortSignalExecuted = XOBDOpenShortPosition(); if (isShortSignalExecuted) { } } } // // Handle Close Trades ... void XOBDHandleCloseTrades() { // // Handle Long/Buy Close ... if (xOBDTrader.CountLongs() > 0 && XOBDCanCloseLongTrade()) { // XSignal closed[]; xOBDTrader.CloseLongPositions(closed); bool hasClosed = ArraySize(closed) > 0; if (hasClosed) { XOBDIssueForceCloseTradesAlert(X_SIGNAL_LONG); } } // // Handle Short/Sell Close ... if (xOBDTrader.CountShorts() > 0 && XOBDCanCloseShortTrade()) { // XSignal closed[]; xOBDTrader.CloseShortPositions(closed); bool hasClosed = ArraySize(closed) > 0; if (hasClosed) { XOBDIssueForceCloseTradesAlert(X_SIGNAL_SHORT); } } // // Handle Close In Profit Teades ... if (xOBDMaxInProfitTradeAge > 0) { // XSignal closed[]; XSignal longTimeTrades[]; xOBDTrader.GetLongTimeTrades( xOBDMaxInProfitTradeAge, _Period, longTimeTrades); int count = ArraySize(longTimeTrades); if (count > 0) { // // Loop ... for (int i = 0; i < count; i++) { // XSignal trade = longTimeTrades[i]; if (trade.profit < 0) { continue; } // bool isClosed = xOBDTrader.Close(trade.ticket); if (isClosed) { Add( trade, closed); } } } // if (ArraySize(closed) > 0) { XOBDIssueLongInProfitTradeClosed(); } } // // Handle Close In DrawDown Trades ... if (xOBDMaxInDrawDownTradeAge > 0) { // XSignal closed[]; XSignal longTimeTrades[]; xOBDTrader.GetLongTimeTrades( xOBDMaxInDrawDownTradeAge, _Period, longTimeTrades); int count = ArraySize(longTimeTrades); if (count > 0) { // // Loop ... for (int i = 0; i < count; i++) { // XSignal trade = longTimeTrades[i]; if (trade.profit > 0) { continue; } // // Open Grid Trades ... XOBDOpenSuppurtTrade(trade); // // // bool isClosed = xOBDTrader.Close(trade.ticket); // if (isClosed) // { // // // Add( // trade, // closed); // } } } // if (ArraySize(closed) > 0) { XOBDIssueLongInDrawdownTradeClosed(); } } } // // Open Long Position ... bool XOBDOpenLongPosition() { // bool result = false; // // Generate Position Signal and Validate it ... XSignal position = XOBDGeneratePositionSignal(X_SIGNAL_LONG); if (!IsValid( position, xOBDMagicNumber)) { return result; } // // Try to Open Position ... result = xOBDTrader.ExecuteSignal(position); if (result) { XOBDIssueSignalExecutionAlert(position); } // return result; } // // Open Short Position ... bool XOBDOpenShortPosition() { // bool result = false; // // Generate Position Signal and Validate it ... XSignal position = XOBDGeneratePositionSignal(X_SIGNAL_SHORT); if (!IsValid( position, xOBDMagicNumber)) { return result; } // // Try to Open Position ... result = xOBDTrader.ExecuteSignal(position); if (result) { XOBDIssueSignalExecutionAlert(position); } // return result; } // // Open a Support Signal ... bool XOBDOpenSuppurtTrade( XSignal &signal // Parent Signal ) { // bool result = false; // if (!xOBDEnableSupportTrades) { return result; } // // Validate Signal ... if (!IsValid(signal, xOBDMagicNumber)) { return result; } // // Market Conditions ... bool hasLongSignal = XOBDCanOpenLongTrade(); bool hasShortSignal = XOBDCanOpenShortTrade(); // ENUM_X_SIGNAL_TYPE type = X_SIGNAL_UNKNOWN; // // Detect Support Signal Direction ... XSignal support = {}; switch (signal.type) { // case X_SIGNAL_LONG: // // First Check Long Support ... // Then Look for Short Support ... if (hasLongSignal) { type = X_SIGNAL_LONG; } else if (hasShortSignal) { type = X_SIGNAL_SHORT; } else { type = signal.type; } break; // case X_SIGNAL_SHORT: // First Check Short Support ... // Then Look for Long Support ... if (hasShortSignal) { type = X_SIGNAL_SHORT; } else if (hasLongSignal) { type = X_SIGNAL_LONG; } else { type = signal.type; } break; } // if (type == X_SIGNAL_UNKNOWN) { return result; } bool isLong = type == X_SIGNAL_LONG; // // Find Common Used ... double entry = GetEntry(type); double volumeMultiplier = 2; if (xOBDVolumeMultiplier > 2) { volumeMultiplier = xOBDVolumeMultiplier; } // // Check Signal is Support ot nor ... int titlePosition = StringFind( signal.comment, "Support"); bool isSupport = titlePosition >= 0; double priceDistance = MathAbs(signal.entry - entry); // if (isSupport || priceDistance < PipsToPrice(5)) { return result; } // datetime time = iTime( _Symbol, _Period, 0); double volume = NormalizeVolume(isSupport ? signal.volume : signal.volume * volumeMultiplier); string comment = "Support_" + GetSignalType(type) + "_For_" + (string)signal.ticket + "_" + (string)volume + "_" + (string)time; // XTPSL tpSL = XOBDCalculateTPSL(type); if (!IsValid(tpSL)) { return result; } // // Calculate reward of signal ... double reward = MathAbs(signal.entry - signal.tp) / 2; double tp = tpSL.sl; // isLong ? entry + reward : entry - reward; double sl = tpSL.sl; // // Filling Support Signal ... support.tp = tp; support.sl = sl; support.type = type; support.time = time; support.entry = entry; support.volume = volume; support.symbol = _Symbol; support.comment = comment; support.magicNumber = xOBDMagicNumber; // // Validate Generated Support ... if (!IsValid(support, xOBDMagicNumber)) { return result; } // result = xOBDTrader.ExecuteSignal(support); if (result) { XOBDIssueSignalExecutionAlert(support); } // return result; } // // Generate Specific type of Signals for Trading ... XSignal XOBDGeneratePositionSignal( ENUM_X_SIGNAL_TYPE type // direction of position ) { // XSignal result = {}; // if (type != X_SIGNAL_LONG && type != X_SIGNAL_SHORT) { return result; } // double ask = GetAsk(); double bid = GetBid(); double entry = GetEntry(type); // double volume = XOBDCalculateVolume(); // datetime time = iTime( _Symbol, _Period, 0); // string typeString = GetSignalType(type); string comment = XOBDProviderName + "_" + typeString + "_" + (string)volume + "_" + (string)time; // XTPSL tpSL = XOBDCalculateTPSL(type); if (IsValid(tpSL)) { // // Apply TP ... if (tpSL.tp > 0) { result.tp = tpSL.tp; } // // Apply SL ... if (tpSL.sl > 0) { result.sl = tpSL.sl; } } // result.type = type; result.time = time; result.entry = entry; result.volume = volume; result.symbol = _Symbol; result.comment = comment; result.magicNumber = xOBDMagicNumber; // return result; } // // END Provided Functions ... // // // START Private Functions ... // // // Calculating Volume for Tradings ... double XOBDCalculateVolume() { // // Assign default Value ... double result = xOBDStaticVolume; // // we can count open trades and in draw down trades // then do check volume based on it for gridding ... int openTrades = xOBDTrader.Count(); if (openTrades == 0) { openTrades = 1; } // // Calculate Normalized Multiplier ... double multiplier = xOBDVolumeMultiplier <= 0 ? 1 : xOBDVolumeMultiplier; // result = multiplier * openTrades * xOBDStaticVolume; // // Normalize Volume ... result = NormalizeVolume(result); // return result; } // // Calculate Signal TP and SL ... XTPSL XOBDCalculateTPSL( 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(xOBDMinRewardPerTradeInPips) + 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; } void XOBDIssueInitializationSucceedAlert() { // string message = "Initializion of (" + XOBDProviderName + " Provider" + " _ " + _Symbol + " _ " + EnumToString(_Period) + ") Succeeded ..."; XOBDIssueAlert(message); } void XOBDIssueDeinitializationSucceedAlert() { // string message = "De Initializion of (" + XOBDProviderName + " Provider" + ") Succeeded ..."; XOBDIssueAlert(message); } void XOBDIssueForceCloseTradesAlert(ENUM_X_SIGNAL_TYPE type) { // string typeStr = GetSignalType(type); if (StringLen(typeStr) == 0) { return; } // string message = "Force Close " + typeStr + " Trades ..."; XOBDIssueAlert(message); } void XOBDIssueMaxAllowedTradesReachedAlert() { // string message = "reached Max Allowed Same Time Trades ..."; XOBDIssueAlert(message); } void XOBDIssueMaxAllowedFreeMarginReachedAlert() { // string message = "reached FreeMarigin For Open Trades ..."; XOBDIssueAlert(message); } void XOBDIssueMinAllowedBalanceReachedAlert() { // string message = "doesn't have Minimum Balance For Open Trades ..."; XOBDIssueAlert(message); } void XOBDIssueSignalExecutionAlert( XSignal &signal // Executed Signal ) { // XOBDIssueAlert(signal); } void XOBDIssueLongInProfitTradeClosed() { // string message = "Closed Long Time in Profit Trades ..."; XOBDIssueAlert(message); } void XOBDIssueLongInDrawdownTradeClosed() { // string message = "Closed Long Time in Profit Trades ..."; XOBDIssueAlert(message); } void XOBDIssueAlert(string message) { // if (xOBDEnableAlerts) { SendAlert(message); } else { LogMessage(message); } } void XOBDIssueAlert(XSignal &signal) { // if (xOBDEnableAlerts) { SendAlert(signal); } else { LogSignal(signal); } } // // END Private Functions ... //