/////////////////////////////////////////////////////// // // SaherElm IT Center MQL5 Class Library // -------------------------------------- // Name: XClass // Description: provides all classes for use ... // // // 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 // #include #include #include #include #include #include "x-saherelm.models.lib.mq5" #include "x-saherelm.common.lib.mq5" // // START Model Definitions ... // // // END Model Definitions ... // // // XSaherElm Account Info Class ... class XCAccountInfo { // // Public properties ... public: // // Constructro ... void XCAccountInfo() { // mAccountInfo = new CAccountInfo(); // mInitialBalance = mAccountInfo.Balance(); } // // Deconstructor ... void ~XCAccountInfo() { // mInitialBalance = 0; } // // User Account ... long GetUserAccount() { return mAccountInfo.Login(); } // // Account Leverage ... long GetLeverage() { return mAccountInfo.Leverage(); } // // Get Trade Expert State ... bool CanExpertTrade() { return mAccountInfo.TradeExpert(); } // // User Account Trade Mopde (ENUM_ACCOUNT_TRADE_MODE) ... ENUM_ACCOUNT_TRADE_MODE GetTradeMode() { return mAccountInfo.TradeMode(); } // // Get Account Balance ... double GetBalance() { return mAccountInfo.Balance(); } // // Get Initial Deposit Balance ... double GetInitialBalance() { return mInitialBalance; } // // Get the amount of give Credit ... double GetCredit() { return mAccountInfo.Credit(); } // // Get the amount of current Profit on account ... double GetProfit() { return mAccountInfo.Profit(); } // // Get the amount of current Equity on account ... double GetEquity() { return mAccountInfo.Equity(); } // // Get the amount of reserved Margin ... double GetMargin() { return mAccountInfo.Margin(); } // // Get the amount of free Margin ... double GetFreeMargin() { return mAccountInfo.FreeMargin(); } // // Get the Level of Margin ... double GetMarginLevel() { return mAccountInfo.MarginLevel(); } // // Get the Level Of Margin for a Deposit ... double GetMarginCall() { return mAccountInfo.MarginCall(); } // // Get the Level of Margin for Stop out ... double GetMarginStopOut() { return mAccountInfo.MarginStopOut(); } // // Get the Client Name ... string GetName() { return mAccountInfo.Name(); } // // Get the Trade Server Name ... string GetServerName() { return mAccountInfo.Server(); } // // Get deposit Currency Name ... string GetCurrency() { return mAccountInfo.Currency(); } // // Get the Company Name that serves an Account ... string GetCompany() { return mAccountInfo.Company(); } // // Calculate Profits for the current account based on passed parameters ... double CalculateTradeProfit( const string symbol, // trading symbol ENUM_ORDER_TYPE type, // order type double volume, // volume double entry, // open price double exit // close price ) { // double result = mAccountInfo.OrderProfitCheck( symbol, type, volume, entry, exit); // return result; } // // Calculate amount of margin which required for trade operation ... double CalculateMarging( const string symbol, // trading symbol ENUM_ORDER_TYPE type, // order type double volume, // volume double entry // open price ) { // double result = mAccountInfo.MarginCheck( symbol, type, volume, entry); // return result; } // // Calculate amount of free margin left after trade operation ... double CalculateFreeMarging( const string symbol, // trading symbol ENUM_ORDER_TYPE type, // order type double volume, // volume double entry // open price ) { // double result = mAccountInfo.FreeMarginCheck( symbol, type, volume, entry); // return result; } // // Calculate the Maximum possible volume of trade operation ... double CalculateMaxVolume( const string symbol, // trading symbol ENUM_ORDER_TYPE type, // order type double entry, // open price double percent = 100 // percent of available margin ) { // double result = mAccountInfo.MaxLotCheck( symbol, type, entry, percent); // return result; } // // Protected properties ... protected: // // Private properties ... private: // // Initial Account Balance ... double mInitialBalance; // // Account Info ... CAccountInfo mAccountInfo; }; // // START Global Definitions: Variables, Properties and etc ... // // // XSaherElm Trade Class ... class XCTrade { // // all public features ... public: // // Constructor ... void XCTrade( string tag, // Specify a Tag for Trader instance string symbol, // Specify Trader Symbol int slippage, // Specify Slippage ulong magicNumber, // Specify Magic Number int maxAllowedTrades, // Specify Max Allowed Trades int maxAllowedSupportTrades, // Specify Max Allowed Support Trades for each Trade double minTradeProfitsInPips, // Minimum Profit of each Trade in Pips double supportTradesPriceDistanceInPips, // Support Trades Price Distance in Pips double minAllowedFreeMarginForOpenTrades, // Minimum Free Marging for Open Trades double minBallanceForOpenTrades // Minimum Balance for Open Trades ) { // mTag = tag; mSymbol = symbol; mSlippage = slippage; mMagicNumber = magicNumber; mMaxAllowedTrades = maxAllowedTrades; mMinTradeProfitsInPips = minTradeProfitsInPips; mMaxAllowedSupportTrades = maxAllowedSupportTrades; mMinBallanceForOpenTrades = minBallanceForOpenTrades; mSupportTradesPriceDistanceInPips = supportTradesPriceDistanceInPips; mMinAllowedFreeMarginForOpenTrades = minAllowedFreeMarginForOpenTrades; // mTrader = new CTrade(); // mTrader.SetAsyncMode(false); mTrader.SetDeviationInPoints(mSlippage); mTrader.SetExpertMagicNumber(mMagicNumber); } // // Deconstructor ... void ~XCTrade() { } // // Count Open Positions ... int Count() { // int result = 0; // int total = PositionsTotal(); for (int i = 0; i < total; i++) { // if (!mPositionInfo.SelectByIndex(i)) { continue; } // if (mPositionInfo.Magic() != mMagicNumber) { continue; } // if (mPositionInfo.Symbol() != mSymbol) { continue; } // result++; } // return result; } // // Count Longs ... int CountLongs() { int result = CountByType(X_SIGNAL_LONG); return result; } // // Count Shorts ... int CountShorts() { int result = CountByType(X_SIGNAL_SHORT); return result; } // // Count By Type ... int CountByType(ENUM_X_SIGNAL_TYPE type) { // // Validate Args ... ENUM_POSITION_TYPE mType = POSITION_TYPE_BUY; if (type == X_SIGNAL_LONG) { mType = POSITION_TYPE_BUY; } else if (type == X_SIGNAL_SHORT) { mType = POSITION_TYPE_SELL; } // int result = CountByType(mType); return result; } // // Count By Type and Kind ... int CountByKind( ENUM_X_SIGNAL_TYPE type, // Specify Type of Positions ENUM_X_SIGNAL_KIND kind // Specify Kind of Positions ) { // int result = 0; // XSignal trades[]; GetPositionsByKind( type, kind, trades); // result = ArraySize(trades); // return result; } // // Retrieve all Positions ... void GetAllPositions(XSignal &result[]) { // CleanBuffer(result); // int total = Count(); ArrayResize(result, total); // int filledIndex = 0; int totalPositions = PositionsTotal(); for (int i = 0; i < totalPositions; i++) { // if (!mPositionInfo.SelectByIndex(i)) { continue; } // if (mPositionInfo.Magic() != mMagicNumber) { continue; } // if (mPositionInfo.Symbol() != mSymbol) { continue; } // result[filledIndex] = PositionToSignal(i); filledIndex++; } } // // Retrieve all Long Positions ... void GetLongPositions(XSignal &result[]) { GetAllPositionsByType(POSITION_TYPE_BUY, result); } // // Retrieve all Short Positions ... void GetShortPositions(XSignal &result[]) { GetAllPositionsByType(POSITION_TYPE_SELL, result); } // // Get Positions by Specified Type ... void GetPositionsByType( ENUM_X_SIGNAL_TYPE type, // Specify Type of Positions XSignal &result[] // Holds Result ... ) { // CleanBuffer(result); // switch (type) { // case X_SIGNAL_LONG: GetLongPositions(result); break; // case X_SIGNAL_SHORT: GetShortPositions(result); break; // case X_SIGNAL_UNKNOWN: default: GetAllPositions(result); break; } } // // Get Positions by Specified Type and Kind ... void GetPositionsByKind( ENUM_X_SIGNAL_TYPE type, // Specify Type of Positions ENUM_X_SIGNAL_KIND kind, // Specify Kind of Positions XSignal &result[] // Holds Result ... ) { // CleanBuffer(result); // XSignal trades[]; switch (type) { // case X_SIGNAL_LONG: GetLongPositions(trades); break; // case X_SIGNAL_SHORT: GetShortPositions(trades); break; // case X_SIGNAL_UNKNOWN: default: GetAllPositions(trades); break; } // int count = ArraySize(trades); if (count <= 0) { return; } // for (int i = 0; i < count; i++) { // XSignal trade = trades[i]; if (trade.kind != kind) { continue; } // Add( trade, result); } } // // Get All Trades Which Candle Passed after Open ... void GetLongTimeTrades( int life, // Max Candle Passed after Trades Open ENUM_TIMEFRAMES period, // Calculate Candles based on time frame ENUM_X_SIGNAL_TYPE type, // Specify Type of Positions ENUM_X_SIGNAL_KIND kind, // Specify Kind of Positions XSignal &result[] // Holds Result ) { // CleanBuffer(result); // // Normalize Period ... if (period == EMPTY_VALUE) { period = _Period; } // XSignal positions[]; GetPositionsByKind( type, kind, positions); int count = ArraySize(positions); if (count <= 0) { return; } // // Current Time Frame Candle Index ... int currentBarIndex = 0; // // Loop through Positions ... for (int i = 0; i < count; i++) { // XSignal trade = positions[i]; // // Retrieve Trade Open Bar Index based on Current Period ... int tradeOpenBarIndex = iBarShift( mSymbol, period, trade.time); // // Calculate Trade Life ... int diff = MathAbs(currentBarIndex - tradeOpenBarIndex); if (diff >= life) { // Add( trade, result); } } } // // Get In DrawDown Trades ... void GetInDrawDownTrades( double maxDrawDown, // Maximum DrawDown of Trades ENUM_X_SIGNAL_TYPE type, // Specify Type of Positions ENUM_X_SIGNAL_KIND kind, // Specify Kind of Positions XSignal &result[] // Holds Result ) { // CleanBuffer(result); // // Validate Args ... if (maxDrawDown <= 0) { maxDrawDown = 0; } // XSignal trades[]; // // Retrieve Signals ... GetPositionsByKind( type, kind, trades); // // Check Trades Count ... int count = ArraySize(trades); if (count <= 0) { return; } // // Loop through all retrieved trades ... for (int i = 0; i < count; i++) { // XSignal trade = trades[i]; if (trade.profit > 0) { continue; } // bool isPassed = maxDrawDown == 0 ? true : (-1 * trade.profit) >= maxDrawDown; if (isPassed) { // Add( trade, result); } } } // // Get In Profit Trades ... void GetInProfitTrades( double minProfit, // Minimum Profit To Close Trades ENUM_X_SIGNAL_TYPE type, // Specify Type of Positions ENUM_X_SIGNAL_KIND kind, // Specify Kind of Positions XSignal &result[] // Holds Result ) { // CleanBuffer(result); // XSignal trades[]; GetPositionsByKind( type, kind, result); // // Check Trades Count ... int count = ArraySize(trades); if (count <= 0) { return; } // // Loop through all retrieved trades ... for (int i = 0; i < count; i++) { // XSignal trade = trades[i]; if (trade.profit < 0) { continue; } // bool isPassed = minProfit <= 0 ? true : trade.profit >= minProfit; if (isPassed) { // Add( trade, result); } } } // // Filter Trades by Searching Comments ... void FilterTrades( string query, // Search String ENUM_X_SIGNAL_TYPE type, // Specify Type of Positions ENUM_X_SIGNAL_KIND kind, // Specify Kind of Positions XSignal &result[] // Holds Result ) { // // Free Buffer ... CleanBuffer(result); // XSignal source[]; GetPositionsByKind( type, kind, source); int sourceCount = ArraySize(source); // if (sourceCount <= 0) { return; } // // Do Filtering Signals ... FilterSignals( query, source, result); } // // Filter In DrawDown Trades by Searching Comments ... void FilterInDrawDowntTrades( string query, // Search String double maxDrawDown, // Maximum DrawDown of Trades ENUM_X_SIGNAL_TYPE type, // Specify Type of Positions ENUM_X_SIGNAL_KIND kind, // Specify Kind of Positions XSignal &result[] // Holds Result ) { // // Free Buffer ... CleanBuffer(result); // XSignal source[]; GetInDrawDownTrades( maxDrawDown, type, kind, source); int sourceCount = ArraySize(source); // if (sourceCount <= 0) { return; } // // Do Filtering Signals ... FilterSignals( query, source, result); } // // Filter In DrawDown Trades by Searching Comments ... void FilterInProfitTrades( string query, // Search String double minProfit, // Minimum Profit of Trades ENUM_X_SIGNAL_TYPE type, // Specify trades type to act ENUM_X_SIGNAL_KIND kind, // Specify Kind of Positions XSignal &result[] // Holds Result ) { // // Free Buffer ... CleanBuffer(result); // XSignal source[]; GetInProfitTrades( minProfit, type, kind, source); int sourceCount = ArraySize(source); // if (sourceCount <= 0) { return; } // // Do Filtering Signals ... FilterSignals( query, source, result); } // // Filter Trades by Searching Comments ... void FilterTrades( string query, // Search String XSignal &source[], // Source Buffer to Filter XSignal &result[] // Holds Result ) { // // Free Buffer ... CleanBuffer(result); // // Do Filtering Signals ... FilterSignals( query, source, result); } // // Force Open a Buy/Long Position ... bool Buy( double volume, // position volume double price, // execution price double sl = 0, // stop loss price double tp = 0, // take profit price const string comment = "" // comment ) { // bool result = false; // result = mTrader.Buy( volume, mSymbol, price, sl, tp, comment); // return result; } // // Force Open a Sell/Short Position ... bool Sell( double volume, // position volume double price, // execution price double sl = 0, // stop loss price double tp = 0, // take profit price const string comment = "" // comment ) { // bool result = false; // result = mTrader.Sell( volume, mSymbol, price, sl, tp, comment); // return result; } // // Validate Signal ... bool ValidateSignal(XSignal &signal) { // bool result = false; // // Validate Signal Type ... result = signal.type != X_SIGNAL_UNKNOWN; if (!result) { return result; } // // Check Symbol ... result = StringLen(signal.symbol) == 0 ? true : signal.symbol == mSymbol; if (!result) { return result; } // // Check magic number ... result = signal.magicNumber <= 0 ? true : signal.magicNumber == mMagicNumber; if (!result) { return result; } // // Check Entry ... result = signal.entry > 0; if (!result) { return result; } // // Check SL ... result = signal.sl == 0 ? true : signal.type == X_SIGNAL_LONG ? signal.sl < signal.entry : signal.sl > signal.entry; if (!result) { return result; } // // Check TP ... result = signal.tp == 0 ? true : signal.type == X_SIGNAL_LONG ? signal.tp > signal.entry : signal.tp < signal.entry; if (!result) { return result; } // // Check Volume ... result = signal.volume > 0; if (!result) { return result; } // // Check Time ... result = signal.time > 0; if (!result) { return result; } // return result; } // // Execute an Specific XSignal instance ... bool ExecuteSignal( XSignal &signal, // Specify Signal for Execution int &error // Error code if Happens ) { // bool result = ValidateSignal(signal); if (!result) { // error = X_INVALID_SIGNAL_ERROR; return result; } // signal.symbol = mSymbol; // bool isTrade = signal.kind == X_KIND_TRADE; // int kindCount = CountByKind( signal.type, signal.kind); // // Check Account Balance ... result = IsAccountBalanceReadyForTrade(); if (!result) { // error = X_XTRADER_NOT_ENOUGH_BALANCE_ERROR; return result; } // // Check Account Free Margin ... result = IsFreeMarginReadyForTrade(); if (!result) { // error = X_XTRADER_NOT_ENOUGH_MARIGIN_ERROR; return result; } // // Check Trade Count ... result = isTrade ? // mMaxAllowedTrades <= 0 ? // true : // kindCount < mMaxAllowedTrades : // mMaxAllowedSupportTrades <= 0 ? // true : // kindCount < mMaxAllowedSupportTrades // ; if (!result) { // error = isTrade ? X_XTRADER_MAX_ALLOWED_TRADE_KIND_REACHED_ERROR : X_XTRADER_MAX_ALLOWED_SUPPORT_KIND_REACHED_ERROR; return result; } // result = signal.type == X_SIGNAL_LONG ? Buy( signal.volume, signal.entry, signal.sl, signal.tp, signal.comment) : signal.type == X_SIGNAL_SHORT ? Sell( signal.volume, signal.entry, signal.sl, signal.tp, signal.comment) : false; // if (result) { error = X_SUCCEED_EXECUTION; } else { error = X_UNKNOWN_ERROR; } // return result; } // // Virtual TP and SL Handler ... void HandleVirtualTPSL( ENUM_X_SIGNAL_TYPE type, // Specify Type of Positions ENUM_X_SIGNAL_KIND kind, // Specify Kind of Positions XSignal &takeProfits[], // Holds all Take Profit Executed Signals XSignal &stopLosses[] // Holds all Stop Loss Executed Signals ) { // CleanBuffer(takeProfits); CleanBuffer(stopLosses); // XSignal trades[]; GetPositionsByKind( type, kind, trades); int count = ArraySize(trades); if (count <= 0) { return; } // // Loop ... for (int i = 0; i < count; i++) { // XSignal trade = trades[i]; // if (trade.virtualTP <= 0 && trade.virtualSL <= 0) { continue; } // double exitPrice = GetExit(trade.type); bool isLong = trade.type == X_SIGNAL_LONG; // // Handle Take Profits ... if (trade.virtualTP > 0) { // bool isPriceReached = isLong ? exitPrice >= trade.virtualTP : exitPrice <= trade.virtualTP; if (isPriceReached) { // bool isClosed = Close(trade.ticket); if (isClosed) { Add( trade, takeProfits); } } } // // Handle Stop Losses ... if (trade.virtualSL < 0) { // bool isPriceReached = isLong ? exitPrice <= trade.virtualSL : exitPrice >= trade.virtualSL; if (isPriceReached) { // bool isClosed = Close(trade.ticket); if (isClosed) { Add( trade, stopLosses); } } } } } void HandleVirtualTPSL( XSignal &takeProfits[], // Holds all Take Profit Executed Signals XSignal &stopLosses[] // Holds all Stop Loss Executed Signals ) { // CleanBuffer(takeProfits); CleanBuffer(stopLosses); // XSignal tradesTP[]; XSignal tradesSL[]; HandleVirtualTPSL( X_SIGNAL_UNKNOWN, X_KIND_TRADE, tradesTP, tradesSL); // // TPs ... int tradesTPCount = ArraySize(tradesTP); if (tradesTPCount > 0) { // // Loop ... for (int i = 0; i < tradesTPCount; i++) { // XSignal fTrade = tradesTP[i]; // Add( fTrade, takeProfits); } } // // SLs ... int tradesSLCount = ArraySize(tradesSL); if (tradesSLCount > 0) { // // Loop ... for (int i = 0; i < tradesSLCount; i++) { // XSignal fTrade = tradesSL[i]; // Add( fTrade, stopLosses); } } // XSignal supportsTP[]; XSignal supportsSL[]; HandleVirtualTPSL( X_SIGNAL_UNKNOWN, X_KIND_SUPPORT, supportsTP, supportsSL); // // TPs ... int supportsTPCount = ArraySize(supportsTP); if (supportsTPCount > 0) { // // Loop ... for (int i = 0; i < supportsTPCount; i++) { // XSignal fTrade = supportsTP[i]; // Add( fTrade, takeProfits); } } // // SLs ... int supportsSLCount = ArraySize(supportsSL); if (supportsSLCount > 0) { // // Loop ... for (int i = 0; i < supportsSLCount; i++) { // XSignal fTrade = supportsSL[i]; // Add( fTrade, stopLosses); } } } // // Modify Position ... bool Modify( const ulong ticket, // position ticket double sl = 0, // stop loss price double tp = 0 // take profit ) { // bool result = false; // // Validate Args ... if (tp <= 0 && sl <= 0) { result = false; return result; } // result = mTrader.PositionModify( ticket, sl, tp); // return result; } // // Close Position By Ticket ... bool Close(ulong ticket) { // bool result = false; // // Try to Select Position ... if (!mPositionInfo.SelectByTicket(ticket)) { // result = false; return result; } // result = mTrader.PositionClose(ticket); // return result; } // // Close Partial By Ticket ... bool ClosePartial(ulong ticket, double volume) { // bool result = false; // if (!mPositionInfo.SelectByTicket(ticket)) { // result = false; return result; } // mTrader.PositionClosePartial( ticket, volume); // return result; } // // Partial Close all Reached Signals ... void RiskFreeSignals( ENUM_X_SIGNAL_TYPE type, // Specify Type of Positions ENUM_X_SIGNAL_KIND kind, // Specify Kind of Positions XSignal &riskFrees[] // Holds all Executed Signals ) { // CleanBuffer(riskFrees); // XSignal trades[]; GetPositionsByKind( type, kind, trades); int count = ArraySize(trades); if (count <= 0) { return; } // // Loop ... for (int i = 0; i < count; i++) { // XSignal trade = trades[i]; // // Ignore Not Risk Free Signal ... if ( trade.riskFree <= 0 || (trade.riskFree > 0 && trade.riskFreeRate <= 0)) { continue; } // bool isLong = trade.type == X_SIGNAL_LONG; // // Check Exit Price reached Risk Free ... double exitPrice = GetExit(trade.type); double isPriceReachedRiskFree = isLong ? exitPrice >= trade.riskFree : exitPrice <= trade.riskFree; if (!isPriceReachedRiskFree) { continue; } // double riskFreeRate = trade.riskFreeRate > 0.75 ? 0.75 : trade.riskFreeRate; double volume = NormalizeVolume(riskFreeRate * trade.volume); // bool isPartialClosed = ClosePartial(trade.ticket, volume); if (isPartialClosed) { // double tpValue = trade.virtualTP > 0 ? trade.virtualTP : trade.tp; double slValue = trade.virtualSL > 0 ? trade.virtualSL : trade.sl; // bool isModified = Modify(trade.ticket, tpValue, slValue); if (isModified) { Add( trade, riskFrees); } } } } void RiskFreeSignals( XSignal &riskFrees[] // Holds all Executed Signals ) { // CleanBuffer(riskFrees); // XSignal trades[]; RiskFreeSignals( X_SIGNAL_UNKNOWN, X_KIND_TRADE, trades); int tradesCount = ArraySize(trades); if (tradesCount > 0) { // // Loop ... for (int i = 0; i < tradesCount; i++) { // XSignal fTrade = trades[i]; // Add( fTrade, riskFrees); } } // XSignal supports[]; RiskFreeSignals( X_SIGNAL_UNKNOWN, X_KIND_SUPPORT, supports); int supportsCount = ArraySize(supports); if (supportsCount > 0) { // // Loop ... for (int i = 0; i < supportsCount; i++) { // XSignal fTrade = supports[i]; // Add( fTrade, riskFrees); } } } // // Close All Open Positions ... void CloseAllPositions( XSignal &closed[] // Holds Closed Positions ) { // CleanBuffer(closed); // XSignal allPositions[]; GetAllPositions(allPositions); // // Count all Specified Positions ... int total = ArraySize(allPositions); if (total <= 0) { return; } // for (int i = 0; i < total; i++) { // XSignal signal = allPositions[i]; bool isClosed = Close(signal.ticket); if (isClosed) { // Add( signal, closed); } } } // // Close Positions By Type ... void ClosePositionsByType( ENUM_X_SIGNAL_TYPE type, // Specify Type of Positions XSignal &closed[] // Holds Closed Positions ) { // CleanBuffer(closed); // XSignal allPositions[]; GetPositionsByType( type, allPositions); // // Count all Specified Positions ... int total = ArraySize(allPositions); if (total <= 0) { return; } // for (int i = 0; i < total; i++) { // XSignal signal = allPositions[i]; bool isClosed = Close(signal.ticket); if (isClosed) { // Add( signal, closed); } } } // // Close Positions By Kind ... void ClosePositionsByKind( ENUM_X_SIGNAL_TYPE type, // Specify Type of Positions ENUM_X_SIGNAL_KIND kind, // Specify Kind of Positions XSignal &closed[] // Holds Closed Positions ) { // CleanBuffer(closed); // XSignal allPositions[]; GetPositionsByKind( type, kind, allPositions); // // Count all Specified Positions ... int total = ArraySize(allPositions); if (total <= 0) { return; } // for (int i = 0; i < total; i++) { // XSignal signal = allPositions[i]; bool isClosed = Close(signal.ticket); if (isClosed) { // Add( signal, closed); } } } // // Close All Trades Which Candle Passed after Open ... void CloseLongTimeTrades( int life, // Max Candle Passed after Trades Open ENUM_TIMEFRAMES period, // Calculate Candles based on time frame ENUM_X_SIGNAL_TYPE type, // Specify Type of Positions ENUM_X_SIGNAL_KIND kind, // Specify Kind of Positions XSignal &closed[] // Holds Closed Trades ) { // CleanBuffer(closed); // // Normalize Period ... if (period == EMPTY_VALUE) { period = _Period; } // XSignal positions[]; GetLongTimeTrades( life, period, type, kind, positions); int count = ArraySize(positions); if (count <= 0) { return; } // // Loop through Positions ... for (int i = 0; i < count; i++) { // XSignal trade = positions[i]; bool isClosed = Close(trade.ticket); if (isClosed) { // Add( trade, closed); } } } void CloseLongTimeTrades( int life, // Max Candle Passed after Trades Open ENUM_TIMEFRAMES period, // Calculate Candles based on time frame XSignal &closed[] // Holds Closed Trades ) { // CleanBuffer(closed); // XSignal trades[]; CloseLongTimeTrades( life, period, X_SIGNAL_UNKNOWN, X_KIND_TRADE, trades); int tradesCount = ArraySize(trades); if (tradesCount > 0) { // // Loop ... for (int i = 0; i < tradesCount; i++) { // XSignal fTrade = trades[i]; // Add( fTrade, closed); } } // XSignal supports[]; CloseLongTimeTrades( life, period, X_SIGNAL_UNKNOWN, X_KIND_SUPPORT, supports); int supportsCount = ArraySize(supports); if (supportsCount > 0) { // // Loop ... for (int i = 0; i < supportsCount; i++) { // XSignal fTrade = supports[i]; // Add( fTrade, closed); } } } // // Close In DrawDown Trades ... void CloseInDrawDownTrades( double maxDrawDown, // Maximum DrawDown of Trades ENUM_X_SIGNAL_TYPE type, // Specify Type of Positions ENUM_X_SIGNAL_KIND kind, // Specify Kind of Positions XSignal &closed[] // Holds Closed Trades ) { // CleanBuffer(closed); // // Validate Args ... if (maxDrawDown <= 0) { return; } // XSignal trades[]; GetInDrawDownTrades( maxDrawDown, type, kind, trades); // // Check Trades Count ... int count = ArraySize(trades); if (count <= 0) { return; } // // Loop through all retrieved trades ... for (int i = 0; i < count; i++) { // XSignal trade = trades[i]; bool isClosed = Close(trade.ticket); if (isClosed) { Add( trade, closed); } } } void CloseInDrawDownTrades( double maxDrawDown, // Maximum DrawDown of Trades XSignal &closed[] // Holds Closed Trades ) { // CleanBuffer(closed); // XSignal trades[]; CloseInDrawDownTrades( maxDrawDown, X_SIGNAL_UNKNOWN, X_KIND_TRADE, trades); int tradesCount = ArraySize(trades); if (tradesCount > 0) { // // Loop ... for (int i = 0; i < tradesCount; i++) { // XSignal fTrade = trades[i]; // Add( fTrade, closed); } } // XSignal supports[]; CloseInDrawDownTrades( maxDrawDown, X_SIGNAL_UNKNOWN, X_KIND_SUPPORT, supports); int supportsCount = ArraySize(supports); if (supportsCount > 0) { // // Loop ... for (int i = 0; i < supportsCount; i++) { // XSignal fTrade = supports[i]; // Add( fTrade, closed); } } } // // Close All In Profit Trades ... void CloseInProfitTrades( double minProfit, // Minimum Profit To Close Trades ENUM_X_SIGNAL_TYPE type, // Specify trades type to act ENUM_X_SIGNAL_KIND kind, // Specify Kind of Positions XSignal &closed[] // Holds Closed Trades ) { // CleanBuffer(closed); // XSignal trades[]; GetInProfitTrades( minProfit, type, kind, trades); // // Check Trades Count ... int count = ArraySize(trades); if (count <= 0) { return; } // // Loop through all retrieved trades ... for (int i = 0; i < count; i++) { // XSignal trade = trades[i]; bool isClosed = Close(trade.ticket); if (isClosed) { Add( trade, closed); } } } void CloseInProfitTrades( double minProfit, // Minimum Profit To Close Trades XSignal &closed[] // Holds Closed Trades ) { // CleanBuffer(closed); // XSignal trades[]; CloseInProfitTrades( minProfit, X_SIGNAL_UNKNOWN, X_KIND_TRADE, trades); int tradesCount = ArraySize(trades); if (tradesCount > 0) { // // Loop ... for (int i = 0; i < tradesCount; i++) { // XSignal fTrade = trades[i]; // Add( fTrade, closed); } } // XSignal supports[]; CloseInProfitTrades( minProfit, X_SIGNAL_UNKNOWN, X_KIND_SUPPORT, supports); int supportsCount = ArraySize(supports); if (supportsCount > 0) { // // Loop ... for (int i = 0; i < supportsCount; i++) { // XSignal fTrade = supports[i]; // Add( fTrade, closed); } } } // // Prepare a Signall ... XSignal GenerateSignal( ENUM_X_SIGNAL_TYPE type, // Signal Type double tp = 0, // Take Profit double sl = 0, // Stop Loss double volume = 0, // Volume double riskFree = 0, // Risk Free Price double riskFreeRate = 0, // Risk Free Rate ENUM_X_SIGNAL_KIND kind = X_KIND_TRADE, // Signal Kind ulong parent = 0, // Support Kind Signal Parent bool useVirtualTPSL = false // Use Virtual TP and SL ) { // XSignal result = {}; // double entry = GetEntry(mSymbol, type); double riskFreePrice = 0; // if (tp <= 0) { // double minReward = PipsToPrice(mMinTradeProfitsInPips); tp = type == X_SIGNAL_LONG ? entry + minReward : entry - minReward; tp = NormalizePrice(tp, mSymbol); } // if (riskFree > 0 && riskFreeRate > 0) { // riskFreePrice = type == X_SIGNAL_LONG ? entry + riskFree : entry - riskFree; riskFreePrice = NormalizePrice(riskFreePrice, mSymbol); } // double tpValue = NormalizePrice(tp, mSymbol); double slValue = NormalizePrice(sl, mSymbol); // result.type = type; result.kind = kind; result.entry = entry; result.parent = parent; result.symbol = mSymbol; result.riskFree = riskFreePrice; result.magicNumber = mMagicNumber; result.riskFreeRate = riskFreeRate; result.tp = useVirtualTPSL ? 0 : tpValue; result.sl = useVirtualTPSL ? 0 : slValue; result.time = iTime(mSymbol, _Period, 0); result.virtualTP = useVirtualTPSL ? tpValue : 0; result.virtualSL = useVirtualTPSL ? slValue : 0; result.volume = NormalizeVolume(volume, mSymbol); result.comment = GetSignalComment(result, useVirtualTPSL); // return result; } XSignal GenerateTradeSignal( ENUM_X_SIGNAL_TYPE type, // Signal Type double tp, // Take Profit double sl, // Stop Loss double volume, // Volume double riskFree = 0, // Risk Free Price double riskFreeRate = 0, // Risk Free Rate bool useVirtualTPSL = false // Use Virtual TP and SL ) { // XSignal result = GenerateSignal( type, tp, sl, volume, riskFree, riskFreeRate, X_KIND_TRADE, 0, useVirtualTPSL); // return result; } XSignal GenerateSupportSignal( ENUM_X_SIGNAL_TYPE type, // Signal Type double tp, // Take Profit double sl, // Stop Loss double volume, // Volume double riskFree, // Risk Free Price double riskFreeRate, // Risk Free Rate ulong parent, // Support Kind Signal Parent bool useVirtualTPSL = false // Use Virtual TP and SL ) { // XSignal result = GenerateSignal( type, tp, sl, volume, riskFree, riskFreeRate, X_KIND_TRADE, parent, useVirtualTPSL); // return result; } // // all protected features ... protected: // // all private features ... private: // // Specified Unique Tag ... string mTag; // // which Symbol ... string mSymbol; // // using deviation, it must be in Point ... int mSlippage; // // using magic number ... ulong mMagicNumber; // // Specify Max Allowed Trades int mMaxAllowedTrades; // // Specify Max Allowed Support Trades for each Trade int mMaxAllowedSupportTrades; // // Minimum Profit of each Trade in Pips double mMinTradeProfitsInPips; // // Support Trades Price Distance in Pips double mSupportTradesPriceDistanceInPips; // // Minimum Free Marging for Open Trades double mMinAllowedFreeMarginForOpenTrades; // // Minimum Balance for Open Trades double mMinBallanceForOpenTrades; // // using CTrade instance ... CTrade mTrader; // // An Instance Of XCAccount Info for Handling Account Related Actions ... XCAccountInfo mAccountInfo; // // using PositionInfo instance ... CPositionInfo mPositionInfo; // // For Manage Deals ... CDealInfo mDealInfo; // // using OrderInfo instance ... COrderInfo mPendingInfo; // // using HistoryOrderInfo instance ... CHistoryOrderInfo mHistoryInfo; // // Count Specific Type Of Positions ... int CountByType(ENUM_POSITION_TYPE type) { // int result = 0; // int total = PositionsTotal(); for (int i = 0; i < total; i++) { // if (!mPositionInfo.SelectByIndex(i)) { continue; } // if (mPositionInfo.Symbol() != mSymbol) { continue; } // if (mPositionInfo.PositionType() != type) { continue; } // result++; } // return result; } // // Convert Position to Signal by Index ... XSignal PositionToSignal(int index) { // XSignal result = {}; // if (!mPositionInfo.SelectByIndex(index)) { return result; } // // ID ... result.id = mPositionInfo.Identifier(); // // Symbol ... result.symbol = mPositionInfo.Symbol(); // // Type ... ENUM_POSITION_TYPE pType = (ENUM_POSITION_TYPE)mPositionInfo.PositionType(); ENUM_X_SIGNAL_TYPE type = pType == POSITION_TYPE_BUY ? X_SIGNAL_LONG : X_SIGNAL_SHORT; result.type = type; // // Kind ... result.kind = ExtractPositionKind(mPositionInfo.Comment()); // // Parent ... result.parent = ExtractPositionParent(mPositionInfo.Comment()); // // MagicNumber ... result.magicNumber = mPositionInfo.Magic(); // // Ticket ... result.ticket = mPositionInfo.Ticket(); // // Entry/Open Price ... result.entry = mPositionInfo.PriceOpen(); // // Take Profit ... result.tp = mPositionInfo.TakeProfit(); // // Virtual TP ... result.virtualTP = ExtractVirtualTP(mPositionInfo.Comment()); // // Stop Loss ... result.sl = mPositionInfo.StopLoss(); // // Virtual SL ... result.virtualSL = ExtractVirtualSL(mPositionInfo.Comment()); // // RiskFree ... result.riskFree = ExtractRiskFree(mPositionInfo.Comment()); // // RiskFreeRate ... result.riskFreeRate = ExtractRiskFreeRate(mPositionInfo.Comment()); // // Profit ... result.profit = mPositionInfo.Profit(); // // Time ... result.time = mPositionInfo.Time(); // // Volume ... result.volume = mPositionInfo.Volume(); // // Comment ... result.comment = mPositionInfo.Comment(); // return result; } // // Convert Position to Signal by Index ... XSignal OrderToSignal(int index) { // XSignal result = {}; // if (!mHistoryInfo.SelectByIndex(index)) { return result; } // // ID ... result.id = mHistoryInfo.PositionId(); // // Symbol ... result.symbol = mHistoryInfo.Symbol(); // // Type ... ENUM_ORDER_TYPE pType = (ENUM_ORDER_TYPE)mHistoryInfo.OrderType(); ENUM_X_SIGNAL_TYPE type = X_SIGNAL_UNKNOWN; switch (pType) { // case ORDER_TYPE_BUY: case ORDER_TYPE_BUY_LIMIT: case ORDER_TYPE_BUY_STOP: case ORDER_TYPE_BUY_STOP_LIMIT: type = X_SIGNAL_LONG; break; // case ORDER_TYPE_SELL: case ORDER_TYPE_SELL_LIMIT: case ORDER_TYPE_SELL_STOP: case ORDER_TYPE_SELL_STOP_LIMIT: type = X_SIGNAL_SHORT; break; // // Default ... default: type = X_SIGNAL_UNKNOWN; break; } result.type = type; // // MagicNumber ... result.magicNumber = mHistoryInfo.Magic(); // // Ticket ... result.ticket = mHistoryInfo.Ticket(); // // Entry/Open Price ... result.entry = mHistoryInfo.PriceOpen(); // // Take Profit ... result.tp = mHistoryInfo.TakeProfit(); // // Stop Loss ... result.sl = mHistoryInfo.StopLoss(); // // Profit ... // TODO Calculate it ... // result.profit = mHistoryInfo.Profit(); // // // // Time ... // result.time = mHistoryInfo.Time(); // // // // Volume ... // result.volume = mHistoryInfo.Volume(); // // Comment ... result.comment = mHistoryInfo.Comment(); // return result; } // // Extract Signal Kind Based on given comment ... ENUM_X_SIGNAL_KIND ExtractPositionKind(string comment) { // ENUM_X_SIGNAL_KIND result = X_KIND_TRADE; // if (StringLen(comment) == 0) { return result; } // string query = GetSignalKind(X_KIND_SUPPORT) + "_For_"; int startPos = StringFind( comment, query); int lastSeparatorPos = StringFind( comment, "_", startPos + StringLen(query) + 1); if (startPos < 0 || lastSeparatorPos < 0) { return result; } // Print( "startPos: " + (string)startPos + ", lastPos: " + (string)lastSeparatorPos + ", Extracted:" + StringSubstr(comment, startPos, startPos + lastSeparatorPos + 1)); // int length = lastSeparatorPos - startPos; string parentTicketStr = StringSubstr( comment, startPos, length); ulong parentTicket = (ulong)parentTicketStr; // result = X_KIND_SUPPORT; // return result; } // // Extract Signal Parent Ticket Based on given comment ... ulong ExtractPositionParent(string comment) { // ulong result = 0; // if (StringLen(comment) == 0) { return result; } // string query = GetSignalKind(X_KIND_SUPPORT) + "_For_"; int startPos = StringFind( comment, query); int lastSeparatorPos = StringFind( comment, "_", startPos + StringLen(query) + 1); if (startPos < 0 || lastSeparatorPos < 0) { return result; } // int length = lastSeparatorPos - startPos; string parentTicketStr = StringSubstr( comment, startPos, length); result = (ulong)parentTicketStr; // return result; } // // Extract Virtual TP based on given comment ... double ExtractVirtualTP(string comment) { // double result = 0; // if (StringLen(comment) == 0) { return result; } // string query = "_P("; int startPos = StringFind( comment, query); int lastSeparatorPos = StringFind( comment, ")", startPos + StringLen(query) + 1); if (startPos < 0 || lastSeparatorPos < 0) { return result; } // int length = lastSeparatorPos - startPos; string resultStr = StringSubstr( comment, startPos, length); result = (double)resultStr; // return result; } // // Extract Virtual SL based on given comment ... double ExtractVirtualSL(string comment) { // double result = 0; // if (StringLen(comment) == 0) { return result; } // string query = "_L("; int startPos = StringFind( comment, query); int lastSeparatorPos = StringFind( comment, ")", startPos + StringLen(query) + 1); if (startPos < 0 || lastSeparatorPos < 0) { return result; } // int length = lastSeparatorPos - startPos; string resultStr = StringSubstr( comment, startPos, length); result = (double)resultStr; // return result; } // // Extract RiskFree based on given comment ... double ExtractRiskFree(string comment) { // double result = 0; // if (StringLen(comment) == 0) { return result; } // string query = "_R("; int startPos = StringFind( comment, query); int lastSeparatorPos = StringFind( comment, ")", startPos + StringLen(query) + 1); if (startPos < 0 || lastSeparatorPos < 0) { return result; } // int length = lastSeparatorPos - startPos; string resultStr = StringSubstr( comment, startPos, length); result = (double)resultStr; // return result; } // // Extract RiskFreeRate based on given comment ... double ExtractRiskFreeRate(string comment) { // double result = 0; // if (StringLen(comment) == 0) { return result; } // string query = "_M("; int startPos = StringFind( comment, query); int lastSeparatorPos = StringFind( comment, ")", startPos + StringLen(query) + 1); if (startPos < 0 || lastSeparatorPos < 0) { return result; } // int length = lastSeparatorPos - startPos; string resultStr = StringSubstr( comment, startPos, length); result = (double)resultStr; // return result; } // // Filter Trades Buffer ... void FilterSignals( string query, // Search String XSignal &source[], // Source Buffer to Filter XSignal &result[] // Holds Result ) { // // Free Buffer ... CleanBuffer(result); // int sourceCount = ArraySize(source); // // Check Conditions and Validate Args ... if ( sourceCount == 0 || StringLen(query) == 0) { return; } // // Loop Through Source ... for (int i = 0; i < sourceCount; i++) { // // Retrieve Indexed Item ... XSignal trade = source[i]; // // Check Query Exists or not ... int pos = StringFind( trade.comment, query); // // Continue if nothing found ... if (pos <= -1) { continue; } // // Resize the result array ... ArrayResize( result, ArraySize(result) + 1); result[ArraySize(result) - 1] = trade; } } // // Get all Positions based on Position Type ... void GetAllPositionsByType(ENUM_POSITION_TYPE type, XSignal &result[]) { // int existsTotal = CountByType(type); // CleanBuffer(result); ArrayResize(result, existsTotal); // int filledIndex = 0; int total = PositionsTotal(); for (int i = 0; i < total; i++) { // if (!mPositionInfo.SelectByIndex(i)) { continue; } // if (mPositionInfo.Magic() != mMagicNumber) { continue; } // if (mPositionInfo.Symbol() != mSymbol) { continue; } // if (mPositionInfo.PositionType() != type) { continue; } // result[filledIndex] = PositionToSignal(i); filledIndex++; } } // // Generate Comments for Specific Signal ... string GetSignalComment( ENUM_X_SIGNAL_KIND kind, // Specify Kind ENUM_X_SIGNAL_TYPE type, // Specify Kind Signal Type ulong parentTicket, // Parent Signal Ticket double volume, // Signal Volume double riskFree, // Risk Free Price double riskFreeRate, // Risk Free Volume Multiplier double virtualTP, // Virtual TP double virtualSL // Virtual SL ) { // string result = ""; // string kindStr = GetSignalKind(kind); string typeStr = GetSignalType(type); if ( volume <= 0 || StringLen(kindStr) == 0 || StringLen(typeStr) == 0 || (parentTicket <= 0 && kind == X_KIND_SUPPORT)) { return result; } // // Normalize Data ... // if (riskFreeRate < 0) { riskFreeRate = 0; } else if (riskFreeRate > 1) { riskFreeRate = 0.75; } // volume = NormalizeVolume(volume, mSymbol); riskFree = NormalizePrice(riskFree, mSymbol); virtualTP = NormalizePrice(virtualTP, mSymbol); virtualSL = NormalizePrice(virtualSL, mSymbol); // if (riskFree > 0 && riskFreeRate == 0) { riskFreeRate = 0.75; } else if (riskFree <= 0 && riskFreeRate > 0) { riskFreeRate = 0; } // string kindTitle = kind == X_KIND_TRADE ? kindStr : kindStr + "_For_" + (string)parentTicket; result = mTag + "_" + typeStr + "_" + kindTitle; // if (virtualTP > 0) { result += "_P(" + (string)virtualTP + ")"; } // if (virtualSL > 0) { result += "_L(" + (string)virtualSL + ")"; } // if (riskFree > 0 && riskFreeRate > 0) { result += "_R(" + (string)riskFree + ")_M(" + (string)riskFreeRate + ")"; } // return result; } string GetSignalComment( XSignal &signal, // Specify Signal bool useVirtualTPSL = false // Use Virtual TP and SL ) { // string result = GetSignalComment( signal.kind, signal.type, signal.parent, signal.volume, signal.riskFree, signal.riskFreeRate, useVirtualTPSL ? signal.virtualTP : 0, useVirtualTPSL ? signal.virtualSL : 0); // return result; } // // Check Number Of Trades is Valid ... bool CanOpenNewTrade() { // bool result = false; // int count = Count(); result = mMaxAllowedTrades <= 0 ? true : count < mMaxAllowedTrades; // return result; } // // Check Number Of Support Trades is Valid ... bool CanOpenSupportTrade() { // bool result = false; // return result; } // // Check Account Has Minimum Balance For Trade ... bool IsAccountBalanceReadyForTrade() { // bool result = false; // result = mAccountInfo.GetBalance() >= mMinBallanceForOpenTrades; // return result; } // // Check Free Margin Has Enough For Trade ... bool IsFreeMarginReadyForTrade() { // bool result = false; // result = mAccountInfo.GetFreeMargin() >= mMinAllowedFreeMarginForOpenTrades; // return result; } }; // // END Global Definitions: Variables, Properties and etc ... //