/////////////////////////////////////////////////////// // // SaherElm IT Center MQL5 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; }; // // Model OnTrade Event Handler Result on XCTrade Class ... struct XOnTradeHandlerState { // bool hasNewDeal; int newDeals; // bool hasNewOrder; int newOrders; // bool hasNewPosition; int newPositions; // bool hasNewHistoryOrder; int newHistoryOrders; }; // typedef void (*OnDealsChanged)(int count); // typedef void (*OnOrdersChanged)(int count); // typedef void (*OnPositionsChanged)(int count); // typedef void (*OnStopLoss)(const XDeal &deal); typedef void (*OnTakeProfit)(const XDeal &deal); // typedef void (*OnTradeStateChanged)(const XOnTradeHandlerState &state); // // END Definitions ... // // // START Import and Inclused requirements ... // // // Includes ... #include #include "../Libraries/x-saherelm.log.lib.mq5" #include "../Libraries/x-saherelm.common.lib.mq5" #include "../Libraries/x-saherelm.seriallizer.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 ... // mDaysForRead = 1; mScanStarted = false; // // Reset On Trade Counter ... ResetOnTradeContext(); // // Init On Trade Context ... InitOnTradeContext(); } // // Deconstructor ... void ~XSCTrade() { } // // START Event Processing ... // // // This Must be Called Every time OnTrade Event Happening ... XOnTradeHandlerState HandleOnTrade() { // // Handle OnTrade Event ... XOnTradeHandlerState state = {}; HandleOnTradeEvent(state); if ( !state.hasNewDeal && !state.hasNewOrder && !state.hasNewPosition && !state.hasNewHistoryOrder) { return state; } // // STATE ... // // Notfy Trade State Changed Event ... NotifyTradeStateChangeEvent(state); // // DEALS ... if (state.hasNewDeal) { // // Notfy Deals Changed Event ... NotifyDealsChangeEvent(state.newDeals); // // Retrieve Last Deal ... XDeal deals[]; GetDeals(deals); int dealsCount = ArraySize(deals); if (dealsCount > 0) { // XDeal lastDeal = deals[0]; // if (lastDeal.reason == DEAL_REASON_TP) { NotifyTakeProfitEvent(lastDeal); } else if (lastDeal.reason == DEAL_REASON_SL) { NotifyStopLossEvent(lastDeal); } } } // // ORDERS ... if (state.hasNewOrder || state.hasNewHistoryOrder) { // // Notfy Orders Changed Event ... NotifyOrdersChangeEvent(state.newOrders + state.newHistoryOrders); } // // POSITIONS ... if (state.hasNewPosition) { // // Notfy Positions Changed Event ... NotifyPositionsChangeEvent(state.newPositions); } // return state; } // // Process On Trade Requirement void HandleOnTradeEvent( XOnTradeHandlerState &result // Hold's Result ) { // if (mScanStarted) { ProcessOnTradeContext(result); } else { InitOnTradeContext(); } } // // Event Emitters ... // // STATE Changed ... // // Clear Trade State Changed Event Handlers ... void ClearOnTradeStateChangedEventHandlers() { // ArrayFree(mTradeStateChangedEventHandlers); // ArrayResize(mTradeStateChangedEventHandlers, 0); } // // Add New Deals Changed Event Handler ... void AddOnTradeStateChangedEventHandler(OnTradeStateChanged handler) { // ArrayResize( mTradeStateChangedEventHandlers, ArraySize(mTradeStateChangedEventHandlers) + 1); // mTradeStateChangedEventHandlers[ArraySize(mTradeStateChangedEventHandlers) - 1] = handler; } // // DEALS ... // // Clear Deals Changed Event Handlers ... void ClearOnDealsChangedEventHandlers() { // ArrayFree(mDealsChangedEventHandlers); // ArrayResize(mDealsChangedEventHandlers, 0); } // // Add New Deals Changed Event Handler ... void AddOnDealsChangedEventHandler(OnDealsChanged handler) { // ArrayResize( mDealsChangedEventHandlers, ArraySize(mDealsChangedEventHandlers) + 1); // mDealsChangedEventHandlers[ArraySize(mDealsChangedEventHandlers) - 1] = handler; } // // ORDERS ... // // Clear Orders Changed Event Handlers ... void ClearOnOrdersChangedEventHandlers() { // ArrayFree(mOrdersChangedEventHandlers); // ArrayResize(mOrdersChangedEventHandlers, 0); } // // Add New Orders Changed Event Handler ... void AddOnOrdersChangedEventHandler(OnOrdersChanged handler) { // ArrayResize( mOrdersChangedEventHandlers, ArraySize(mOrdersChangedEventHandlers) + 1); // mOrdersChangedEventHandlers[ArraySize(mOrdersChangedEventHandlers) - 1] = handler; } // // POSITIONS ... // // Clear Positions Changed Event Handlers ... void ClearOnPositionsChangedEventHandlers() { // ArrayFree(mPositionsChangedEventHandlers); // ArrayResize(mPositionsChangedEventHandlers, 0); } // // Add New Positions Changed Event Handler ... void AddOnPositionsChangedEventHandler(OnPositionsChanged handler) { // ArrayResize( mPositionsChangedEventHandlers, ArraySize(mPositionsChangedEventHandlers) + 1); // mPositionsChangedEventHandlers[ArraySize(mPositionsChangedEventHandlers) - 1] = handler; } // // TPSL ... // // Clear Stop Loss Event Handlers ... void ClearOnStopLossEventHandlers() { // ArrayFree(mStopLossEventHandlers); // ArrayResize(mStopLossEventHandlers, 0); } // // Add New Stop Loss Event Handler ... void AddOnStopLossEventHandler(OnStopLoss handler) { // ArrayResize( mStopLossEventHandlers, ArraySize(mStopLossEventHandlers) + 1); // mStopLossEventHandlers[ArraySize(mStopLossEventHandlers) - 1] = handler; } // // Clear Take Profit Event Handlers ... void ClearOnTakeProfitEventHandlers() { // ArrayFree(mTakeProfitEventHandlers); // ArrayResize(mTakeProfitEventHandlers, 0); } // // Add New Stop Loss Event Handler ... void AddOnTakeProfitEventHandler(OnTakeProfit handler) { // ArrayResize( mTakeProfitEventHandlers, ArraySize(mTakeProfitEventHandlers) + 1); // mTakeProfitEventHandlers[ArraySize(mTakeProfitEventHandlers) - 1] = handler; } // // 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; // 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) { // result += positionProfit; // continue; } else if ( type != NULL && StringLen(symbol) > 0) { // if (type == positionType && symbol == positionSymbol) { // if (type == POSITION_TYPE_BUY) { result += positionProfit; } else { result += positionProfit; } // continue; } } else if (StringLen(symbol) > 0) { // if (positionSymbol == symbol) { result += positionProfit; // continue; } } else if (type != NULL) { // if (type == positionType) { // if (type == POSITION_TYPE_BUY) { result += positionProfit; } else { 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; } // bool GetPosition( XPosition &position, // Holds result ... ulong ticket // Required Position Ticket ... ) { // bool result = false; // XPosition positions[]; GetPositions(positions); int positionsCount = ArraySize(positions); if (positionsCount <= 0) { return result; } // for (int i = 0; i < positionsCount; i++) { // XPosition iPosition = positions[i]; // result = iPosition.ticket == ticket; if (!result) { continue; } // position = iPosition; break; } // return result; } // // Retrieve Positions as an Array ... void GetPositions( XPosition &result[] // Hold Result ... ) { // Clean(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 ... ) { // Clean(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); } } // // Execute a Signal ... bool ExecuteSignal( XSignal &signal, // Signal ... string comment = "", // Position Comment ... ENUM_ORDER_TYPE_TIME lifetime = ORDER_TIME_GTC, // Order LifeTime ... datetime expiration = 0 // order expiration time ) { // bool result = false; // double currentEntry = GetEntry( signal.symbol, signal.type); bool isLong = IsLong(signal.type); // ResetLastError(); // if (signal.mode == X_ORDER_MODE_MARKET) { // // Execute MArket Orders ... if (isLong) { // result = Buy( signal.symbol, signal.period, signal.volume, signal.entry, signal.sl, signal.tp, comment); } else { // result = Sell( signal.symbol, signal.period, signal.volume, signal.entry, signal.sl, signal.tp, comment); } } else if (signal.mode == X_ORDER_MODE_LIMIT) { // // Execute Limit Orders ... // // Check Conditions ... // // Check Price ... result = isLong ? signal.entry < currentEntry : signal.entry > currentEntry; if (!result) { return result; } // // Check Expiration Date ... result = (lifetime == ORDER_TIME_SPECIFIED || lifetime == ORDER_TIME_SPECIFIED_DAY) ? expiration > 0 : true; if (!result) { return result; } // if (isLong) { // result = BuyLimit( signal.symbol, signal.period, signal.volume, signal.entry, signal.sl, signal.tp, lifetime, expiration, comment); } else { // result = SellLimit( signal.symbol, signal.period, signal.volume, signal.entry, signal.sl, signal.tp, lifetime, expiration, comment); } } else if (signal.mode == X_ORDER_MODE_STOP) { // // Execute Stop Orders ... // // Check Conditions ... // // Check Price ... result = isLong ? signal.entry > currentEntry : signal.entry < currentEntry; if (!result) { return result; } // // Check Expiration Date ... result = (lifetime == ORDER_TIME_SPECIFIED || lifetime == ORDER_TIME_SPECIFIED_DAY) ? expiration > 0 : true; if (!result) { return result; } // if (isLong) { // result = BuyStop( signal.symbol, signal.period, signal.volume, signal.entry, signal.sl, signal.tp, lifetime, expiration, comment); } else { // result = SellStop( signal.symbol, signal.period, signal.volume, signal.entry, signal.sl, signal.tp, lifetime, expiration, comment); } } // if (!result) { // LogMessage("Error: " + (string)GetLastError() + ", " + GetErrorDescription(GetLastError())); } // return result; } // // Execute a Collection of Signals ... int ExecuteSignals( const XSignal &signals[], // an Array of Signals ... string comment = "", // Position Comment ... ENUM_ORDER_TYPE_TIME lifetime = ORDER_TIME_GTC, // Order LifeTime ... datetime expiration = 0 // order expiration time ) { // int result = 0; // int signalsCount = ArraySize(signals); if (signalsCount <= 0) { return result; } // for (int i = 0; i < signalsCount; i++) { // XSignal iSignal = signals[i]; // bool isExecuted = ExecuteSignal( iSignal, comment, lifetime, expiration); // if (isExecuted) { result++; } } // return result; } // // Retrieve in Profit Positions ... void GetInProfitPositions( XPosition &result[] // Hold Result ... ) { // Clean(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 ... ) { // Clean(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[], // Holdes Result .... string symbol, // Trading Symbol ... ENUM_TIMEFRAMES period, // Trading TimeFrame ... ENUM_ORDER_STATE state = NULL // Order State ... ) { // Clean(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 (!mOrderInfo.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 oSymbol = 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 oState = 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(); // if (StringLen(symbol) > 0 && symbol != oSymbol) { continue; } // ENUM_TIMEFRAMES oPeriod = ExtractPositionPeriod(comment); if (period != NULL && period != oPeriod) { continue; } // if (state != NULL && oState != state) { continue; } // // 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.magic = magic; iOrder.state = oState; iOrder.ticket = ticket; iOrder.smybol = oSymbol; 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); } } // int OrdersCount() { return OrdersTotal(); } // // Cancel Specific Orders ... bool CancelOrders( XOrder &orders[]) { // bool result = false; // int ordersCount = ArraySize(orders); if (ordersCount <= 0) { return result; } // for (int i = 0; i < ordersCount; i++) { // XOrder iOrder = orders[i]; // bool isDeleted = mTrader.OrderDelete(iOrder.ticket); if (isDeleted && !result) { result = isDeleted; } } // return result; } // // Retrieve All Deals ... void GetDeals(XDeal &result[]) { // Clean(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; } // // Retrieve Last Placed Order Ticket ... ulong GetLastPlacedOrderTicket() { // ulong result = 0; int ordersCount = OrdersTotal(); if (ordersCount <= 0) { return result; } // if (mOrderInfo.SelectByIndex(ordersCount - 1)) { result = mOrderInfo.Ticket(); } // return result; } // // SUPPORT Signals ... // // Find an Specific Position Has Support Signal Or not ... bool HasSupport(ulong ticket) { // bool result = false; // int count = PositionsCount(); if (count <= 1) { return result; } // XPosition position; result = GetPosition( position, ticket); if (!result) { return result; } // XPosition positions[]; GetPositions(positions); for (int i = 0; i < count; i++) { // XPosition iPosition = positions[i]; // string supportTicketStr = ExtractParentTicketOfSupport(iPosition.comment); if (StringLen(supportTicketStr) == 0) { continue; } // ulong parentTicket = (ulong)supportTicketStr; // result = parentTicket == ticket && iPosition.ticket != parentTicket; if (result) { break; } } // return result; } // // Get All Support Positions for Specific Position ... bool GetSupportPositions( ulong ticket, // Parent Position Ticket XPosition &supports[] // Holds Result ... ) { // bool result = false; // Clean(supports); // int count = PositionsCount(); if (count <= 0) { return result; } // XPosition parentPosition; bool positionExist = GetPosition( parentPosition, ticket); if (!positionExist) { return result; } // bool hasSupport = HasSupport(ticket); if (!hasSupport) { return result; } // XPosition positions[]; GetPositions(positions); for (int i = 0; i < count; i++) { // XPosition iPosition = positions[i]; // if (iPosition.ticket == ticket) { continue; } // string pTicketStr = ExtractParentTicketOfSupport(iPosition.comment); if (StringLen(pTicketStr) <= 0) { continue; } // ulong pTicket = (ulong)pTicketStr; if (pTicket != ticket) { continue; } // Add( iPosition, supports); } // result = ArraySize(supports) > 0; // return result; } // bool GetSupportOrders( ulong ticket, // Parent Position Ticket XOrder &supports[], // Holds Result ... string symbol, // Trading Symbol ... ENUM_TIMEFRAMES period, // Trading TimeFrame ... ENUM_ORDER_STATE state = NULL // Order State ... ) { // bool result = false; // Clean(supports); // XOrder orders[]; GetOrders( orders, symbol, period, state); int ordersCount = ArraySize(orders); result = ordersCount > 0; if (!result) { return result; } // for (int i = 0; i < ordersCount; i++) { // XOrder iOrder = orders[i]; // string pTicketStr = ExtractParentTicketOfSupport(iOrder.comment); if (StringLen(pTicketStr) == 0) { continue; } // ulong pTicket = (ulong)pTicketStr; if (pTicket != ticket) { continue; } // Add( iOrder, supports); } // result = ArraySize(supports) > 0; // return result; } // // Generate SL Support Signal ... bool GenerateSLSupportSignal( XSignal &signal, // Holds Result .... ulong ticket, // Specific Position Ticket ... double slGapPoint = 10, // Which Distance to SL for Enabling Signal ... double volumeMultiplier = 2 // Support Signals Volume Multiplier ... ) { // bool result = false; // int count = PositionsCount(); if (count <= 0) { return result; } // bool hasSupport = HasSupport(ticket); if (hasSupport) { return result; } // XPosition position; result = GetPosition( position, ticket); if (!result) { return result; } // bool isLong = IsLong(position.type); // string symbol = position.symbol; ENUM_TIMEFRAMES period = ExtractPositionPeriod(position.comment); double volume = position.volume * volumeMultiplier; volume = NormalizeVolume( volume, symbol); ENUM_POSITION_TYPE type = isLong ? POSITION_TYPE_SELL : POSITION_TYPE_BUY; ENUM_X_ORDER_MODES mode = X_ORDER_MODE_STOP; // double slGapPrice = PointToPrice( symbol, slGapPoint); double riskPrice = MathAbs(position.entry - position.sl); // double entry = isLong ? position.sl + slGapPrice : position.sl - slGapPrice; entry = NormalizePrice(entry, symbol); // double sl = isLong ? entry + riskPrice : entry - riskPrice; sl = NormalizePrice(sl, symbol); // double tp = isLong ? entry - riskPrice : entry + riskPrice; tp = NormalizePrice(tp, symbol); // signal.sl = sl; signal.tp = tp; signal.type = type; signal.mode = mode; signal.entry = entry; signal.volume = volume; signal.symbol = symbol; signal.period = period; // return result; } // // Close a Position and it's Supports on a Profit ... bool ClosePositionAndSupports( ulong ticket, // Position Ticket double minProfit = 4 // Minimum Profit For Closing ) { // bool result = false; // if (minProfit <= 0) { return result; } // int count = PositionsCount(); if (count <= 0) { return result; } // XPosition position; bool isExist = GetPosition( position, ticket); if (!isExist) { return result; } // bool hasSupport = HasSupport(ticket); if (!hasSupport) { return result; } // XPosition supports[]; hasSupport = GetSupportPositions( ticket, supports); int supportsCount = ArraySize(supports); if (!hasSupport || supportsCount <= 0) { return result; } // double profitSummary = 0; for (int i = 0; i < supportsCount; i++) { // XPosition iSupport = supports[i]; // profitSummary += iSupport.profit; } // result = profitSummary > 0 && profitSummary >= minProfit; if (!result) { return result; } // Add( position, supports); // string comment = "Close Position (" + (string)ticket + ") and it's Supports in Profit: " + (string)profitSummary + " ..."; ClosePositions( supports, comment); // if (result) { LogMessage(comment); } // return result; } // // END Provided Functions ... // // // Protected ... protected: // // Private ... // // EVENTS Handlers Notifiers ... // // STATE ... void NotifyTradeStateChangeEvent(const XOnTradeHandlerState &state) { // int count = ArraySize(mTradeStateChangedEventHandlers); if (count <= 0) { return; } // for (int i = 0; i < count; i++) { // OnTradeStateChanged iHandler = mTradeStateChangedEventHandlers[i]; iHandler(state); } } // // DEALS ... void NotifyDealsChangeEvent(int changes) { // int count = ArraySize(mDealsChangedEventHandlers); if (count <= 0) { return; } // for (int i = 0; i < count; i++) { // OnDealsChanged iHandler = mDealsChangedEventHandlers[i]; iHandler(changes); } } // // ORDERS ... void NotifyOrdersChangeEvent(int changes) { // int count = ArraySize(mOrdersChangedEventHandlers); if (count <= 0) { return; } // for (int i = 0; i < count; i++) { // OnOrdersChanged iHandler = mOrdersChangedEventHandlers[i]; iHandler(changes); } } // // POSITIONS ... void NotifyPositionsChangeEvent(int changes) { // int count = ArraySize(mPositionsChangedEventHandlers); if (count <= 0) { return; } // for (int i = 0; i < count; i++) { // OnPositionsChanged iHandler = mPositionsChangedEventHandlers[i]; iHandler(changes); } } // // TPSL ... // void NotifyStopLossEvent(const XDeal &deal) { // int count = ArraySize(mStopLossEventHandlers); if (count <= 0) { return; } // for (int i = 0; i < count; i++) { // OnStopLoss iHandler = mStopLossEventHandlers[i]; iHandler(deal); } } // void NotifyTakeProfitEvent(const XDeal &deal) { // int count = ArraySize(mTakeProfitEventHandlers); if (count <= 0) { return; } // for (int i = 0; i < count; i++) { // OnTakeProfit iHandler = mTakeProfitEventHandlers[i]; iHandler(deal); } } 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; // // START Trade Processing ... // // int mDaysForRead; // // set the limits of the trade history on the global scope ... // // // start date for trade history in cache ... datetime mStartDate; // // end date for trade history in cache ... datetime mEndDate; // // global OnTrade counters ... // // number of active orders ... int mOrdersCount; // // number of open positions ... int mPositionsCount; // // number of deals in the trade history cache ... int mDealsCount; // // number of orders in the trade history cache ... int mHistoryOrdersCount; // // flag of counter relevance ... bool mScanStarted; // // Check Statrt Date In Trade History ... void CheckStartDateInTradeHistory() { // // initial interval, if we were to start working right now .. datetime currStart = TimeCurrent() - (mDaysForRead * PeriodSeconds(PERIOD_D1)); // // make sure that the start limit of the trade history has not gone // more than 1 day over the intended date ... if (currStart - mStartDate > PeriodSeconds(PERIOD_D1)) { // // correct the start date of history to be loaded in the cache ... mStartDate = currStart; // // now reload the trade history for the updated interval ... HistorySelect(mStartDate, mEndDate); // // correct the deal and order counters in history for further comparison mHistoryOrdersCount = HistoryOrdersTotal(); mDealsCount = HistoryDealsTotal(); } } // // Process On Trade Context ... void ProcessOnTradeContext( XOnTradeHandlerState &result // Hold's Result ) { // mEndDate = TimeCurrent(); // ResetLastError(); // // download trading history from the specified interval to the program cache ... bool selected = HistorySelect(mStartDate, mEndDate); if (!selected) { return; } // // get the current values ... int currOrders = OrdersTotal(); int currPositions = PositionsTotal(); int currDeals = HistoryDealsTotal(); int currHistoryOrders = HistoryOrdersTotal(); // // Orders ... // check if the number of active orders has been changed ... if (currOrders != mOrdersCount) { // // number of active orders has been changed ... result.hasNewOrder = true; result.newOrders = currOrders - mOrdersCount; // // update the value ... mOrdersCount = currOrders; } // // Positions ... // changes in the number of open positions ... if (currPositions != mPositionsCount) { // // number of open positions has been changed ... result.hasNewPosition = true; result.newPositions = currPositions - mPositionsCount; // // update the value ... mPositionsCount = currPositions; } // // Deals ... // changes in the number of deals in the trade history cache ... if (currDeals != mDealsCount) { // // number of deals in the trade history cache has been changed ... result.hasNewDeal = true; result.newDeals = currDeals - mDealsCount; // // update the value ... mDealsCount = currDeals; } // // History Orders ... // changes in the number of history orders in the trade history cache ... if (currHistoryOrders != mHistoryOrdersCount) { // // number of history orders in the trade history cache has been changed ... result.hasNewHistoryOrder = true; result.newHistoryOrders = currHistoryOrders - mHistoryOrdersCount; // // update the value ... mHistoryOrdersCount = currHistoryOrders; } // // checking if it is necessary to change the limits of the trade history to be requested in cache ... CheckStartDateInTradeHistory(); } // // Reset On Trade Scanner Context ... void ResetOnTradeContext() { // mEndDate = TimeCurrent(); mStartDate = mEndDate - (mDaysForRead * PeriodSeconds(PERIOD_D1)); } // // Initial Context Of Trade Scanner ... void InitOnTradeContext() { // ResetLastError(); // mOrdersCount = OrdersTotal(); mPositionsCount = PositionsTotal(); // // load history ... bool selected = HistorySelect(mStartDate, mEndDate); if (!selected) { return; } // // get the current value ... mDealsCount = HistoryDealsTotal(); mHistoryOrdersCount = HistoryOrdersTotal(); // mScanStarted = true; } // // Deals Changed Event Handlers ... OnDealsChanged mDealsChangedEventHandlers[]; // // Orders Changed Event Handlers ... OnOrdersChanged mOrdersChangedEventHandlers[]; // // Positions Changed Event Handlers ... OnPositionsChanged mPositionsChangedEventHandlers[]; // // Trade State Changed Event Handlers ... OnTradeStateChanged mTradeStateChangedEventHandlers[]; // // TPSL ... OnStopLoss mStopLossEventHandlers[]; OnTakeProfit mTakeProfitEventHandlers[]; // // END Trade Processing ... // }; // // 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 Clean(XDeal &buffer[]) { // ArrayFree(buffer); ArrayResize(buffer, 0); } void Clean(XOrder &buffer[]) { // ArrayFree(buffer); ArrayResize(buffer, 0); } void Clean(XPosition &buffer[]) { // ArrayFree(buffer); ArrayResize(buffer, 0); } // // Generate Identifier Tag ... string GenerateTag(XSignal &info) { // string result = ""; // result = info.symbol + "," + ToString(info.period); // return result; } // // Convert Position to Signal ... XSignal ToSignalInfo( XPosition &position) { // XSignal result; // result.tp = position.tp; result.sl = position.sl; result.type = position.type; result.entry = position.entry; result.symbol = position.symbol; result.period = position.period; result.volume = position.volume; // return result; } // // END Usefull Functions ... //