/////////////////////////////////////////////////////// // // SaherElm IT Center MQL5 Expert Class Library // ---------------------------------------------- // Name: XSCTrade // Description: provides all Trade requirements ... // // // 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 // // START Definitions ... // // // Model an Open Position ... struct XPosition { // // Magic Number ... ulong magic; // // Ticket ID ... ulong ticket; // // Tradinng Symbol ... string symbol; // // Trading Period ... ENUM_TIMEFRAMES period; // // Position Type ... ENUM_POSITION_TYPE type; // // Take Profit ... double tp; // // Stop Loss ... double sl; // // Position Current Profit ... double profit; // // Position Open Price ... double entry; // // Current Symbol Price ... double price; // // Position Swap ... double swap; // // Position Commission ... double commission; // // Volume ... double volume; // // Position Open Time ... datetime openAt; // // Position Comment ... string comment; }; // // Model an Order ... struct XOrder { // // Time of order placement ... datetime setupAt; // // Time of order expiration ... datetime expiredAt; // // Time of order execution or cancellation ... datetime executedAt; // // Order type ... ENUM_ORDER_TYPE type; // // Order state ... ENUM_ORDER_STATE state; // // Type of execution by remainder ... ENUM_ORDER_TYPE_FILLING filling; // // Order lifetime ... ENUM_ORDER_TYPE_TIME lifetime; // // Order ticket ... ulong ticket; // // Magic Number ... long magic; // // Position id, that is placed on order, // when it is executed. Each executed order invokes a // deal, that opens new or changes existing // position. Id of that position is placed on // executed order in this moment. long pocitionID; // // Initial volume on order placement ... double initialVolume; // // Unfilled volume ... double currentVolume; // // Price, specified in the order ... double openPrice; // // Current price by order symbol ... double currentPrice; // // Price of placing Limit order when StopLimit order is triggered ... double stopLimitPrice; // // Take Profit level ... double tp; // // Stop Loss level ... double sl; // // Trading Symbol ... string smybol; // // Order Comment ... string comment; }; // // Model a Deal ... struct XDeal { // // the ID of the Expert Advisor, that executed the deal ... ulong magic; // // the ID of position, in which the deal was involved ... ulong positionId; // // Ticket ... ulong ticket; // // the name of the deal symbol ... string symbol; // // order by which the deal is executed ... ulong order; // // the time of deal execution ... datetime time; // // Deal price ... double price; // // the financial result of the deal (in deposit currency) ... double profit; // // the amount of swap when position is closed ... double swap; // // the amount of commission of the deal ... double commission; // // the volume of deal ... double volume; // // the deal comment ... string comment; // // the deal type ... // ------------------------------------------------------------------ // DEAL_TYPE_BUY => Buy ... // DEAL_TYPE_SELL => Sell ... // DEAL_TYPE_BUY_CANCELED => Canceled buy deal ... // There can be a situation when a previously executed buy deal is canceled. In this case, // the type of the previously executed deal (DEAL_TYPE_BUY) is changed to DEAL_TYPE_BUY_CANCELED, // and its profit/loss is zeroized. Previously obtained profit/loss is charged/withdrawn using a separated balance operation ... // // DEAL_TYPE_SELL_CANCELED => Canceled sell deal ... // There can be a situation when a previously executed sell deal is canceled. In this case, // the type of the previously executed deal (DEAL_TYPE_SELL) is changed to DEAL_TYPE_SELL_CANCELED, // and its profit/loss is zeroized. Previously obtained profit/loss is charged/withdrawn using a separated balance operation // // DEAL_TYPE_BALANCE => Balance ... // DEAL_TYPE_CREDIT => Credit ... // DEAL_TYPE_CHARGE => Additional charge ... // DEAL_TYPE_CORRECTION => Correction ... // DEAL_TAX => Tax charges ... // DEAL_TYPE_BONUS => Bonus ... // DEAL_TYPE_INTEREST => Interest rate ... // DEAL_DIVIDEND => Dividend operations... // DEAL_DIVIDEND_FRANKED => Franked (non-taxable) dividend operations ... // DEAL_TYPE_COMMISSION => Additional commission ... // DEAL_TYPE_COMMISSION_DAILY => Daily commission ... // DEAL_TYPE_COMMISSION_MONTHLY => Monthly commission ... // DEAL_TYPE_COMMISSION_AGENT_DAILY => Daily agent commission ... // DEAL_TYPE_COMMISSION_AGENT_MONTHLY => Monthly agent commission ENUM_DEAL_TYPE type; // // the deal direction ... // ---------------------------------- // DEAL_ENTRY_IN => Entry in ... // DEAL_ENTRY_OUT => Entry out ... // DEAL_ENTRY_INOUT => Reverse ... // DEAL_ENTRY_OUT_BY => Close a position by an opposite one ... ENUM_DEAL_ENTRY entry; // // deal reson ... // --------------------- // DEAL_REASON_SL => The deal was executed as a result of Stop Loss activation ... // DEAL_REASON_TP => The deal was executed as a result of Take Profit activation ... // DEAL_REASON_SO => The deal was executed as a result of the Stop Out event ... // DEAL_REASON_WEB => The deal was executed as a result of activation of an order placed from the web platform ... // DEAL_REASON_SPLIT => The deal was executed after the split (price reduction) of an instrument, which had an open position during split announcement ... // DEAL_REASON_CLIENT => The deal was executed as a result of activation of an order placed from a desktop terminal ... // DEAL_REASON_MOBILE => The deal was executed as a result of activation of an order placed from a mobile application ... // DEAL_REASON_EXPERT => The deal was executed as a result of activation of an order placed from an MQL5 program, i.e. an Expert Advisor or a script ... // DEAL_REASON_VMARGIN => The deal was executed after charging the variation margin ... // DEAL_REASON_ROLLOVER => The deal was executed due to a rollover ... ENUM_DEAL_REASON reason; }; // // END Definitions ... // // // START Import and Inclused requirements ... // // // Includes ... #include #include "../Libraries/x-saherelm.log.lib.mq5" #include "../Libraries/x-saherelm.common.lib.mq5" // // END Import and Inclused requirements ... // // // START Overrides ... // // // XCTrade Base Class ... class XSCTradeBase : public CTrade { public: // // Modify Specific Position, by Specific Comment ... bool PositionModify( const string symbol, // Symbol const double sl, // Stop Loss const double tp, // Take Profit const string comment = "" // Comment For Modify ) { // // check stopped if (IsStopped(__FUNCTION__)) { return (false); } // // check position existence if (!SelectPosition(symbol)) { return (false); } // // clean ClearStructures(); // // setting request m_request.action = TRADE_ACTION_SLTP; m_request.symbol = symbol; m_request.magic = m_magic; m_request.sl = sl; m_request.tp = tp; m_request.position = PositionGetInteger(POSITION_TICKET); // // Specified Comment ... if (StringLen(comment) > 0) { m_request.comment = comment; } // // action and return the result return (OrderSend(m_request, m_result)); } bool PositionModify( const ulong ticket, // Position Ticket const double sl, // Stop Loss const double tp, // Take Profit const string comment = "" // Comment For Modify ) { // // check stopped if (IsStopped(__FUNCTION__)) { return (false); } // // check position existence if (!PositionSelectByTicket(ticket)) { return (false); } // // clean ClearStructures(); // // setting request m_request.action = TRADE_ACTION_SLTP; m_request.position = ticket; m_request.symbol = PositionGetString(POSITION_SYMBOL); m_request.magic = m_magic; m_request.sl = sl; m_request.tp = tp; // // Specified Comment ... if (StringLen(comment) > 0) { m_request.comment = comment; } // // action and return the result return (OrderSend(m_request, m_result)); } // // Close Specific Position, by Specific Comment ... bool PositionClose( const string symbol, // Symbol const ulong deviation, // Deviation const string comment = "" // Comment For Close ) { // bool partial_close = false; int retry_count = 10; uint retcode = TRADE_RETCODE_REJECT; // // check stopped if (IsStopped(__FUNCTION__)) { return (false); } // // clean ClearStructures(); // // check filling if (!FillingCheck(symbol)) { return (false); } // do { // // check if (SelectPosition(symbol)) { // if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { // // prepare request for close BUY position m_request.type = ORDER_TYPE_SELL; m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); } else { // // prepare request for close SELL position m_request.type = ORDER_TYPE_BUY; m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); } } else { // // position not found m_result.retcode = retcode; return (false); } // // setting request m_request.action = TRADE_ACTION_DEAL; m_request.symbol = symbol; m_request.volume = PositionGetDouble(POSITION_VOLUME); m_request.magic = m_magic; m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; m_request.position = PositionGetInteger(POSITION_TICKET); // // Specify Comment ... m_request.comment = comment; // // check volume double max_volume = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX); if (m_request.volume > max_volume) { // m_request.volume = max_volume; partial_close = true; } else { partial_close = false; } // // hedging? just send order if (IsHedging()) { return (OrderSend(m_request, m_result)); } // // order send if (!OrderSend(m_request, m_result)) { // if (--retry_count != 0) { continue; } // if (retcode == TRADE_RETCODE_DONE_PARTIAL) { m_result.retcode = retcode; } // return (false); } // //--- WARNING. If position volume exceeds the maximum volume allowed for deal, //--- and when the asynchronous trade mode is on, for safety reasons, position is closed not completely, //--- but partially. It is decreased by the maximum volume allowed for deal. if (m_async_mode) { break; } // retcode = TRADE_RETCODE_DONE_PARTIAL; if (partial_close) { Sleep(1000); } } while (partial_close); // // succeed return (true); } bool PositionClose( const ulong ticket, // Position Ticket const ulong deviation, // Deviation const string comment = "" // Comment For Close ) { // // check stopped if (IsStopped(__FUNCTION__)) { return (false); } // // check position existence if (!PositionSelectByTicket(ticket)) { return (false); } // string symbol = PositionGetString(POSITION_SYMBOL); // // clean ClearStructures(); // // check filling if (!FillingCheck(symbol)) { return (false); } // // check if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { // // prepare request for close BUY position m_request.type = ORDER_TYPE_SELL; m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); } else { // // prepare request for close SELL position m_request.type = ORDER_TYPE_BUY; m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); } // // setting request m_request.action = TRADE_ACTION_DEAL; m_request.position = ticket; m_request.symbol = symbol; m_request.volume = PositionGetDouble(POSITION_VOLUME); m_request.magic = m_magic; m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; // // Specify Comment ... m_request.comment = comment; // // close position return (OrderSend(m_request, m_result)); } // // Partial Close Specific Position, by Specific Comment ... bool PositionClosePartial( const string symbol, // Symbol const double volume, // Partial Closing Volume const ulong deviation, // Deviation const string comment = "" // Comment For Close ) { // uint retcode = TRADE_RETCODE_REJECT; // // check stopped if (IsStopped(__FUNCTION__)) { return (false); } // // for hedging mode only if (!IsHedging()) { return (false); } // // clean ClearStructures(); // // check filling if (!FillingCheck(symbol)) { return (false); } // // check if (SelectPosition(symbol)) { // if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { // // prepare request for close BUY position m_request.type = ORDER_TYPE_SELL; m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); } else { // // prepare request for close SELL position m_request.type = ORDER_TYPE_BUY; m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); } } else { // // position not found m_result.retcode = retcode; return (false); } // // check volume double position_volume = PositionGetDouble(POSITION_VOLUME); if (position_volume > volume) { position_volume = volume; } // // setting request m_request.action = TRADE_ACTION_DEAL; m_request.symbol = symbol; m_request.volume = position_volume; m_request.magic = m_magic; m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; m_request.position = PositionGetInteger(POSITION_TICKET); // // Specifieng Comment ... m_request.comment = comment; // // hedging? just send order return (OrderSend(m_request, m_result)); } bool PositionClosePartial( const ulong ticket, // Position Ticket const double volume, // Partial Closing Volume const ulong deviation, // Deviation const string comment = "" // Comment For Close ) { // // check stopped if (IsStopped(__FUNCTION__)) { return (false); } // // for hedging mode only if (!IsHedging()) { return (false); } // // check position existence if (!PositionSelectByTicket(ticket)) { return (false); } // string symbol = PositionGetString(POSITION_SYMBOL); // // clean ClearStructures(); // // check filling if (!FillingCheck(symbol)) { return (false); } // // check if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { // // prepare request for close BUY position m_request.type = ORDER_TYPE_SELL; m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); } else { // // prepare request for close SELL position m_request.type = ORDER_TYPE_BUY; m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); } // // check volume double position_volume = PositionGetDouble(POSITION_VOLUME); if (position_volume > volume) { position_volume = volume; } // // setting request m_request.action = TRADE_ACTION_DEAL; m_request.position = ticket; m_request.symbol = symbol; m_request.volume = position_volume; m_request.magic = m_magic; m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; // // Specifieng Comment ... m_request.comment = comment; // // close position return (OrderSend(m_request, m_result)); } }; // // END Overrides ... // // // a Class for Manage Trades ... class XSCTrade { // // Public ... public: // // Constructor ... void XSCTrade( int slippage, // Specify Slippage ulong magicNumber // Specify Magic Number ) { // mSlippage = slippage; mMagicNumber = magicNumber; // mPeriodPrefix = "PR"; // mTrader = new XSCTradeBase(); // mTrader.SetAsyncMode(false); mTrader.SetDeviationInPoints(mSlippage); mTrader.SetExpertMagicNumber(mMagicNumber); // // Setting Log Level ... mTrader.LogLevel(LOG_LEVEL_ERRORS); // // Prepare Trade Event Materials ... mStartDate = 0; mLastOrdersCount = OrdersTotal(); mLastDealsCount = HistoryDealsTotal(); mLastPositionsCount = PositionsTotal(); // GetDeals(mLastDeals); GetOrders(mLastOrders); GetPositions(mLastPositions); } // // Deconstructor ... void ~XSCTrade() { } // // START Event Processing ... // // // This Must be Called Every time OnTrade Event Happening ... void HandleOnTrade() { // int ordersCount = OrdersTotal(); int dealsCount = HistoryDealsTotal(); int positionsCount = PositionsTotal(); // // LogMessage("Salam"); // GetDeals(mDeals); GetOrders(mOrders); GetPositions(mPositions); // datetime currentTime = TimeCurrent(); HistorySelect(mStartDate, currentTime); // // Processing Positions ... if (positionsCount > mLastPositionsCount) { // // Position Appeared ... LogMessage("Position Appeared ..."); // // Update Deals ... dealsCount = HistoryDealsTotal(); GetDeals(mDeals); } else if (positionsCount < mLastPositionsCount) { // // Position Disappeared ... LogMessage("Position Disappeared ..."); // // Update Deals ... dealsCount = HistoryDealsTotal(); GetDeals(mDeals); } // // Processing Order Changes ... if (ordersCount > mLastOrdersCount) { // // Orders Appeared ... LogMessage("Orders Appeared ..."); } else if (ordersCount < mLastOrdersCount) { // // Orders Disappeared ... LogMessage("Orders Disappeared ..."); } // // Processing Deal Changes ... if (dealsCount > mLastDealsCount) { // // Deals Appeared ... LogMessage("Deals Appeared ..."); } else if (dealsCount > mLastDealsCount) { // // Deals Disappeard ... LogMessage("Deals Disappeard ..."); } // // Update Date after processing ... // mLastOrdersCount = OrdersTotal(); mLastDealsCount = HistoryDealsTotal(); mLastPositionsCount = PositionsTotal(); // GetDeals(mLastDeals); GetOrders(mLastOrders); GetPositions(mLastPositions); } // // END Event Processing ... // // // START Provided Functions ... // // // Count Currently Open Positions ... int PositionsCount( string symbol = "", // Specified Symbol ENUM_POSITION_TYPE type = NULL // Specified Type ) { // int result = 0; // int allPositions = 0; int longPositions = 0; int shortPositions = 0; // int positionsCount = PositionsTotal(); if (positionsCount <= 0) { return result; } // for (int i = 0; i < positionsCount; i++) { // if (!mPositionInfo.SelectByIndex(i)) { continue; } // if (mPositionInfo.Magic() != mMagicNumber) { continue; } // string positionSymbol = mPositionInfo.Symbol(); // ENUM_POSITION_TYPE positionType = mPositionInfo.PositionType(); // if ( type == NULL && StringLen(symbol) <= 0) { // allPositions++; // continue; } else if ( type != NULL && StringLen(symbol) > 0) { // if (type == positionType && symbol == positionSymbol) { // if (type == POSITION_TYPE_BUY) { longPositions++; } else { shortPositions++; } // continue; } } else if (StringLen(symbol) > 0) { // if (positionSymbol == symbol) { // allPositions++; // continue; } } else if (type != NULL) { // if (type == positionType) { // if (type == POSITION_TYPE_BUY) { longPositions++; } else { shortPositions++; } // continue; } } } // // Specify Result ... if ( type == NULL && StringLen(symbol) <= 0) { // result = allPositions; } else if ( type != NULL && StringLen(symbol) > 0) { // if (type == POSITION_TYPE_BUY) { result = longPositions; } else { result = shortPositions++; } } else if (StringLen(symbol) > 0) { // result = allPositions; } else if (type != NULL) { // if (type == POSITION_TYPE_BUY) { result = longPositions; } else { result = shortPositions; } } // return result; } // // Retrieve Max In Profit Position Ticket ... ulong GetMaxInProfitPosition( string symbol = "", // Specified Symbol ENUM_POSITION_TYPE type = NULL // Specified Type ) { // ulong result = -1; // double profit = 0; // int positionsCount = PositionsTotal(); if (positionsCount <= 0) { return result; } // for (int i = 0; i < positionsCount; i++) { // if (!mPositionInfo.SelectByIndex(i)) { continue; } // if (mPositionInfo.Magic() != mMagicNumber) { continue; } // ulong positionTicket = mPositionInfo.Ticket(); // string positionSymbol = mPositionInfo.Symbol(); // double positionProfit = mPositionInfo.Profit(); double positionAbsProfit = MathAbs(positionProfit); if (positionProfit <= 0) { continue; } // ENUM_POSITION_TYPE positionType = mPositionInfo.PositionType(); // if ( type == NULL && StringLen(symbol) <= 0) { // if (profit < positionAbsProfit) { // result = positionTicket; profit = positionAbsProfit; } // continue; } else if ( type != NULL && StringLen(symbol) > 0) { // if (type == positionType && symbol == positionSymbol) { // if (type == POSITION_TYPE_BUY) { // if (profit < positionAbsProfit) { // result = positionTicket; profit = positionAbsProfit; } } else { // if (profit < positionAbsProfit) { // result = positionTicket; profit = positionAbsProfit; } } // continue; } } else if (StringLen(symbol) > 0) { // if (positionSymbol == symbol) { // if (profit < positionAbsProfit) { // result = positionTicket; profit = positionAbsProfit; } // continue; } } else if (type != NULL) { // if (type == positionType) { // if (type == POSITION_TYPE_BUY) { // if (profit < positionAbsProfit) { // result = positionTicket; profit = positionAbsProfit; } } else { // if (profit < positionAbsProfit) { // result = positionTicket; profit = positionAbsProfit; } } // continue; } } } // return result; } // // Retrieve Max In DrawDown Position Ticket ... ulong GetMaxInDrawDownPosition( string symbol = "", // Specified Symbol ENUM_POSITION_TYPE type = NULL // Specified Type ) { // ulong result = -1; // double profit = 0; // int positionsCount = PositionsTotal(); if (positionsCount <= 0) { return result; } // for (int i = 0; i < positionsCount; i++) { // if (!mPositionInfo.SelectByIndex(i)) { continue; } // if (mPositionInfo.Magic() != mMagicNumber) { continue; } // ulong positionTicket = mPositionInfo.Ticket(); // string positionSymbol = mPositionInfo.Symbol(); // double positionProfit = mPositionInfo.Profit(); double positionAbsProfit = MathAbs(positionProfit); if (positionProfit >= 0) { continue; } // ENUM_POSITION_TYPE positionType = mPositionInfo.PositionType(); // if ( type == NULL && StringLen(symbol) <= 0) { // if (profit < positionAbsProfit) { // result = positionTicket; profit = positionAbsProfit; } // continue; } else if ( type != NULL && StringLen(symbol) > 0) { // if (type == positionType && symbol == positionSymbol) { // if (type == POSITION_TYPE_BUY) { // if (profit < positionAbsProfit) { // result = positionTicket; profit = positionAbsProfit; } } else { // if (profit < positionAbsProfit) { // result = positionTicket; profit = positionAbsProfit; } } // continue; } } else if (StringLen(symbol) > 0) { // if (positionSymbol == symbol) { // if (profit < positionAbsProfit) { // result = positionTicket; profit = positionAbsProfit; } // continue; } } else if (type != NULL) { // if (type == positionType) { // if (type == POSITION_TYPE_BUY) { // if (profit < positionAbsProfit) { // result = positionTicket; profit = positionAbsProfit; } } else { // if (profit < positionAbsProfit) { // result = positionTicket; profit = positionAbsProfit; } } // continue; } } } // return result; } // // Retrieve Specific Position's Profit ... double GetPositionProfit( const ulong ticket // Specified Position Ticket ) { // double result = 0; // int positionsCount = PositionsTotal(); if (positionsCount <= 0) { return result; } // for (int i = 0; i < positionsCount; i++) { // if (!mPositionInfo.SelectByIndex(i)) { continue; } // if (mPositionInfo.Magic() != mMagicNumber) { continue; } // ulong positionTicket = mPositionInfo.Ticket(); if (positionTicket != ticket) { continue; } // result = mPositionInfo.Profit(); break; } // return result; } // // Retrieve Specific Position's OpenDate ... datetime GetPositionOpenDate( const ulong ticket // Specified Position Ticket ) { // datetime result = 0; // int positionsCount = PositionsTotal(); if (positionsCount <= 0) { return result; } // for (int i = 0; i < positionsCount; i++) { // if (!mPositionInfo.SelectByIndex(i)) { continue; } // if (mPositionInfo.Magic() != mMagicNumber) { continue; } // ulong positionTicket = mPositionInfo.Ticket(); if (positionTicket != ticket) { continue; } // result = mPositionInfo.Time(); break; } // return result; } // // Retrieve Specific Position's Comment ... string GetPositionComment( const ulong ticket // Specified Position Ticket ) { // string result = ""; // int positionsCount = PositionsTotal(); if (positionsCount <= 0) { return result; } // for (int i = 0; i < positionsCount; i++) { // if (!mPositionInfo.SelectByIndex(i)) { continue; } // if (mPositionInfo.Magic() != mMagicNumber) { continue; } // ulong positionTicket = mPositionInfo.Ticket(); if (positionTicket != ticket) { continue; } // result = mPositionInfo.Comment(); break; } // return result; } // // Retrieve All Open Positions Profit ... double GetPositionsProfit( string symbol = "", // Specified Symbol ENUM_POSITION_TYPE type = NULL // Specified Type ) { // double result = 0; // double profit = 0; // int positionsCount = PositionsTotal(); if (positionsCount <= 0) { return result; } // for (int i = 0; i < positionsCount; i++) { // if (!mPositionInfo.SelectByIndex(i)) { continue; } // if (mPositionInfo.Magic() != mMagicNumber) { continue; } // ulong positionTicket = mPositionInfo.Ticket(); // string positionSymbol = mPositionInfo.Symbol(); // double positionProfit = mPositionInfo.Profit(); // ENUM_POSITION_TYPE positionType = mPositionInfo.PositionType(); // if ( type == NULL && StringLen(symbol) <= 0) { // if (profit < positionProfit) { // result += positionProfit; } // continue; } else if ( type != NULL && StringLen(symbol) > 0) { // if (type == positionType && symbol == positionSymbol) { // if (type == POSITION_TYPE_BUY) { // if (profit < positionProfit) { // result += positionProfit; } } else { // if (profit < positionProfit) { // result += positionProfit; } } // continue; } } else if (StringLen(symbol) > 0) { // if (positionSymbol == symbol) { // if (profit < positionProfit) { // result += positionProfit; } // continue; } } else if (type != NULL) { // if (type == positionType) { // if (type == POSITION_TYPE_BUY) { // if (profit < positionProfit) { // result += positionProfit; } } else { // if (profit < positionProfit) { // result += positionProfit; } } // continue; } } } // return result; } // // Find Oldes Position ... ulong GetOldestPosition( string symbol = "", // Specified Symbol ENUM_POSITION_TYPE type = NULL // Specified Type ) { // ulong result = 0; // int age = 0; // int positionsCount = PositionsTotal(); if (positionsCount <= 0) { return result; } // for (int i = 0; i < positionsCount; i++) { // if (!mPositionInfo.SelectByIndex(i)) { continue; } // if (mPositionInfo.Magic() != mMagicNumber) { continue; } // ulong positionTicket = mPositionInfo.Ticket(); // string positionSymbol = mPositionInfo.Symbol(); // double positionProfit = mPositionInfo.Profit(); double positionAbsProfit = MathAbs(positionProfit); if (positionProfit >= 0) { continue; } // ENUM_POSITION_TYPE positionType = mPositionInfo.PositionType(); // string positionComment = mPositionInfo.Comment(); ENUM_TIMEFRAMES positionPeriod = ExtractPositionPeriod(positionComment); // // Calculate Position's Age ... datetime positionOpenTime = mPositionInfo.Time(); // // Retrieve Trade Open Bar Index based on Current Period ... int positionOpenBarIndex = iBarShift( positionSymbol, positionPeriod, positionOpenTime); // // Calculate Trade Life ... int positionAge = MathAbs(0 - positionOpenBarIndex); // if ( type == NULL && StringLen(symbol) <= 0) { // if (age < positionAge) { // age = positionAge; result = positionTicket; } // continue; } else if ( type != NULL && StringLen(symbol) > 0) { // if (type == positionType && symbol == positionSymbol) { // if (type == POSITION_TYPE_BUY) { // if (age < positionAge) { // age = positionAge; result = positionTicket; } } else { // if (age < positionAge) { // age = positionAge; result = positionTicket; } } // continue; } } else if (StringLen(symbol) > 0) { // if (positionSymbol == symbol) { // if (age < positionAge) { // age = positionAge; result = positionTicket; } // continue; } } else if (type != NULL) { // if (type == positionType) { // if (type == POSITION_TYPE_BUY) { // if (age < positionAge) { // age = positionAge; result = positionTicket; } } else { // if (age < positionAge) { // age = positionAge; result = positionTicket; } } // continue; } } } // return result; } // // Force Open a Buy/Long Position ... bool Buy( string symbol, // Specified Symbol ENUM_TIMEFRAMES period, // Specified Trade's Period double volume, // position volume double price, // execution price double sl = 0, // stop loss price double tp = 0, // take profit price string comment = "" // comment ) { // bool result = false; // string mPeriodStr = GeneratePositionPeriodComment(period); // comment += mPeriodStr; // result = mTrader.Buy( volume, symbol, price, sl, tp, comment); // return result; } // // Send BUY LIMIT order ... bool BuyLimit( string symbol, // Specified Symbol ENUM_TIMEFRAMES period, // Specified Trade's Period double volume, // order volume double price, // order price double sl = 0.0, // stop loss price double tp = 0.0, // take profit price ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime datetime expiration = 0, // order expiration time string comment = "" // comment ) { // bool result = false; // string mPeriodStr = GeneratePositionPeriodComment(period); // comment += mPeriodStr; // result = mTrader.BuyLimit( volume, price, symbol, sl, tp, typeTime, expiration, comment); // return result; } // // Send BUY STOP order ... bool BuyStop( string symbol, // Specified Symbol ENUM_TIMEFRAMES period, // Specified Trade's Period double volume, // order volume double price, // order price double sl = 0.0, // stop loss price double tp = 0.0, // take profit price ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime datetime expiration = 0, // order expiration time string comment = "" // comment ) { // bool result = false; // string mPeriodStr = GeneratePositionPeriodComment(period); // comment += mPeriodStr; // result = mTrader.BuyStop( volume, price, symbol, sl, tp, typeTime, expiration, comment); // return result; } // // Force Open a Sell/Short Position ... bool Sell( string symbol, // Specified Symbol ENUM_TIMEFRAMES period, // Specified Trade's Period double volume, // position volume double price, // execution price double sl = 0, // stop loss price double tp = 0, // take profit price string comment = "" // comment ) { // bool result = false; // string mPeriodStr = GeneratePositionPeriodComment(period); // comment += mPeriodStr; // result = mTrader.Sell( volume, symbol, price, sl, tp, comment); // return result; } // // Send SELL LIMIT order ... bool SellLimit( string symbol, // Specified Symbol ENUM_TIMEFRAMES period, // Specified Trade's Period double volume, // order volume double price, // order price double sl = 0.0, // stop loss price double tp = 0.0, // take profit price ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime datetime expiration = 0, // order expiration time string comment = "" // comment ) { // bool result = false; // string mPeriodStr = GeneratePositionPeriodComment(period); // comment += mPeriodStr; // result = mTrader.SellLimit( volume, price, symbol, sl, tp, typeTime, expiration, comment); // return result; } // // Send SELL STOP order ... bool SellStop( string symbol, // Specified Symbol ENUM_TIMEFRAMES period, // Specified Trade's Period double volume, // order volume double price, // order price double sl = 0.0, // stop loss price double tp = 0.0, // take profit price ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime datetime expiration = 0, // order expiration time string comment = "" // comment ) { // bool result = false; // string mPeriodStr = GeneratePositionPeriodComment(period); // comment += mPeriodStr; // result = mTrader.SellStop( volume, price, symbol, sl, tp, typeTime, expiration, comment); // return result; } // // Modify Position ... bool Modify( const ulong ticket, // position ticket double sl = 0, // stop loss price double tp = 0, // take profit string comment = "" // comment ) { // bool result = false; // // Validate Args ... if (tp <= 0 && sl <= 0) { result = false; return result; } // // Use Position Comment when there isn't new One ... if (StringLen(comment) == 0) { comment = GetPositionComment(ticket); } // result = mTrader.PositionModify( ticket, sl, tp, comment); // return result; } // // Close Position By Ticket ... bool Close( ulong ticket, // Position Ticket string comment = "" // Close Position By Specific Comment ) { // bool result = false; // // Try to Select Position ... if (!mPositionInfo.SelectByTicket(ticket)) { return result; } // // Close Position By Specific Comment ... result = mTrader.PositionClose( ticket, mSlippage, comment); // return result; } // // Close All Positions ... void CloseAllPositions( string comment = "" // Close Position By Specific Comment ) { // int positionsCount = PositionsTotal(); if (positionsCount <= 0) { return; } // for (int i = 0; i < positionsCount; i++) { // if (!mPositionInfo.SelectByIndex(i)) { continue; } // if (mPositionInfo.Magic() != mMagicNumber) { continue; } // ulong positionTicket = mPositionInfo.Ticket(); Close( positionTicket, comment); } } // // Close Partial By Ticket ... bool ClosePartial( ulong ticket, // Position Ticket double volume, // Volume Size for Partial Closing string comment = "" // Close Position By Specific Comment ) { // bool result = false; // if (!mPositionInfo.SelectByTicket(ticket)) { return result; } // result = mTrader.PositionClosePartial( ticket, volume, mSlippage, comment); // return result; } // // Find Position Open Bar Index ... int GetPositionOpenBarIndex( const ulong ticket // position ticket ) { // int result = -1; // int positionsCount = PositionsTotal(); if (positionsCount <= 0) { return result; } // for (int i = 0; i < positionsCount; i++) { // if (!mPositionInfo.SelectByIndex(i)) { continue; } // if (mPositionInfo.Magic() != mMagicNumber) { continue; } // ulong positionTicket = mPositionInfo.Ticket(); if (positionTicket != ticket) { continue; } // string symbol = mPositionInfo.Symbol(); datetime openAt = mPositionInfo.Time(); string comment = mPositionInfo.Comment(); ENUM_TIMEFRAMES period = ExtractPositionPeriod(comment); // result = iBarShift( symbol, period, openAt); } // return result; } // // Retrieve Positions as an Array ... void GetPositions( XPosition &result[] // Hold Result ... ) { // Clear(result); // int positionsCount = PositionsTotal(); if (positionsCount <= 0) { return; } // for (int i = 0; i < positionsCount; i++) { // if (!mPositionInfo.SelectByIndex(i)) { continue; } // if (mPositionInfo.Magic() != mMagicNumber) { continue; } // ulong magic = mPositionInfo.Magic(); ulong ticket = mPositionInfo.Ticket(); string symbol = mPositionInfo.Symbol(); datetime openAt = mPositionInfo.Time(); double swap = mPositionInfo.Swap(); double sl = mPositionInfo.StopLoss(); double tp = mPositionInfo.TakeProfit(); double profit = mPositionInfo.Profit(); double volume = mPositionInfo.Volume(); string comment = mPositionInfo.Comment(); double entry = mPositionInfo.PriceOpen(); double price = mPositionInfo.PriceCurrent(); double commission = mPositionInfo.Commission(); ENUM_POSITION_TYPE type = mPositionInfo.PositionType(); ENUM_TIMEFRAMES period = ExtractPositionPeriod(comment); // XPosition iPosition = {}; // iPosition.tp = tp; iPosition.sl = sl; iPosition.swap = swap; iPosition.type = type; iPosition.magic = magic; iPosition.entry = entry; iPosition.price = price; iPosition.ticket = ticket; iPosition.symbol = symbol; iPosition.period = period; iPosition.volume = volume; iPosition.openAt = openAt; iPosition.profit = profit; iPosition.comment = comment; iPosition.commission = commission; // Add( iPosition, result); } } // void GetPositions( XPosition &result[], // Hold Result ... string symbol, // Trading Symbol ... ENUM_TIMEFRAMES period // Trading Period ... ) { // Clear(result); // int positionsCount = PositionsTotal(); if (positionsCount <= 0) { return; } // XPosition allPositions[]; GetPositions(allPositions); // for (int i = 0; i < positionsCount; i++) { // XPosition iPosition = allPositions[i]; // if (symbol != iPosition.symbol) { continue; } // ENUM_TIMEFRAMES positionPeriod = ExtractPositionPeriod(iPosition.comment); if (period != positionPeriod) { continue; } // Add( iPosition, result); } } // // Retrieve in Profit Positions ... void GetInProfitPositions( XPosition &result[] // Hold Result ... ) { // Clear(result); // XPosition allPositions[]; GetPositions(allPositions); int positionsCount = ArraySize(allPositions); if (positionsCount <= 0) { return; } // for (int i = 0; i < positionsCount; i++) { // XPosition iPosition = allPositions[i]; // if (iPosition.profit > 0) { Add( iPosition, result); } } } // // Retrieve in Drawdown Positions ... void GetInDrawdownPositions( XPosition &result[] // Hold Result ... ) { // Clear(result); // XPosition allPositions[]; GetPositions(allPositions); int positionsCount = ArraySize(allPositions); if (positionsCount <= 0) { return; } // for (int i = 0; i < positionsCount; i++) { // XPosition iPosition = allPositions[i]; // if (iPosition.profit < 0) { Add( iPosition, result); } } } // // Close a Collection Of Positions ... void ClosePositions( XPosition &positions[], // Positions to Close ... string comment = "" // Specified Comment ... ) { // int positionsCount = ArraySize(positions); if (positionsCount <= 0) { return; } // for (int i = 0; i < positionsCount; i++) { // XPosition iPosition = positions[i]; // Close( iPosition.ticket, comment); } } // // Retrieve All Orders ... void GetOrders(XOrder &result[]) { // Clear(result); // int ordersCount = OrdersTotal(); if (ordersCount <= 0) { return; } // // Since Orders may be so more than positions ... // start Orders Collectiong Loops reverse ... for (int i = ordersCount - 1; i >= 0; i--) { // if (!mPositionInfo.SelectByIndex(i)) { continue; } // if (mOrderInfo.Magic() != mMagicNumber) { continue; } // // Reading Order Info ... long magic = mOrderInfo.Magic(); double sl = mOrderInfo.StopLoss(); ulong ticket = mOrderInfo.Ticket(); double tp = mOrderInfo.TakeProfit(); string smybol = mOrderInfo.Symbol(); string comment = mOrderInfo.Comment(); long pocitionID = mOrderInfo.PositionId(); double openPrice = mOrderInfo.PriceOpen(); datetime setupAt = mOrderInfo.TimeSetup(); datetime executedAt = mOrderInfo.TimeDone(); ENUM_ORDER_STATE state = mOrderInfo.State(); ENUM_ORDER_TYPE type = mOrderInfo.OrderType(); double currentPrice = mOrderInfo.PriceCurrent(); datetime expiredAt = mOrderInfo.TimeExpiration(); double initialVolume = mOrderInfo.VolumeInitial(); double currentVolume = mOrderInfo.VolumeCurrent(); double stopLimitPrice = mOrderInfo.PriceStopLimit(); ENUM_ORDER_TYPE_TIME lifetime = mOrderInfo.TypeTime(); ENUM_ORDER_TYPE_FILLING filling = mOrderInfo.TypeFilling(); // // Now Create an instance of XOrder struct and fill it by // retrieved data, and add it to results ... XOrder iOrder = {}; // iOrder.sl = sl; iOrder.tp = tp; iOrder.type = type; iOrder.state = state; iOrder.magic = magic; iOrder.ticket = ticket; iOrder.smybol = smybol; iOrder.setupAt = setupAt; iOrder.comment = comment; iOrder.filling = filling; iOrder.lifetime = lifetime; iOrder.expiredAt = expiredAt; iOrder.openPrice = openPrice; iOrder.pocitionID = pocitionID; iOrder.executedAt = executedAt; iOrder.currentPrice = currentPrice; iOrder.initialVolume = initialVolume; iOrder.currentVolume = currentVolume; iOrder.stopLimitPrice = stopLimitPrice; // Add( iOrder, result); } } // // Retrieve All Deals ... void GetDeals(XDeal &result[]) { // Clear(result); // int dealsCount = HistoryDealsTotal(); if (dealsCount <= 0) { return; } // for (int i = dealsCount - 1; i >= 0; i--) { // if (!mDealInfo.SelectByIndex(i)) { continue; } // if (mDealInfo.Magic() != mMagicNumber) { continue; } // // Reading Order Info ... double swap = mDealInfo.Swap(); ulong magic = mDealInfo.Magic(); ulong order = mDealInfo.Order(); ulong ticket = mDealInfo.Ticket(); datetime time = mDealInfo.Time(); double price = mDealInfo.Price(); string symbol = mDealInfo.Symbol(); double profit = mDealInfo.Profit(); double volume = mDealInfo.Volume(); string comment = mDealInfo.Comment(); ulong positionId = mDealInfo.PositionId(); ENUM_DEAL_ENTRY entry = mDealInfo.Entry(); double commission = mDealInfo.Commission(); ENUM_DEAL_TYPE type = mDealInfo.DealType(); ENUM_DEAL_REASON reason = (ENUM_DEAL_REASON)HistoryDealGetInteger( ticket, DEAL_REASON); // XDeal iDeal = {}; // iDeal.swap = swap; iDeal.time = time; iDeal.type = type; iDeal.magic = magic; iDeal.entry = entry; iDeal.order = order; iDeal.price = price; iDeal.ticket = ticket; iDeal.symbol = symbol; iDeal.profit = profit; iDeal.volume = volume; iDeal.reason = reason; iDeal.comment = comment; iDeal.positionId = positionId; iDeal.commission = commission; // Add( iDeal, result); } } // // Generate String Representation Of Position's Time Frame ... string GeneratePositionPeriodComment(ENUM_TIMEFRAMES period) { // string result = mPeriodPrefix + "(" + ToString(period) + ")"; // return result; } // // Extract Position Time Frame From it's Comment ... ENUM_TIMEFRAMES ExtractPositionPeriod(string comment) { // ENUM_TIMEFRAMES result = _Period; // if (StringLen(comment) <= 0) { return result; } // string periodStr = ExtractString( comment, mPeriodPrefix + "(", ")"); if (StringLen(periodStr) <= 0) { return result; } // result = ToPeriod(periodStr); // return result; } // // Retrieve Last Open Position Ticket ... ulong GetLastOpenPositionTicket() { // ulong result = 0; int positionsCount = PositionsTotal(); if (positionsCount <= 0) { return result; } // result = PositionGetTicket(PositionsTotal() - 1); // return result; } // // END Provided Functions ... // // // Protected ... protected: // // Private ... private: // // using deviation, it must be in Point ... int mSlippage; // // using magic number ... ulong mMagicNumber; // // using CTrade instance ... XSCTradeBase mTrader; // // Deals Info ... CDealInfo mDealInfo; // // Order Info ... COrderInfo mOrderInfo; // // using PositionInfo instance ... CPositionInfo mPositionInfo; // // ADDITIONAL Data ... // string mPeriodPrefix; // // Trade Processing ... datetime mStartDate; int mLastDealsCount; int mLastOrdersCount; int mLastPositionsCount; // XDeal mDeals[]; XOrder mOrders[]; XPosition mPositions[]; // XDeal mLastDeals[]; XOrder mLastOrders[]; XPosition mLastPositions[]; }; // // START Usefull Functions ... // // // Add Specific XPosition to Specified Array ... void Add( XDeal &item, XDeal &buffer[]) { // ArrayResize( buffer, ArraySize(buffer) + 1); // buffer[ArraySize(buffer) - 1] = item; } void Add( XOrder &item, XOrder &buffer[]) { // ArrayResize( buffer, ArraySize(buffer) + 1); // buffer[ArraySize(buffer) - 1] = item; } void Add( XPosition &item, XPosition &buffer[]) { // ArrayResize( buffer, ArraySize(buffer) + 1); // buffer[ArraySize(buffer) - 1] = item; } // // Clear All Items Inside Array ... void Clear(XDeal &buffer[]) { // ArrayFree(buffer); ArrayResize(buffer, 0); } void Clear(XOrder &buffer[]) { // ArrayFree(buffer); ArrayResize(buffer, 0); } void Clear(XPosition &buffer[]) { // ArrayFree(buffer); ArrayResize(buffer, 0); } // // END Usefull Functions ... //