/////////////////////////////////////////////////////// // // 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 // // Imports ... #include "../Classes/x-saherelm.base.class.mq5" #include "../Libraries/x-saherelm.xtrade.lib.mq5" #include "../Classes/x-saherelm.xaccount.class.mq5" // // Definitions ... // // 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)); } }; // // Implementation ... // a Class For Manage Trades and Handle Trading Actions ... class XSCTrade : public XSCBase { // // Public ... public: // // Props ... // // Constructors ... void XSCTrade( int slippage, // Specify Slippage ulong magicNumber, // Specify Magic Number int manageInterval, // Manager Check Intervals Seconds double maxAllowedSpread, // Max Allowed Spred for Opening Trades int maxAllowedPositions, // Max Allowed Positions double maxAllowedDrawdownFactor // Max Allowed Drawdown Factor ) { // // Setting Props ... mSlippage = slippage; mMagicNumber = magicNumber; // mManageInterval = manageInterval; // mMaxAllowedSpread = maxAllowedSpread; mMaxAllowedPositions = maxAllowedPositions; mMaxAllowedDrawdownFactor = maxAllowedDrawdownFactor; // mAccount = new XSCAccount(); // // Instance Base Trader Class ... mTrader = new XSCTradeBase(); // // Configuring Base Trader Class ... mTrader.SetAsyncMode(false); mTrader.SetDeviationInPoints(mSlippage); mTrader.SetExpertMagicNumber(mMagicNumber); // // Setting Log Level ... mTrader.LogLevel(LOG_LEVEL_ERRORS); // // OnTrade Context ... // mDaysForRead = 1; mScanStarted = false; // // Reset On Trade Counter ... ResetOnTradeContext(); // // Init On Trade Context ... InitOnTradeContext(); // // Sync Position Infos ... SyncPositionInfos(); } // // Deconstructor ... ~XSCTrade() { // // Remove Pointer ... delete mTrader; delete mAccount; } // // Props ... // // Retrieve Slippage ... int GetSlippage() { return mSlippage; } // // Retrieve Magic Number ... ulong GetMagicNumber() { return mMagicNumber; } // int GetManageInterval() { return mManageInterval; } // double GetMaxAllowedSpread() { return mMaxAllowedSpread; } // int GetMaxAllowedPositions() { return mMaxAllowedPositions; } // double GetMaxAllowedDrawdownFactor() { return mMaxAllowedDrawdownFactor; } // // Add Event Listeners ... // // Add New Deals Changed Event Handler ... void AddOnTradeStateChangedEventHandler(TOnTradeStateChanged handler) { // Add( handler, mTradeStateChangedEventHandlers // ); } // // Add New Deals Changed Event Handler ... void AddOnDealsChangedEventHandler(TOnDealsChanged handler) { // Add( handler, mDealsChangedEventHandlers // ); } // // Add New Orders Changed Event Handler ... void AddOnOrdersChangedEventHandler(TOnOrdersChanged handler) { // Add( handler, mOrdersChangedEventHandlers // ); } // // Add New Positions Changed Event Handler ... void AddOnPositionsChangedEventHandler(TOnPositionsChanged handler) { // Add( handler, mPositionsChangedEventHandlers // ); } // // Add New Stop Loss Event Handler ... void AddOnStopLossEventHandler(TOnStopLoss handler) { // Add( handler, mStopLossEventHandlers // ); } // // Add New Stop Loss Event Handler ... void AddOnTakeProfitEventHandler(TOnTakeProfit handler) { // Add( handler, mTakeProfitEventHandlers // ); } // // Functions ... // // Handlers ... // // Process On Trade Requirement ... // this Only Used when we Have to Proccess OnTrade Event in EA(s) ... void HandleOnTradeEvent( XOnTradeHandlerState &result // Hold's Result ) { // result.Clean(); // if (mScanStarted) { // ProcessOnTradeContext(result); } else { // // Init Trade Context ... InitOnTradeContext(); // return; } // // Here we Can Check the Start ... bool isValid = // result.IsValid() && // !result.hasNewDeal && !result.hasNewOrder && !result.hasNewPosition && !result.hasNewHistoryOrder // ; if (!isValid) { return; } // // State ... // // Notfy Trade State Changed Event ... NotifyTradeStateChangeEvent(result); // // Deals ... if (result.hasNewDeal) { // // Notfy Deals Changed Event ... NotifyDealsChangeEvent(result.newDeals); // // Retrieve Last Deal ... XDeal deals[]; int dealsCount = GetDeals(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 (result.hasNewOrder || result.hasNewHistoryOrder) { // // Notfy Orders Changed Event ... NotifyOrdersChangeEvent(result.newOrders + result.newHistoryOrders); } // // Positions ... if (result.hasNewPosition) { // // Notfy Positions Changed Event ... NotifyPositionsChangeEvent(result.newPositions); } } // // This Must be Called Every time OnTrade Event Happening ... // this Used for Implementing Custom Senarios ... 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; } // // Trade Actions ... // // Main ... // // Policies ... // // Check Acocunt Balance is Allow new Trades or not ... bool CheckEquityForTrade() { // bool result = false; // if (mMaxAllowedDrawdownFactor <= 0) { // result = true; return result; } // double equity = mAccount.GetEquity(); double balance = mAccount.GetBalance(); // double selectedBalance = MathMax(equity, balance) - MathMin(equity, balance); // double maxAllowedBalanceDrawDown = GetMaxAllowedEquity(); // result = equity > balance || (equity <= balance && selectedBalance <= maxAllowedBalanceDrawDown); // return result; } // // Check Max Allowed Positions Policy for Trade ... bool CheckPositionsForTrade() { // bool result = false; // if (mMaxAllowedPositions <= 0) { // result = true; return result; } // XPosition positions[]; int positionsCount = GetPositions(positions); if (positionsCount <= 0) { // result = true; return result; } // result = positionsCount < mMaxAllowedPositions; // return result; } // // Check Spread is Ok for Executing Specific Signal ... bool CheckSpreadForSignalExecution(XSignal &signal) { // bool result = false; // bool isSpreadCheckEnable = mMaxAllowedSpread > 0; if (!isSpreadCheckEnable) { result = true; } else { // // Retrieve Signal Spread ... double spread = signal.GetSpread(); result = spread <= mMaxAllowedSpread; } // return result; } // // Check Account Policy ... bool CheckAccountPolicy( XSignal &signal, // For Executing Signal ENUM_X_SIGNAL_EXECUTION_RESULT &state // State Holder ) { // bool result = false; // // Check Positions For Trade ... result = CheckPositionsForTrade(); if (!result) { // state = X_SIGNAL_EXECUTION_FAILED_MAX_REACHED; return result; } // // Check Equity For Trade ... result = CheckEquityForTrade(); if (!result) { // state = X_SIGNAL_EXECUTION_FAILED_NO_EQUITY; return result; } // // Check Spread for Trade ... result = CheckSpreadForSignalExecution(signal); if (!result) { // state = X_SIGNAL_EXECUTION_FAILED_SPREAD; return result; } // return result; } // // Manage ... // this must be Call on OnTick for Manage // Positions ... // NOTE: Call this Before Checking IsNewBar ... void Manage() { // // All required Position Managements Actions implemented here ... datetime tmc = TimeCurrent(); bool canManage = !IsValid(mLastManageOn) ? true : mLastManageOn + mManageInterval >= tmc; if (!canManage) { return; } // mLastManageOn = tmc; // // - [] Partial Close; // - [] Risk Free; // - [] Trail Stop; // - [] SLS; // - [] TPS; // // - [] Data Collector; // - [] Profit Management; // // TODO: Implement them ... // // Implement Signal Collector Inside this Class // and Manipulate Signals when SL/TP/Partial Close/Trail Stop/Profit/Close/ Modify and etc Happens ... } // // Execute a Signal ... bool ExecuteSignal( XSignal &signal, // Signal ENUM_X_SIGNAL_EXECUTION_RESULT &state, // Result ENUM_ORDER_TYPE_TIME lifetime = ORDER_TIME_GTC, // Order LifeTime datetime expiration = NULL, // order expiration time bool checkPolicies = true // Check Account Policies ) { // bool result = false; state = X_SIGNAL_EXECUTION_UNKNOWN; // double currentEntry = GetEntry( signal.symbol, signal.type // ); bool isLong = IsLong(signal.type); // // Select SL and TP ... // double selectedSL = 0; signal.RegularSL(selectedSL); // double selectedTP = 0; signal.RegularTP(selectedTP); // if (!signal.IsValid()) { // state = X_SIGNAL_EXECUTION_FAILED_INVALID_PARAMS; return result; } // // Handle Market Execution ... if (signal.mode == X_ORDER_MODE_MARKET) { // // Do Apply Policies here ... bool hasPolicy = !checkPolicies ? true : CheckAccountPolicy(signal, state); if (!hasPolicy) { result = false; } else { // if (isLong) { // result = Buy( signal.symbol, signal.period, signal.volume, signal.entry, selectedSL, selectedTP, signal.comment // ); } else { // result = Sell( signal.symbol, signal.period, signal.volume, signal.entry, selectedSL, selectedTP, signal.comment // ); } } } // // Handle Stop Execution ... else if (signal.mode == X_ORDER_MODE_STOP) { // // Check Conditions ... // // Check Price ... result = isLong ? signal.entry > currentEntry : signal.entry < currentEntry; if (!result) { // state = X_SIGNAL_EXECUTION_FAILED_PRICE_ERROR; return result; } // // Execute Order ... if (isLong) { // result = BuyStop( signal.symbol, signal.period, signal.volume, signal.entry, selectedSL, selectedTP, lifetime, expiration, signal.comment // ); } else { // result = SellStop( signal.symbol, signal.period, signal.volume, signal.entry, selectedSL, selectedTP, lifetime, expiration, signal.comment // ); } } // // Handle Limit Execution ... else if (signal.mode == X_ORDER_MODE_LIMIT) { // // Check Conditions ... // // Check Price ... result = isLong ? signal.entry < currentEntry : signal.entry > currentEntry; if (!result) { // state = X_SIGNAL_EXECUTION_FAILED_PRICE_ERROR; return result; } // // Execute Order ... if (isLong) { // result = BuyLimit( signal.symbol, signal.period, signal.volume, signal.entry, selectedSL, selectedTP, lifetime, expiration, signal.comment // ); } else { // result = SellLimit( signal.symbol, signal.period, signal.volume, signal.entry, selectedSL, selectedTP, lifetime, expiration, signal.comment // ); } } // // Handle Ticket ... if (result) { // state = X_SIGNAL_EXECUTION_SUCCEED; // ulong ticket; if (signal.mode == X_ORDER_MODE_MARKET) { ticket = GetLastOpenPositionTicket(); } else { ticket = GetLastPlacedOrderTicket(); } // signal.positionId = ticket; // // Handle Store XPositionInfo ... if (signal.mode == X_ORDER_MODE_MARKET) { // // TODO: Implement this ... } // // Handle Executing Support Signals ... int supportsCount = ArraySize(signal.supports); if (supportsCount > 0) { // int executed = 0; for (int i = 0; i < supportsCount; i++) { // XSignal iSupport = signal.supports[i]; // int supIndex = i + 1; string iComment = GenerateSupportTag(ticket); // bool isExecuted = ExecuteSignal( iSupport, state, lifetime, expiration // ); if (isExecuted) { executed++; } } // result = executed == supportsCount; } } // return result; } // // Execute a Collection Of Signals ... int ExecuteSignals( XSignal &signals[], // Collection of Signal for Execution ENUM_X_SIGNAL_EXECUTION_RESULT &states[], // Signal Execution Result ENUM_ORDER_TYPE_TIME lifetime = ORDER_TIME_GTC, // Order LifeTime datetime expiration = NULL, // order expiration time bool checkPolicies = true // Check Account Policies ) { // int result = 0; // Clean(states); // int signalsCount = ArraySize(signals); if (signalsCount <= 0) { return result; } // ArrayResize(states, signalsCount); ArrayInitialize(states, X_SIGNAL_EXECUTION_UNKNOWN); for (int i = 0; i < signalsCount; i++) { // bool isExecuted = ExecuteSignal( signals[i], states[i], lifetime, expiration // ); // if (isExecuted) { result++; } } // return result; } // // Regular Trade Actions ... // // Buy ... // // 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 = NULL // comment ) { // bool result = false; // ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); if (!IsValid(comment) || !IsValid(mPeriod)) { // string mPeriodStr = GeneratePeriodTag(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 = NULL // comment ) { // bool result = false; // ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); if (!IsValid(comment) || !IsValid(mPeriod)) { // string mPeriodStr = GeneratePeriodTag(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 = NULL // comment ) { // bool result = false; // ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); if (!IsValid(comment) || !IsValid(mPeriod)) { // string mPeriodStr = GeneratePeriodTag(period); // comment += mPeriodStr; } // result = mTrader.BuyStop( volume, price, symbol, sl, tp, typeTime, expiration, comment // ); // return result; } // // Sell ... // // 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 = NULL // comment ) { // bool result = false; // ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); if (!IsValid(comment) || !IsValid(mPeriod)) { // string mPeriodStr = GeneratePeriodTag(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 = NULL // comment ) { // bool result = false; // ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); if (!IsValid(comment) || !IsValid(mPeriod)) { // string mPeriodStr = GeneratePeriodTag(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 = NULL // comment ) { // bool result = false; // ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); if (!IsValid(comment) || !IsValid(mPeriod)) { // string mPeriodStr = GeneratePeriodTag(period); // comment += mPeriodStr; } // result = mTrader.SellStop( volume, price, symbol, sl, tp, typeTime, expiration, comment // ); // return result; } // // Check a Position is Exists Open or not ... bool IsOpen( ulong ticket // Specified Position Ticket ) { // bool result = false; // result = mPositionInfo .SelectByTicket(ticket); // return result; } // // Modify Position ... bool Modify( const ulong ticket, // position ticket double sl = 0, // stop loss price double tp = 0, // take profit string comment = NULL // comment ) { // bool result = false; // // Validate Args ... result = IsOpen(ticket) && (tp >= 0 || sl >= 0); if (!result) { return result; } // // Use Position Comment when there isn't new One ... if (!IsValid(comment) == 0) { // // if there isn't provided Comment // Use Position Comment for default ... comment = "Modify " + GetPositionComment(ticket); } // result = mTrader.PositionModify( ticket, sl, tp, comment // ); // return result; } // // Close Position By Ticket ... bool Close( ulong ticket, // Position Ticket string comment = NULL // Close Position By Specific Comment ) { // bool result = false; // // Check Position Open ... result = !IsOpen(ticket); if (!result) { return result; } // // Use Default Position Comment if it's Not Provided ... if (!IsValid(comment)) { comment = "Close " + GetPositionComment(ticket); } // // Close Position By Specific Comment ... result = mTrader.PositionClose( ticket, mSlippage, comment // ); // return result; } // // Close Specified Positions ... int Close( string comment = NULL, // Close Position By Specific Comment string symbol = NULL, // Trading Symbol string provider = NULL, // Signal Provider ENUM_TIMEFRAMES period = NULL, // Trading Period ENUM_POSITION_TYPE type = NULL, // Long (Buy) or Short (Sell) bool filterByMagic = true // Get Only Self Open Positions ) { // int result = 0; // XPosition positions[]; int positionsCount = GetPositions( positions, symbol, provider, period, type, filterByMagic); if (positionsCount <= 0) { return result; } // for (int i = 0; i < positionsCount; i++) { // XPosition iPosition = positions[i]; // bool isClosed = Close( iPosition.ticket, comment // ); if (isClosed) { result++; } } // return result; } // // Close a Collection of Positions ... int Close( XPosition &positions[], // Collection of Positions string comment // Close Comment ) { // int result = 0; // int positionsCount = ArraySize(positions); if (positionsCount <= 0) { return result; } // for (int i = 0; i < positionsCount; i++) { // XPosition iPosition = positions[i]; // bool isClosed = Close( iPosition.ticket, comment // ); if (isClosed) { result++; } } // return result; } // // Close Partial By Ticket ... bool ClosePartial( ulong ticket, // Position Ticket double volume, // Volume Size for Partial Closing string comment = NULL // Close Position By Specific Comment ) { // bool result = false; // result = IsOpen(ticket); if (!result) { return result; } // // Use Default Partial Close Comment ... if (!IsValid(comment)) { // comment += "PClose " + GetPositionComment(ticket); } // result = mTrader.PositionClosePartial( ticket, volume, mSlippage, comment // ); // return result; } // // Cancel Specific Order ... bool CancelOrder(ulong ticket) { return mTrader .OrderDelete(ticket); } // // Cancel Specific Orders ... int CancelOrders( XOrder &orders[] // Specified Orders ... ) { // int result = 0; // 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++; } } // return result; } // // Extractors ... // // Positions ... // // Calculate Positions Profit ... double Profit( string symbol = NULL, // Trading Symbol string provider = NULL, // Signal Provider ENUM_TIMEFRAMES period = NULL, // Trading Period ENUM_POSITION_TYPE type = NULL, // Long (Buy) or Short (Sell) bool filterByMagic = true // Get Only Self Open Positions ) { // double result = 0; // // Retrieve Positions ... XPosition positions[]; int positionsCount = GetPositions( positions, symbol, provider, period, type, filterByMagic // ); if (positionsCount <= 0) { return result; } // for (int i = 0; i < positionsCount; i++) { result += positions[i].profit; } // return result; } // // Retrieve Specific Position by Index ... bool GetPosition( int index, // Specified Index XPosition &result // Hold's Result ) { // return result .ByIndex(index); } // // Retrieve Specific Position by Ticket ... bool GetPosition( ulong ticket, // Specified Ticket XPosition &result // Hold's Result ) { // return result .ByTicket(ticket); } // // Retrieve Positions ... int GetPositions( XPosition &result[], // Hold's Result string symbol = NULL, // Trading Symbol string provider = NULL, // Signal Provider ENUM_TIMEFRAMES period = NULL, // Trading Period ENUM_POSITION_TYPE type = NULL, // Long (Buy) or Short (Sell) bool filterByMagic = true, // Get Only Self Open Positions bool forceClean = true // Clean Result Array ) { // int mResult = 0; // int before = ArraySize(result); // if (forceClean) { Clean(result); } // // Count Positions ... int itemsCount = PositionsTotal(); if (itemsCount <= 0) { return mResult; } // // Loop Through all Positions ... for (int i = itemsCount - 1; i >= 0; i--) { // XPosition iItem; bool isLoaded = iItem.ByIndex(i); if (!isLoaded) { continue; } // // Now we have to Check Given Filters ... bool isFiltersPassed = iItem.IsFiltersPassed( symbol, provider, period, type, mMagicNumber, filterByMagic // ); if (!isFiltersPassed) { continue; } // // Add Filtered Item into Result ... AddRef( iItem, result // ); } // int after = ArraySize(result); // mResult = after - before; // return mResult; } // // Select In Profit Positions ... int GetInProfitPositions( XPosition &result[], // Hold's Result string symbol = NULL, // Trading Symbol string provider = NULL, // Signal Provider ENUM_TIMEFRAMES period = NULL, // Trading Period ENUM_POSITION_TYPE type = NULL, // Long (Buy) or Short (Sell) ENUM_X_POSITION_SELECT_METHODS method = NULL, // Selection Method bool filterByMagic = true, // Get Only Self Open Positions bool forceClean = true // Clean Result Array ) { // int mResult = 0; // int before = ArraySize(result); // if (forceClean) { Clean(result); } // XPosition positions[]; int positionsCount = GetPositions( positions, symbol, provider, period, type, filterByMagic, forceClean); if (positionsCount <= 0) { return mResult; } // XPosition min; XPosition max; // for (int i = 0; i < positionsCount; i++) { // XPosition iPosition = positions[i]; // if (iPosition.profit <= 0) { continue; } // // Calculate Min and Max ... // // Min ... if (!min.IsValid() || min.profit <= 0 || min.profit > iPosition.profit) { min = iPosition; } // // Max ... if (!max.IsValid() || max.profit <= 0 || max.profit < iPosition.profit) { max = iPosition; } // bool isSelectionMethodFilterPassed = // (method == NULL || method == X_POSITION_SELECT_ALL || method == X_POSITION_SELECT_ALL) ? true : false; // ; if (!isSelectionMethodFilterPassed) { continue; } // AddRef( iPosition, result // ); } // if (min.IsValid() && (method == X_POSITION_SELECT_MIN || method == X_POSITION_SELECT_BOTH)) { // AddRef( min, result // ); } // if (max.IsValid() && (method == X_POSITION_SELECT_MAX || method == X_POSITION_SELECT_BOTH)) { // AddRef( max, result // ); } // int after = ArraySize(result); // mResult = after - before; // return mResult; } // // Select In Drawdown Positions ... int GetInDrawdownPositions( XPosition &result[], // Hold's Result string symbol = NULL, // Trading Symbol string provider = NULL, // Signal Provider ENUM_TIMEFRAMES period = NULL, // Trading Period ENUM_POSITION_TYPE type = NULL, // Long (Buy) or Short (Sell) ENUM_X_POSITION_SELECT_METHODS method = NULL, // Selection Method bool filterByMagic = true, // Get Only Self Open Positions bool forceClean = true // Clean Result Array ) { // int mResult = 0; // int before = ArraySize(result); // if (forceClean) { Clean(result); } // XPosition positions[]; int positionsCount = GetPositions( positions, symbol, provider, period, type, filterByMagic, forceClean); if (positionsCount <= 0) { return mResult; } // XPosition min; XPosition max; // for (int i = 0; i < positionsCount; i++) { // XPosition iPosition = positions[i]; // if (iPosition.profit >= 0) { continue; } // // Calculate Min and Max ... // // Min ... if (!min.IsValid() || min.profit <= 0 || min.profit > iPosition.profit) { min = iPosition; } // // Max ... if (!max.IsValid() || max.profit <= 0 || max.profit < iPosition.profit) { max = iPosition; } // bool isSelectionMethodFilterPassed = // (method == NULL || method == X_POSITION_SELECT_ALL || method == X_POSITION_SELECT_ALL) ? true : false; // ; if (!isSelectionMethodFilterPassed) { continue; } // AddRef( iPosition, result // ); } // if (min.IsValid() && (method == X_POSITION_SELECT_MIN || method == X_POSITION_SELECT_BOTH)) { // AddRef( min, result // ); } // if (max.IsValid() && (method == X_POSITION_SELECT_MAX || method == X_POSITION_SELECT_BOTH)) { // AddRef( max, result // ); } // int after = ArraySize(result); // mResult = after - before; // return mResult; } // // Orders ... // // Retrieve Specific Order by Index ... bool GetOrder( int index, // Specified Index XOrder &result // Hold's Result ) { // return result .ByIndex(index); } // // Retrieve Specific Positions Orders ... int GetOrders( ulong ticket, // Positions Ticket XOrder &result[], // Hold's Result bool forceClean = true // Clean Result Array ) { // int mResult = 0; // // Select History by Specified Ticket ... bool isHistorySelected = HistorySelectByPosition(ticket); if (!isHistorySelected) { return mResult; } // int ordersCount = HistoryOrdersTotal(); if (ordersCount <= 0) { return mResult; } // int before = ArraySize(result); // if (forceClean) { Clean(result); } // for (int i = 0; i < ordersCount; i++) { // XOrder iOrder; bool isLoaded = iOrder.HistoryByIndex(i); if (!isLoaded) { continue; } // bool isTicketFilterPassed = // iOrder.ticket = ticket // ; if (!isTicketFilterPassed) { continue; } // AddRef( iOrder, result // ); } // int after = ArraySize(result); // mResult = after - before; // return mResult; } // // Retrieve All Orders ... int GetOrders( XOrder &result[], // Hold's Result string symbol = NULL, // Trading Symbol string provider = NULL, // Signal Provider ENUM_TIMEFRAMES period = NULL, // Trading Period ENUM_ORDER_TYPE type = NULL, // Long (Buy) or Short (Sell) ENUM_ORDER_STATE state = NULL, // Order State bool filterByMagic = true, // Get Only Self Open Positions bool forceClean = true // Clean Result Array ) { // int mResult = 0; // int before = ArraySize(result); // if (forceClean) { Clean(result); } // // Count Positions ... int itemsCount = OrdersTotal(); if (itemsCount <= 0) { return mResult; } // // Loop Through all Positions ... for (int i = itemsCount - 1; i >= 0; i--) { // XOrder iItem; bool isLoaded = iItem.ByIndex(i); if (!isLoaded) { continue; } // // Now we have to Check Given Filters ... bool isFiltersPassed = iItem.IsFiltersPassed( symbol, provider, period, type, state, mMagicNumber, filterByMagic // ); if (!isFiltersPassed) { continue; } // // Add Filtered Item into Result ... AddRef( iItem, result // ); } // int after = ArraySize(result); // mResult = after - before; // return mResult; } // // Retrieve Historical Orders ... int GetOrders( XOrder &result[], // Hold's Result string symbol = NULL, // Trading Symbol string provider = NULL, // Signal Provider ENUM_TIMEFRAMES period = NULL, // Trading Period ENUM_ORDER_TYPE type = NULL, // Long (Buy) or Short (Sell) ENUM_ORDER_STATE state = NULL, // Order State datetime startDate = NULL, // Specify Start Date datetime endDate = NULL, // Specify End Date bool filterByMagic = true, // Get Only Self Open Positions bool forceClean = true // Clean Result Array ) { // int mResult = 0; // endDate = NormalizeTime(endDate); // if (!IsValid(startDate)) { startDate = endDate - PeriodSeconds(PERIOD_D1); } // bool isHistorySelected = HistorySelect( startDate, endDate); if (!isHistorySelected) { return mResult; } // int before = ArraySize(result); // if (forceClean) { Clean(result); } // // Count Positions ... int itemsCount = OrdersTotal(); if (itemsCount <= 0) { return mResult; } // // Loop Through all Positions ... for (int i = itemsCount - 1; i >= 0; i--) { // XOrder iItem; bool isLoaded = iItem.HistoryByIndex(i); if (!isLoaded) { continue; } // // Now we have to Check Given Filters ... bool isFiltersPassed = iItem.IsFiltersPassed( symbol, provider, period, type, state, mMagicNumber, filterByMagic // ); if (!isFiltersPassed) { continue; } // // Add Filtered Item into Result ... AddRef( iItem, result // ); } // int after = ArraySize(result); // mResult = after - before; // return mResult; } // // Deals ... // // Retrieve Specific Deal by Index ... bool GetDeal( int index, // Specified Index XDeal &result // Hold's Result ) { // return result .ByIndex(index); } // // Retrieve Specified Deal's History ... int GetDealsHistory( XDeal &deal, // Specified Deal XOrder &history[], // Deals History bool forceClean = true // Clean Result Array ) { // int result = 0; // if (!deal.IsValid()) { return result; } // result = GetOrders( deal.positionId, history, forceClean); // return result; } // // Retrieve All Deals ... int GetDeals( XDeal &result[], // Hold's Result string symbol = NULL, // Trading Symbol string provider = NULL, // Signal Provider ENUM_TIMEFRAMES period = NULL, // Trading Period ENUM_DEAL_TYPE type = NULL, // Deal Type ENUM_DEAL_ENTRY entry = NULL, // Deal Entry ENUM_DEAL_REASON reason = NULL, // Deal Reason datetime startDate = NULL, // Specify Start Date datetime endDate = NULL, // Specify End Date bool filterByMagic = true, // Get Only Self Open Positions bool forceClean = true // Clean Result Array ) { // int mResult = 0; // endDate = NormalizeTime(endDate); // if (!IsValid(startDate)) { startDate = endDate - PeriodSeconds(PERIOD_D1); } // bool isHistorySelected = HistorySelect( startDate, endDate); if (!isHistorySelected) { return mResult; } // int before = ArraySize(result); // if (forceClean) { Clean(result); } // // Count Positions ... int itemsCount = HistoryDealsTotal(); if (itemsCount <= 0) { return mResult; } // // Loop Through all Positions ... for (int i = itemsCount - 1; i >= 0; i--) { // XDeal iItem; bool isLoaded = iItem.ByIndex(i); if (!isLoaded) { continue; } // // Now we have to Check Given Filters ... bool isFiltersPassed = iItem.IsFiltersPassed( symbol, provider, period, type, entry, reason, mMagicNumber, filterByMagic // ); if (!isFiltersPassed) { continue; } // // Add Filtered Item into Result ... AddRef( iItem, result // ); } // int after = ArraySize(result); // mResult = after - before; // return mResult; } // // Protected ... protected: // // Props ... // // Event Listener Notifiers ... // // State ... void NotifyTradeStateChangeEvent(const XOnTradeHandlerState &state) { // int count = ArraySize(mTradeStateChangedEventHandlers); if (count <= 0) { return; } // for (int i = 0; i < count; i++) { // TOnTradeStateChanged 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++) { // TOnDealsChanged 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++) { // TOnOrdersChanged 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++) { // TOnPositionsChanged iHandler = mPositionsChangedEventHandlers[i]; iHandler(changes); } } // // StopLoss ... void NotifyStopLossEvent(const XDeal &deal) { // int count = ArraySize(mStopLossEventHandlers); if (count <= 0) { return; } // for (int i = 0; i < count; i++) { // TOnStopLoss iHandler = mStopLossEventHandlers[i]; iHandler(deal); } } // // Take Profit ... void NotifyTakeProfitEvent(const XDeal &deal) { // int count = ArraySize(mTakeProfitEventHandlers); if (count <= 0) { return; } // for (int i = 0; i < count; i++) { // TOnTakeProfit iHandler = mTakeProfitEventHandlers[i]; iHandler(deal); } } // // Tools ... // // Retrieve Specified Position Comment ... string GetPositionComment(ulong ticket) { // string result = NULL; // if (!IsOpen(ticket)) { return result; } // XPosition position; bool isLoaded = position.ByTicket(ticket); if (!isLoaded) { return result; } // result = position.comment; // 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; } // // XPosition Pack ... // // Extract specific Positions Pack ... // in this senario there is no need to Position exists itself ... bool GetPositionPack( ulong ticket, // Specified Positions Ticket string symbol, // Specified Position Symbol ENUM_TIMEFRAMES period, // Specified Position Period XPositionPack &pack // Hold Result ) { // bool result = false; // pack.Clean(); // XPosition position; bool hasPosition = GetPosition( ticket, position // ); if (hasPosition) { pack.position = position; } // XOrder supportOrders[]; XPosition supportPositions[]; // XOrder orders[]; GetOrders( orders, symbol, // Specified Symbol NULL, // All Providers period, // Specified Period NULL, // All Types ORDER_STATE_PLACED, // Just UnTriggered Orders true // Filter by Magic ); int ordersCount = ArraySize(orders); // // Select Orders ... if (ordersCount > 0) { // for (int i = 0; i < ordersCount; i++) { // XOrder iOrder = orders[i]; // // Retrieve Order Supported Ticket ... ulong parentTicket = ExtractSupportedTicket(iOrder.comment); if (NotEmpty(parentTicket) && parentTicket == ticket) { // AddRef( iOrder, supportOrders // ); } } } // int supportOrdersCount = ArraySize(supportOrders); if (supportOrdersCount > 0) { // pack.supportOrdersCount = supportOrdersCount; // Copy( supportOrders, pack.supportOrders); } // XPosition positions[]; GetPositions( positions, symbol, // Specified Symbol ... NULL, // All Providers ... period // Specified Period ... ); int positionsCount = ArraySize(positions); // // Select Positions ... if (positionsCount > 0) { // for (int i = 0; i < positionsCount; i++) { // XPosition iPosition = positions[i]; // ulong parentTicket = ExtractSupportedTicket(iPosition.comment); if (NotEmpty(parentTicket) && parentTicket == ticket) { // AddRef( iPosition, supportPositions // ); } } } // int supportPositionsCount = ArraySize(supportPositions); if (supportPositionsCount > 0) { // pack.supportPositionsCount = supportPositionsCount; // Copy( supportPositions, pack.supportPositions); } // result = supportOrdersCount > 0 || supportPositionsCount > 0; // return result; } // // Extract Specific Deals Position's Pack ... // this used when a Position SL or TP triggered and we want to close // all it's Supported Packs ... bool GetDealPack( XDeal &deal, XPositionPack &pack // ) { // bool result = false; // ulong ticket = deal.positionId; ENUM_TIMEFRAMES dealPeriod = GetDealPeriod(deal); string dealSymbol = deal.symbol; // // So We Have to Get Positions Pack ... result = GetPositionPack( ticket, dealSymbol, dealPeriod, pack // ); // return result; } // ENUM_TIMEFRAMES GetDealPeriod(XDeal &deal) { // ENUM_TIMEFRAMES result = NULL; // XOrder orders[]; int ordersCount = GetDealsHistory( deal, orders); if (!ordersCount) { return result; } // for (int i = 0; i < ordersCount; i++) { // XOrder iOrder = orders[i]; // if (IsValid(iOrder.comment)) { // ENUM_TIMEFRAMES iPeriod = ExtractPeriod(iOrder.comment); if (IsValid(iPeriod)) { result = iPeriod; break; } } } // return result; } // double GetMaxAllowedEquity() { // double equity = mAccount.GetEquity(); double balance = mAccount.GetBalance(); // double balanceForFactor = MathAbs(equity - balance); if (balanceForFactor <= 0) { balanceForFactor = balance; } else { balanceForFactor = equity; } // double result = balanceForFactor * mMaxAllowedDrawdownFactor; // return result; } // // Private ... private: // // Props ... // int mSlippage; // Slippage ... ulong mMagicNumber; // Magic Number (Unique Identifier) ... // datetime mLastManageOn; // Last Manager Check int mManageInterval; // Manager Check Intervals Seconds // double mMaxAllowedSpread; // Max Allowed Spred for Opening Trades int mMaxAllowedPositions; // Max Allowed Same Positions double mMaxAllowedDrawdownFactor; // Max Allowed Drawdown Factor // XSCAccount *mAccount; // Account Info Provider XSCTradeBase *mTrader; // Base CTrade Manipulated Instance ... // CDealInfo mDealInfo; // Deals Info ... COrderInfo mOrderInfo; // Order Info ... CPositionInfo mPositionInfo; // Positions Info CHistoryOrderInfo mHistoryOrderInfo; // History Orders Info ... // // Position Info Collector ... // XSCPositionInfoCollector mPositionInfoCollector; // Position Info Data Collector ... // void SyncPositionInfos() { // // TODO: Complete this ... // // Read All Stored Positions ... // XPositionInfo infos[]; // int infosCount = mPositionInfoCollector.Collect(infos); // // // // Clear Store ... // mPositionInfoCollector.Clear(); // // // XPosition positions[]; // int positionsCount = GetPositions(positions); // if (positionsCount <= 0) // { // Clean(infos); // } // // // // Now we Have to Find each Position Info inside Positions and Update them ... // XPositionInfo datas[]; // for (int i = 0; i < infosCount; i++) // { // // // XPositionInfo iInfo = infos[i]; // // // // Check Positions Contains Specific ticket or not ... // for (int j = 0; j < positionsCount; j++) // { // // // XPosition jPosition = positions[j]; // // // if (jPosition.ticket != iInfo.ticket) // { // // // // this is a Position which is not listed in Collector ... // } // else // { // // // // Now we have a Position which Listed Before in Collector ... // // we Have to Update it ... // } // } // } } // // Tools ... // // OnTrade Event Handlers Section ... // // Props ... // int mDaysForRead; // Reading Dates for Trade History Checker ... datetime mEndDate; // End Date for Trade history Checking ... datetime mStartDate; // Start Date for Trade history Checking ... ... int mOrdersCount; // Number of Active orders ... int mPositionsCount; // Number of Open positions ... int mDealsCount; // Number of Deals in the Trade History Checking ... int mHistoryOrdersCount; // Number of Orders in the Trade History Checking ... bool mScanStarted; // a Flag of counter relevance ... // // Event Listeners ... // // Deals Changed Event Handlers ... TOnDealsChanged mDealsChangedEventHandlers[]; // // Orders Changed Event Handlers ... TOnOrdersChanged mOrdersChangedEventHandlers[]; // // Positions Changed Event Handlers ... TOnPositionsChanged mPositionsChangedEventHandlers[]; // // Trade State Changed Event Handlers ... TOnTradeStateChanged mTradeStateChangedEventHandlers[]; // // TPSL ... TOnStopLoss mStopLossEventHandlers[]; TOnTakeProfit mTakeProfitEventHandlers[]; // // 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; } // // 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(); } }; //