/////////////////////////////////////////////////////// // // 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.tools.lib.mq5" #include "../Classes/x-saherelm.xalert.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 ... XSCAccount *mAccount; // Account Info Provider // // Constructors ... void XSCTrade( int slippage, // Specify Slippage ulong magicNumber, // Specify Magic Number double maxAllowedSpread = 0, // Max Allowed Spred for Opening Trades int maxAllowedPositions = 0, // Max Allowed Positions double maxAllowedDrawdownFactor = 0 // Max Allowed Drawdown Factor ) { // // Setting Props ... mSlippage = slippage; mMagicNumber = magicNumber; // 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(); } // // Deconstructor ... ~XSCTrade() { // // Remove Pointer ... delete mTrader; delete mAccount; // Clean(mOnModifyEventHandlers); Clean(mStopLossEventHandlers); Clean(mTakeProfitEventHandlers); Clean(mOnForceCloseEventHandlers); Clean(mDealsChangedEventHandlers); Clean(mOrdersChangedEventHandlers); Clean(mOnPartialCloseEventHandlers); Clean(mPositionsChangedEventHandlers); Clean(mTradeStateChangedEventHandlers); } // // Props ... // // Retrieve Slippage ... int GetSlippage() { return mSlippage; } // // Retrieve Magic Number ... ulong GetMagicNumber() { return mMagicNumber; } // double GetMaxAllowedSpread() { return mMaxAllowedSpread; } // int GetMaxAllowedPositions() { return mMaxAllowedPositions; } // void SetMaxAllowedPositions(int value) { // if (value < 0) { value = 0; } // mMaxAllowedPositions = value; } // double GetMaxAllowedDrawdownFactor() { return mMaxAllowedDrawdownFactor; } // // Add Event Listeners ... // void AddOnModifyPositionEventHandler(TOnModify handler) { // Add( handler, mOnModifyEventHandlers // ); } // void AddOnForceClosePositionEventHandler(TOnForceClose handler) { // Add( handler, mOnForceCloseEventHandlers // ); } // void AddOnPartialClosePositionEventHandler(TOnPartialClose handler) { // Add( handler, mOnPartialCloseEventHandlers // ); } // // 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 &mSignal) { // bool result = false; // bool isSpreadCheckEnable = mMaxAllowedSpread > 0; if (!isSpreadCheckEnable) { result = true; } else { // // Retrieve Signal Spread ... double spread = mSignal.GetSpread(); result = spread <= mMaxAllowedSpread; } // return result; } // // Check Account Policy ... bool CheckAccountPolicy( XSignal &mSignal, // 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(mSignal); if (!result) { // state = X_SIGNAL_EXECUTION_FAILED_SPREAD; return result; } // return result; } // // Execute a Signal ... bool ExecuteSignal( XSignal &mSignal, // 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( mSignal.symbol, mSignal.type // ); bool isLong = IsLong(mSignal.type); // if (!mSignal.IsValid()) { // state = X_SIGNAL_EXECUTION_FAILED_INVALID_PARAMS; return result; } // // Prepare Signal Comment ... string mSComment = mSignal.GenerateComment(); if (!Contains(mSComment, mSignal.comment)) { mSignal.comment += mSComment; } // // Handle Market Execution ... if (mSignal.mode == X_ORDER_MODE_MARKET) { // // Do Apply Policies here ... bool hasPolicy = !checkPolicies ? true : CheckAccountPolicy(mSignal, state); if (!hasPolicy) { result = false; } else { // if (isLong) { // result = Buy( mSignal.symbol, mSignal.period, mSignal.volume, mSignal.entry, mSignal.sl, mSignal.tp, mSignal.comment // ); } else { // result = Sell( mSignal.symbol, mSignal.period, mSignal.volume, mSignal.entry, mSignal.sl, mSignal.tp, mSignal.comment // ); } } } // // Handle Stop Execution ... else if (mSignal.mode == X_ORDER_MODE_STOP) { // // Check Conditions ... // // Check Price ... result = isLong ? mSignal.entry > currentEntry : mSignal.entry < currentEntry; if (!result) { // state = X_SIGNAL_EXECUTION_FAILED_PRICE_ERROR; return result; } // // Execute Order ... if (isLong) { // result = BuyStop( mSignal.symbol, mSignal.period, mSignal.volume, mSignal.entry, mSignal.sl, mSignal.tp, lifetime, expiration, mSignal.comment // ); } else { // result = SellStop( mSignal.symbol, mSignal.period, mSignal.volume, mSignal.entry, mSignal.sl, mSignal.tp, lifetime, expiration, mSignal.comment // ); } } // // Handle Limit Execution ... else if (mSignal.mode == X_ORDER_MODE_LIMIT) { // // Check Conditions ... // // Check Price ... result = isLong ? mSignal.entry < currentEntry : mSignal.entry > currentEntry; if (!result) { // state = X_SIGNAL_EXECUTION_FAILED_PRICE_ERROR; return result; } // // Execute Order ... if (isLong) { // result = BuyLimit( mSignal.symbol, mSignal.period, mSignal.volume, mSignal.entry, mSignal.sl, mSignal.tp, lifetime, expiration, mSignal.comment // ); } else { // result = SellLimit( mSignal.symbol, mSignal.period, mSignal.volume, mSignal.entry, mSignal.sl, mSignal.tp, lifetime, expiration, mSignal.comment // ); } } // // Handle Ticket ... if (result) { // state = X_SIGNAL_EXECUTION_SUCCEED; // ulong ticket; if (mSignal.mode == X_ORDER_MODE_MARKET) { ticket = GetLastOpenPositionTicket(); } else { ticket = GetLastPlacedOrderTicket(); } // mSignal.positionId = ticket; // // Handle Store XPositionInfo ... if (mSignal.mode == X_ORDER_MODE_MARKET) { // // TODO: Implement this ... } // // Handle Executing Support Signals ... int supportsCount = ArraySize(mSignal.supports); if (supportsCount > 0) { // int executed = 0; for (int i = 0; i < supportsCount; i++) { // XSignal iSupport = mSignal.supports[i]; // int supIndex = i + 1; string iComment = GenerateSupportTag(ticket); iSupport.comment = iComment; // 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, checkPolicies // ); // if (isExecuted) { result++; } } // return result; } // int ExecuteSpecifiedSignals( XSignal &signals[], // Collection of Signal for Execution XSignal ¬Executeds[], // Not Executed Signal 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); Clean(notExecuteds); // 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++; } else { // AddRef( signals[i], notExecuteds // ); } } // 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 ... XPosition position; result = GetPosition( ticket, position // ) && (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 // ); if (result) { // NotifyModifyEvent( ticket, position.profit, 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 ... XPosition position; result = GetPosition( ticket, position // ); 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 // ); if (result) { // NotifyForceCloseEvent( ticket, position, 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_X_POSITION_TYPES 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; // XPosition position; result = GetPosition( ticket, position // ); if (!result) { return result; } // // Use Default Partial Close Comment ... if (!IsValid(comment)) { // comment += "PClose " + GetPositionComment(ticket); } // result = mTrader.PositionClosePartial( ticket, volume, mSlippage, comment // ); if (result) { // NotifyPartialCloseEvent( ticket, position.profit, 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_X_POSITION_TYPES 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); } // double GetPositionCommission( ulong ticket // Specified Ticket ) { // double result = 0; // XPosition position; bool hasPosition = GetPosition( ticket, position // ); if (!hasPosition) { return result; } // XDeal deals[]; int dealsCount = GetDeals( deals, position.symbol, position.provider, position.period, NULL, DEAL_ENTRY_IN // ); if (IsValidSize(dealsCount)) { // for (int i = 0; i < dealsCount; i++) { // XDeal iDeal = deals[i]; if (iDeal.positionId == ticket) { // result = iDeal.commission; break; } } } // return result; } // // 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_X_POSITION_TYPES 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; } // void GetPositions( XPosition &longs[], // Hold's Longs Result XPosition &shorts[], // Hold's Shorts Result string symbol = NULL, // Trading Symbol string provider = NULL, // Signal Provider ENUM_TIMEFRAMES period = NULL, // Trading Period bool filterByMagic = true, // Get Only Self Open Positions bool forceClean = true // Clean Result Array ) { // // Retrieve Long Positions ... GetPositions( longs, symbol, provider, period, X_POSITION_TYPE_LONG, filterByMagic, forceClean // ); // // Retrieve Short Positions ... GetPositions( shorts, symbol, provider, period, X_POSITION_TYPE_SHORT, filterByMagic, forceClean // ); } // // 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_X_POSITION_TYPES 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) ? 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_X_POSITION_TYPES 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) ? 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_X_POSITION_TYPES 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_X_POSITION_TYPES 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); } // bool GetLastDeal( XDeal &result // Hold's Result ) { // bool mResult = false; // mResult = HistorySelect(0, TimeCurrent()); if (!mResult) { return mResult; } // int lastDealIndex = HistoryDealsTotal() - 1; // mResult = GetDeal( lastDealIndex, result // ); // return mResult; } // // 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; } // // Support Functions ... // // Check a Position has Support or not ... bool HasSupport( ulong ticket, bool forceOpen = true // ) { // bool result = false; // result = ticket > 0; if (!result) { return result; } // if (forceOpen) { // result = IsOpen(ticket); if (!result) { return result; } } // XPosition positions[]; int positionsCount = GetPositions(positions); result = IsValidSize(positionsCount); if (!result) { return result; } // // Extract Support Positions ... XPosition supports[]; int supportsCount = ExtractSupports( positions, supports // ); result = IsValidSize(supportsCount); if (!result) { return result; } // // Loop Through Supports ... for (int i = 0; i < supportsCount; i++) { // XPosition iSupport = supports[i]; // ulong supportedTicket = ExtractSupportedTicket(iSupport.comment); ulong eqmSupportedTicket = ExtractEQMSupportedTicket(iSupport.comment); // result = // (supportedTicket > 0 && ticket == supportedTicket) // || // (eqmSupportedTicket > 0 && ticket == eqmSupportedTicket) // ; if (result) { break; } } // return result; } // // Retrieve Specific Position's Supports ... int GetSupports( ulong ticket, XPosition &dest[], // Result ... bool forceOpen = true // ) { // int result = 0; // Clean(dest); // bool hasSupport = HasSupport( ticket, forceOpen // ); if (!hasSupport) { return result; } // XPosition positions[]; int positionsCount = GetPositions(positions); if (!IsValidSize(positionsCount)) { return result; } // // Extract Support Positions ... XPosition supports[]; int supportsCount = ExtractSupports( positions, supports // ); if (!IsValidSize(supportsCount)) { return result; } // // Loop Through Supports ... for (int i = 0; i < supportsCount; i++) { // XPosition iSupport = supports[i]; // ulong supportedTicket = ExtractSupportedTicket(iSupport.comment); ulong eqmSupportedTicket = ExtractEQMSupportedTicket(iSupport.comment); // bool isOwn = // (supportedTicket > 0 && ticket == supportedTicket) // || // (eqmSupportedTicket > 0 && ticket == eqmSupportedTicket) // ; if (isOwn) { // AddRef( iSupport, dest // ); } } // result = ArraySize(dest); // return result; } // // Retrieve Specific Position's Supports ... int GetSupports( ulong ticket, XOrder &dest[], // Result ... bool forceOpen = true // ) { // int result = 0; // Clean(dest); // bool hasSupport = HasSupport( ticket, forceOpen // ); if (!hasSupport) { return result; } // XOrder orders[]; int ordersCount = GetOrders( orders, NULL, // All Symbols ... NULL, // All Providers ... NULL, // All Periods ... X_POSITION_TYPE_ALL, // All Types ... ORDER_STATE_PLACED, // Untriggere Orders ... true // ); if (!IsValidSize(ordersCount)) { return result; } // // Extract Support Positions ... XOrder supports[]; int supportsCount = ExtractSupports( orders, supports // ); if (!IsValidSize(supportsCount)) { return result; } // // Loop Through Supports ... for (int i = 0; i < supportsCount; i++) { // XOrder iSupport = supports[i]; // ulong supportedTicket = ExtractSupportedTicket(iSupport.comment); ulong eqmSupportedTicket = ExtractEQMSupportedTicket(iSupport.comment); // bool isOwn = // (supportedTicket > 0 && ticket == supportedTicket) // || // (eqmSupportedTicket > 0 && ticket == eqmSupportedTicket) // ; if (isOwn) { // AddRef( iSupport, dest // ); } } // result = ArraySize(dest); // return result; } // // Tools ... // // 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; } // // Prepare Dynamic Volume ... double GetDynamicVolume( string _symbol, double _balanceFactor, double _volumeStep // ) { // double result = 0; // // Validate Inputs ... if (!IsValid(_symbol) || _volumeStep <= 0 || _balanceFactor <= 0) { return result; } // // Retrieve Account Balance ... double balance = mAccount.GetBalance(); // double bStep = balance / _balanceFactor; bStep = MathFloor(bStep); if (bStep == 0) { bStep = 1; } // result = bStep * _volumeStep; // result = NormalizeVolume( result, _symbol // ); // return result; } // // 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); } } // void NotifyModifyEvent( ulong ticket, double profit, string comment // ) { // int count = ArraySize(mOnModifyEventHandlers); if (count <= 0) { return; } // for (int i = 0; i < count; i++) { // TOnModify iHandler = mOnModifyEventHandlers[i]; iHandler( ticket, profit, comment // ); } } // void NotifyForceCloseEvent( ulong ticket, XPosition &position, string comment // ) { // int count = ArraySize(mOnForceCloseEventHandlers); if (count <= 0) { return; } // for (int i = 0; i < count; i++) { // TOnForceClose iHandler = mOnForceCloseEventHandlers[i]; iHandler( ticket, position, comment // ); } } // void NotifyPartialCloseEvent( ulong ticket, double profit, string comment // ) { // int count = ArraySize(mOnPartialCloseEventHandlers); if (count <= 0) { return; } // for (int i = 0; i < count; i++) { // TOnModify iHandler = mOnPartialCloseEventHandlers[i]; iHandler( ticket, profit, comment // ); } } // // 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; } // 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) ... // double mMaxAllowedSpread; // Max Allowed Spred for Opening Trades int mMaxAllowedPositions; // Max Allowed Same Positions double mMaxAllowedDrawdownFactor; // Max Allowed Drawdown Factor // 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 ... // // 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[]; // TOnModify mOnModifyEventHandlers[]; TOnForceClose mOnForceCloseEventHandlers[]; TOnPartialClose mOnPartialCloseEventHandlers[]; // // 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(); } }; // // a Class For Read and Write Trade Info Data in Files ... class XTradeCollector { // // Public ... public: // // Props ... // // Constructor(s) ... void XTradeCollector( string _path = NULL // Base Path ) { // mAccount = new XSCAccount(); // if (IsValid(_path)) { mPath = _path; } else { mPath = "XTradeData" + "\\" + mAccount.GetCompany(); } } // // Deconstructor ... void ~XTradeCollector() {} // bool IsExists(XTradeData &item) { // bool result = false; // int mHandler = GetFileHandlerForRead(item); result = mHandler != INVALID_HANDLE; FileClose(mHandler); // return result; } // bool Save(XTradeData &item) { // bool result = false; // // Check info is Valid ... result = item.IsValid(); if (!result) { return result; } // string content = item.ToString(); content += "\n" + "-----------" + "\n" + "Signal: " + "\n" + "-----------" + "\n" + item.ToString(true); // result = IsValid(content); if (!result) { return result; } // int mHandler = GetFileHandlerForWrite(item); result = mHandler != INVALID_HANDLE; if (!result) { return result; } // FileWrite(mHandler, content); FileFlush(mHandler); FileClose(mHandler); // return result; } // bool SaveSignal(XTradeData &item) { // bool result = false; // string content = item.ToString(true); result = IsValid(content); if (!result) { return result; } // int mHandler = GetSignalFileHandlerForWrite(item); result = mHandler != INVALID_HANDLE; if (!result) { return result; } // FileWrite(mHandler, content); FileFlush(mHandler); FileClose(mHandler); // return result; } // // Conditions only save for Loss Signals ... // this means the profit must be Lower than Zero ... // ans also message Contains SL ... bool SaveConditions(XTradeData &item) { // bool result = false; // // Validate Item ... result = // item.profit < 0 && Contains("SL", item.message) // ; if (!result) { return result; } // string content = item.signal.conditions; result = IsValid(content); if (!result) { return result; } // int mHandler = GetConditionsFileHandlerForWrite(item); result = mHandler != INVALID_HANDLE; if (!result) { return result; } // FileSeek(mHandler, 0, SEEK_END); FileWrite(mHandler, content); FileFlush(mHandler); FileClose(mHandler); // return result; } // // Protected ... protected: // // Private ... private: // // Props ... // string mPath; // Base Path ... // XSCAccount *mAccount; // string GetFilePath(XTradeData &item) { // string fileName = item.GetFileName(); // return GetFilePath(fileName); } string GetFilePath(string fileName) { // string result = ""; // result = // mPath + "\\" + "Trades" + "\\" + fileName + ".x121.log" // ; // return result; } // string GetSignalFilePath(XTradeData &item) { // string fileName = item.GetSignalFileName(); // return GetSignalFilePath(fileName); } string GetSignalFilePath(string fileName) { // string result = ""; // result = // mPath + "\\" + "Signals" + "\\" + fileName + ".x121.log" // ; // return result; } // string GetConditionsFilePath(XTradeData &item) { // bool isLong = IsLong(item.type); // string fileName = item.symbol + "\\" + (isLong ? "Longs" : "Shorts"); // return GetConditionsFilePath(fileName); } string GetConditionsFilePath(string fileName) { // string result = ""; // result = // mPath + "\\" + "Conditions" + "\\" + fileName + ".x121.log" // ; // return result; } // int GetFileHandlerForRead(XTradeData &item) { // int result = INVALID_HANDLE; // string filePath = GetFilePath(item); if (!IsValid(filePath)) { return result; } // result = FileOpen( filePath, FILE_READ | FILE_TXT // ); // return result; } int GetFileHandlerForWrite(XTradeData &item) { // int result = INVALID_HANDLE; // string filePath = GetFilePath(item); if (!IsValid(filePath)) { return result; } // result = FileOpen( filePath, FILE_READ | FILE_WRITE | FILE_TXT // ); // return result; } // int GetSignalFileHandlerForRead(XTradeData &item) { // int result = INVALID_HANDLE; // string filePath = GetSignalFilePath(item); if (!IsValid(filePath)) { return result; } // result = FileOpen( filePath, FILE_READ | FILE_TXT // ); // return result; } int GetSignalFileHandlerForWrite(XTradeData &item) { // int result = INVALID_HANDLE; // string filePath = GetSignalFilePath(item); if (!IsValid(filePath)) { return result; } // result = FileOpen( filePath, FILE_READ | FILE_WRITE | FILE_TXT // ); // return result; } // int GetConditionsFileHandlerForRead(XTradeData &item) { // int result = INVALID_HANDLE; // string filePath = GetConditionsFilePath(item); if (!IsValid(filePath)) { return result; } // result = FileOpen( filePath, FILE_READ | FILE_TXT // ); // return result; } int GetConditionsFileHandlerForWrite(XTradeData &item) { // int result = INVALID_HANDLE; // string filePath = GetConditionsFilePath(item); if (!IsValid(filePath)) { return result; } // result = FileOpen( filePath, FILE_READ | FILE_WRITE | FILE_TXT // ); // return result; } }; // // Trade Handler Class ... class XSCXTradeHandler : public XSCBaseAlert { // // Public ... public: // // // Constructor(s) ... void XSCXTradeHandler(XSCTrade *trader) { // mTrader = trader; mCollector = new XTradeCollector(); } // // Deconstructor ... void ~XSCXTradeHandler() { // delete mTrader; delete mCollector; } // // Getter(s) / Setter(s) ... // bool SaveSignals() { return mSaveSignals; } // void SaveSignals(bool value) { mSaveSignals = value; } // bool SaveTrades() { return mSaveTrades; } // void SaveTrades(bool value) { mSaveTrades = value; } // bool SaveConditions() { return mSaveConditions; } // void SaveConditions(bool value) { mSaveConditions = value; } // int MaxSameTimeTrades() { return maxSameTimeTrades; } // bool AllowLong() { return mAllowLong; } // void AllowLong(bool value) { mAllowLong = value; } // bool AllowShort() { return mAllowShort; } // void AllowShort(bool value) { mAllowShort = value; } // int MaxAllowedLongs() { return mMaxAllowedLongs; } // void MaxAllowedLongs(int value) { // if (value < 0) { value = 0; } // mMaxAllowedLongs = value; } // int MaxAllowedShorts() { return mMaxAllowedShorts; } // void MaxAllowedShorts(int value) { // if (value < 0) { value = 0; } // mMaxAllowedShorts = value; } // bool UseMaxAllowedTradesPerSymbol() { return mUseMaxAllowedTradesPerSymbol; } // void UseMaxAllowedTradesPerSymbol(bool value) { mUseMaxAllowedTradesPerSymbol = value; } // double MaxDrawdownPercentForOpenTrades() { return mMaxDrawdownPercentForOpenTrades; } // void MaxDrawdownPercentForOpenTrades(double value) { // if (value < 0) { value = 0; } // mMaxDrawdownPercentForOpenTrades = value; } // // Trailling ... // bool AllowTrailStops() { return mAllowTrailStops; } // void AllowTrailStops(bool value) { mAllowTrailStops = value; } // bool IgnoreTPOnTrail() { return mIgnoreTPOnTrail; } // void IgnoreTPOnTrail(bool value) { mIgnoreTPOnTrail = value; } // double TrailStartInPoint() { return mTrailStartInPoint; } // void TrailStartInPoint(double value) { // if (value < 0) { value = 0; } // mTrailStartInPoint = value; } // double TrailStepInPoint() { return mTrailStepInPoint; } // void TrailStepInPoint(double value) { // if (value < 0) { value = 0; } // mTrailStepInPoint = value; } // bool TrailBasedOnProfit() { return mTrailBasedOnProfit; } // void TrailBasedOnProfit(bool value) { mTrailBasedOnProfit = value; } // // Recovery ... // bool AllowRecover() { return mAllowRecover; } // void AllowRecover(bool value) { mAllowRecover = value; } // double RecoveryTPPoint() { return mRecoveryTPPoint; } // void RecoveryTPPoint(double value) { // if (value < 0) { value = 0; } // mRecoveryTPPoint = value; } // double RecoverySLPoint() { return mRecoverySLPoint; } // void RecoverySLPoint(double value) { // if (value < 0) { value = 0; } // mRecoverySLPoint = value; } // int MaxAllowedRecover() { return mMaxAllowedRecover; } // void MaxAllowedRecover(int value) { // if (value < 0) { value = 0; } // mMaxAllowedRecover = value; } // double MaxAllowedRecoveryVolume() { return mMaxAllowedRecoveryVolume; } // void MaxAllowedRecoveryVolume(double value) { // if (value < 0) { value = 0; } // mMaxAllowedRecoveryVolume = value; } // double RecoveryVolumeMultiplier() { return mRecoveryVolumeMultiplier; } // void RecoveryVolumeMultiplier(double value) { // if (value < 0) { value = 0; } // mRecoveryVolumeMultiplier = value; } // bool ForcePressuresInRecovery() { return mForcePressuresInRecovery; } // void ForcePressuresInRecovery(bool value) { mForcePressuresInRecovery = value; } // // Hedging ... // bool AllowHedging() { return mAllowHedging; } // void AllowHedging(bool value) { mAllowHedging = value; } // double HedgeVolumeFactor() { return mHedgeVolumeFactor; } // void HedgeVolumeFactor(double value) { // if (value < 0) { value = 0; } // mHedgeVolumeFactor = value; } // int MinTradesForHedge() { return mMinTradesForHedge; } // void MinTradesForHedge(int value) { // if (value < 0) { value = 0; } // mMinTradesForHedge = value; } // double HedgeMinProfitPerVolumeFactor() { return mHedgeMinProfitPerVolumeFactor; } // void HedgeMinProfitPerVolumeFactor(double value) { // if (value < 0) { value = 0; } // mHedgeMinProfitPerVolumeFactor = value; } // // Position Protecting ... // bool AllowProtectPositions() { return mAllowProtectPositions; } // void AllowProtectPositions(bool value) { mAllowProtectPositions = value; } // // Tools ... // // Calculate Max Drawdown and it's Percent ... double GetMaxDrawdown() { // XPosition positions[]; int positionsCount = mTrader.GetPositions(positions); if (IsValidSize(positionsCount)) { double mEquity = mTrader.mAccount.GetEquity(); if (mEquity > maxDrawdown) { maxDrawdown = mEquity; } // drawdownPercent = (maxDrawdown - mEquity) / (staticBalanceForCalculateDrawdown > 0 ? staticBalanceForCalculateDrawdown : maxDrawdown) * 100; drawdownPercent = NormalizeDouble(drawdownPercent, 3); } else { // maxDrawdown = 0.0; drawdownPercent = 0.0; } // return drawdownPercent; } // // Trade Handling Functions ... // // First Step of Trade Handling ... // Since Must Call when a Signal Executed ... void AddData( XSignal &signal, // Executed Signal double commission = 0, // Commission bool forceTrail = false, // Force Signal Trailling Stop bool forceRecover = false // Force Signal Recovery ) { // // Check Signal Valid ... if (!signal.IsValid()) { return; } // // Check Signal Support or Recovery ... bool isSupport = IsSupport(signal.comment); bool isRecovery = ExtractRecoveredTicket(signal.comment) > 0; // XTradeData item; bool isFilled = item.Fill(signal); if (!isFilled) { return; } // item.commission = commission; // // Trailling Configuration ... // // Force Trail used to implement Trailing for // Custom Positions ... if (mAllowTrailStops || forceTrail) { // if (!isSupport && !isRecovery) { item.allowTrailStop = true; } // item.ignoreTPOnTrail = mIgnoreTPOnTrail; item.trailStepInPoint = mTrailStepInPoint; item.trailStartInPoint = mTrailStartInPoint; item.trailBasedOnProfit = mTrailBasedOnProfit; } // // Recovery Configuration ... // // Force Recovery used to implement Recovery for // Custom Positions ... if (mAllowRecover || forceRecover) { // if (!isSupport && !isRecovery) { item.allowRecover = true; } // item.recoveryTPPoint = mRecoveryTPPoint; item.recoverySLPoint = mRecoverySLPoint; item.maxAllowedRecover = mMaxAllowedRecover; item.recoveryVolumeMultiplier = mRecoveryVolumeMultiplier; // ENUM_POSITION_TYPE _type; bool isConverted = ToPositionType( _type, item.type // ); if (isConverted) { item.recoveryLookingType = GetOppositPositionType(_type); } } // Add(item); // SaveSignal(item); } // void Finish(const XDeal &deal) { // int idx = -1; bool hasItem = HasItem( deal.positionId, idx // ); if (!hasItem) { return; } // // Update Item Info ... mData[idx].swap = deal.swap; mData[idx].endTime = deal.time; mData[idx].profit = deal.profit; // mData[idx].message = deal.reason == DEAL_REASON_TP ? "TP" : "SL"; // Save(idx); } // void Finish( const ulong ticket, const XPosition &position, const string comment // ) { // int idx = -1; bool hasItem = HasItem( ticket, idx // ); if (!hasItem) { return; } // // Update Item Info ... mData[idx].swap = position.swap; mData[idx].endTime = TimeCurrent(); mData[idx].profit = position.profit; // mData[idx].message = comment; // Save(idx); } // // this Method call's by a Timer, // or in OnTick for Update Positions, // Data ... void UpdateData() { // XPosition positions[]; int count = mTrader.GetPositions(positions); if (!IsValidSize(count)) { return; } // for (int i = 0; i < count; i++) { // XPosition iPosition = positions[i]; // int idx = -1; bool isExists = HasItem( iPosition.ticket, idx // ); if (!isExists) { // // Add New Data ... // // Find Executed Signal Deal History ... XDeal deals[]; double commission = 0; int dealsCount = mTrader.GetDeals( deals, iPosition.symbol, iPosition.provider, iPosition.period, NULL, DEAL_ENTRY_IN // ); if (IsValidSize(dealsCount)) { // for (int i = 0; i < dealsCount; i++) { // XDeal iDeal = deals[i]; if (iDeal.positionId == iPosition.ticket) { // commission = iDeal.commission; break; } } } // XTradeData iData; iData.Fill( iPosition // ); // iData.ticket = iPosition.ticket; // Add(iData); } else { // // Update Exists ... mData[idx].Update(iPosition); } } // count = Count(); if (count > maxSameTimeTrades) { maxSameTimeTrades = count; } // GetMaxDrawdown(); } // void UpdateSignal(XSignal &signal) { // if (!signal.IsValid()) { return; } // int count = Count(); if (!IsValidSize(count)) { return; } // for (int i = 0; i < count; i++) { // bool isOwn = mData[i].IsOwn( signal.symbol, signal.provider, signal.period, ToPositionType(signal.type) // ); if (isOwn) { mData[i].Fill(signal); } } } // void RemoveSignal(XSignal &signal) { // if (!signal.IsValid()) { return; } // int signalIDX = -1; ENUM_X_POSITION_TYPES xType = ToPositionType(signal.type); bool hasSignal = HasItem( signal.symbol, signal.provider, signal.period, xType, signalIDX // ); if (!hasSignal || !IsValidIndex(signalIDX)) { return; } // // Remove Item From List ... ArrayRemove( mData, signalIDX, 1 // ); } // // Do all Protections ... void HandleProtection() { // int count = Count(); if (!IsValidSize(count)) { return; } // // Do Hedging ... if (mAllowHedging) { // // Retrieve Positions ... XPosition positions[]; int positionsCount = mTrader.GetPositions( positions // ); // bool isParamsValid = mHedgeVolumeFactor > 0 && mHedgeMinProfitPerVolumeFactor > 0; // bool isCountValid = mMinTradesForHedge <= 0 ? positionsCount >= 1 : positionsCount >= mMinTradesForHedge; // // Validate State ... if (isParamsValid && isCountValid) { // double swaps = 0; double profits = 0; double volumes = 0; double commissions = 0; double requiredProfitsForHedge = 0; CalculateHedgeData( positions, swaps, profits, volumes, commissions, requiredProfitsForHedge // ); // bool canHedge = profits >= requiredProfitsForHedge; if (canHedge) { // string comment = "Hedging ..."; // if (IsValidSize(positionsCount)) { // int closeds = mTrader.Close( positions, comment // ); if (IsValidSize(closeds)) { // string msg = ToString(positionsCount) + " Closed Due Hedge Action in: " + ToString(profits) + " ..."; Alert(msg); // return; } } } } } // // Do Force Closing ... // // Loop through Data ... for (int i = 0; i < count; i++) { // ulong ticket = mData[i].ticket; double profit = mData[i].profit; double volume = mData[i].volume; string symbol = mData[i].symbol; string provider = mData[i].provider; bool isLong = IsLong(mData[i].type); ENUM_TIMEFRAMES period = mData[i].period; double points = GetPoints(mData[i].symbol); bool ignoreTPOnTrail = mData[i].ignoreTPOnTrail; double recoveryTPPoint = mData[i].recoveryTPPoint; double recoverySLPoint = mData[i].recoverySLPoint; int maxAllowedRecover = mData[i].maxAllowedRecover; double trailStepInPoints = mData[i].trailStepInPoint; double trailStartInPoint = mData[i].trailStartInPoint; bool trailBasedOnProfit = mData[i].trailBasedOnProfit; double recoveryVolumeMultiplier = mData[i].recoveryVolumeMultiplier; // XPosition iPosition; bool hasPosition = mTrader.GetPosition( ticket, iPosition // ); if (!hasPosition) { continue; } // // Allow Trail Only for Positions Which // doesnt Have Any Support ... bool iHasSupport = mTrader.HasSupport( ticket // ); if (iHasSupport) { continue; } // // Try to Detect Recovered Positions ... // XPosition positions[]; XPosition recoveries[]; int recoveriesCount = 0; int positionsCount = mTrader.GetPositions( positions, symbol, provider, period // ); if (positionsCount > 0) { // recoveriesCount = ExtractRecoveries( ticket, positions, recoveries // ); } // // Handle Recovery Break Event if Hedging is Disabled ... if (mData[i].allowRecover) { // if (mData[i].recoveryLevel <= 0) { // if (profit > 0 && iPosition.tp == 0) { // double proftiInPoints = profit / volume; bool canClose = proftiInPoints >= recoveryTPPoint; if (canClose) { // string comment = "Recovery TP ..."; bool isClosed = mTrader.Close( ticket, comment // ); if (isClosed) { // string msg = "Position (" + ToString(ticket) + ") Hit's Recovery TP ..."; Alert(msg); break; } } } } else { // if (recoveriesCount > 0 && !mAllowHedging) { // XPosition mustClose[]; AddRef( iPosition, mustClose // ); // // Summary Calculations ... double rVolume = volume; double rProfit = profit; bool hasMaxVolume = false; double rSwap = mData[i].swap; double rCommission = mData[i].commission; for (int j = 0; j < recoveriesCount; j++) { // rSwap += recoveries[j].swap; rProfit += recoveries[j].profit; rVolume += recoveries[j].volume; rCommission += mTrader.GetPositionCommission(recoveries[j].ticket); // if (!hasMaxVolume && mMaxAllowedRecoveryVolume > 0 && recoveries[j].volume >= mMaxAllowedRecoveryVolume) { hasMaxVolume = true; } // AddRef( recoveries[j], mustClose // ); } double profitSummary = rProfit + (-1 * rSwap) - MathAbs(rCommission); // double requiredProfitPoints = recoveriesCount * recoveryTPPoint; // if (mData[i].recoveryLevel >= 2) // { // // // requiredProfitPoints /= mData[i].recoveryLevel; // if (requiredProfitPoints < recoveryTPPoint) // { // requiredProfitPoints = recoveryTPPoint; // } // } // if (profitSummary > 0) { // double rProfitInPoints = profitSummary / volume; // bool canFinishRecovery = rProfitInPoints >= requiredProfitPoints; if (canFinishRecovery) { // // Here we Have to close All Recoveries // and Position it Self ... // string comment = "Recovery Done ..."; // int closeds = mTrader.Close( mustClose, comment // ); if (closeds > 0) { // string msg = "EQM Done Recovery (" + ToString(closeds) + ") Positions ..."; Alert(msg); // break; } } } // Clean(mustClose); Clean(positions); Clean(recoveries); } } } // // Retriece CIndex Bar ... XOHCL cBar; bool isBarInited = cBar.Init( symbol, period, 1 // ); if (!isBarInited) { continue; } // // For Trend ... XOHCL tmpHSW[]; XOHCL tmpLSW[]; // // Detect Bullish/Bearish Patterns and Trends ... // // Bullish ... bool hasBullishPower = cBar.HasBullishPower(); bool hasBullishPattern = HasBullishPattern(cBar); bool hasBullishPressure = cBar.HasBullishPressure(); bool isBullishTrend = cBar.HasBullishTrend( tmpHSW, tmpLSW, true // ); bool hasBullishSigns = // // isBullishTrend && cBar.IsBullish() && hasBullishPattern && (hasBullishPower && hasBullishPressure) // ; // // Bearish ... bool hasBearishPower = cBar.HasBearishPower(); bool hasBearishPattern = HasBearishPattern(cBar); bool hasBearishPressure = cBar.HasBearishPressure(); bool isBearishTrend = cBar.HasBearishTrend( tmpHSW, tmpLSW, true // ); bool hasBearishSigns = // // isBearishTrend && cBar.IsBearish() && hasBearishPressure && (hasBearishPower && hasBearishPattern) // ; // // Trail ... if (mData[i].allowTrailStop) { // // Do Trail ... // // Only Can Trail if Position In Profit ... if (profit > 0) { // // Current Profit ... double profitInPoints = (profit / volume); // // Check Trailling Method ... if (trailBasedOnProfit) { // // if Trailling Method is Based on Profits Growing // these Values must Greater than 0 ... if (trailStartInPoint > 0 && trailStepInPoints > 0) { // double requiredProfit = trailStartInPoint + (mData[i].trailLevel * trailStepInPoints); bool isProfitPassed = profitInPoints >= requiredProfit; if (isProfitPassed) { // // Calculate new Level SL ... double sl = isLong ? iPosition.entry + (mData[i].trailLevel * (trailStepInPoints * points)) : iPosition.entry - (mData[i].trailLevel * (trailStepInPoints * points)); sl = NormalizePrice( sl, symbol // ); // // Calculate TP ... double tp = ignoreTPOnTrail ? 0 : iPosition.tp; // if (sl != iPosition.sl) { // bool isModified = mTrader.Modify( ticket, sl, tp // ); if (isModified) { // // Increase Trail Level ... mData[i].trailLevel++; // string msg = "Position (" + ToString(ticket) + ") Stops in Level: " + ToString(mData[i].trailLevel) + " Trailed Successfully ..."; Alert(msg); } } } } } else { // // Handle Trailling Based On Bars ... // bool canTrail = true; if (trailStartInPoint > 0) { // // Check Profit ... canTrail = profitInPoints >= trailStartInPoint; } // if (canTrail) { // // Zero Index Bar ... XOHCL zBar; bool isInited = zBar.Init( symbol, period, 0 // ); if (isInited) { // // Get Previous Bar ... XOHCL cBar; isInited = zBar.GetPreviousBar(cBar); if (isInited) { // // Get Prev of Previous Bar ... XOHCL pBar; isInited = cBar.GetPreviousBar(pBar); if (isInited) { // // Here we have to Check Bar Closes for // Trailling Stops ... canTrail = // isLong ? cBar.IsBullish() && cBar.close > pBar.open : cBar.IsBearish() && cBar.close < pBar.open // ; if (canTrail) { // // Calculate new Level SL ... double sl = isLong ? cBar.low : cBar.high; sl = NormalizePrice( sl, symbol // ); // // Calculate TP ... double tp = ignoreTPOnTrail ? 0 : iPosition.tp; // if (sl != iPosition.sl) { // bool isModified = mTrader.Modify( ticket, sl, tp // ); if (isModified) { // // Increase Trail Level ... mData[i].trailLevel++; // string msg = "Position (" + ToString(ticket) + ") Stops in Level: " + ToString(mData[i].trailLevel) + " Trailed Successfully ..."; Alert(msg); } } } } } } } } } } // // Recovery ... if (mData[i].allowRecover) { // // Do Recovery ... // // Check Looking for Direction ... ENUM_X_POSITION_TYPES recoveryLookingType = mData[i].recoveryLookingType; if (recoveryLookingType == X_POSITION_TYPE_ALL || recoveryLookingType == X_POSITION_TYPE_NONE) { continue; } // bool isDirectional = recoveryLookingType == mData[i].type; // bool hasPressure = !mForcePressuresInRecovery ? true : isDirectional // // Looking For Directional Pressure ... ? isLong ? hasBullishSigns : hasBearishSigns // // Looking For InDirectional Pressure ... : isLong ? hasBearishSigns : hasBullishSigns; // // Check Required Properties Validation ... if ( recoveryTPPoint > 0 && recoverySLPoint > 0 && (maxAllowedRecover <= 0 ? true : mData[i].recoveryLevel < maxAllowedRecover)) { // // Calculate requirements ... double distanceInPoints = (MathAbs(profit) / volume); // double _volumeMultiplier = ((mData[i].recoveryLevel + 1) * recoveryVolumeMultiplier); // double _volume = // volume * (_volumeMultiplier <= 0 ? 1 : _volumeMultiplier); double _volume = mData[i].recoveryVolume <= 0 ? volume * recoveryVolumeMultiplier : mData[i].recoveryVolume; if (mMaxAllowedRecoveryVolume > 0 && _volume > mMaxAllowedRecoveryVolume) { _volume = mMaxAllowedRecoveryVolume; } // string _comment = GenerateRecoveryTag(ticket); // XSignal rSignal; bool isPrepared = false; // if (profit < 0 && hasPressure && !isDirectional && distanceInPoints >= recoverySLPoint) { // FixRecoveredPositionTPSL(iPosition); // ENUM_POSITION_TYPE _type = isLong ? POSITION_TYPE_SELL : POSITION_TYPE_BUY; double _entry = GetEntry(symbol, _type); // isPrepared = rSignal.Prepare( symbol, provider, period, _type, X_ORDER_MODE_MARKET, _entry, _volume, 0, 0 // ); } else if (profit >= 0 && hasPressure && isDirectional) { // FixRecoveredPositionTPSL(iPosition); // ENUM_POSITION_TYPE _type = isLong ? POSITION_TYPE_BUY : POSITION_TYPE_SELL; double _entry = GetEntry(symbol, _type); // isPrepared = rSignal.Prepare( symbol, provider, period, _type, X_ORDER_MODE_MARKET, _entry, _volume, 0, 0 // ); } // if (isPrepared && rSignal.IsValid()) { // // Attach Recovery Tag ... rSignal.comment = _comment; // // Execute Recovery Signal ... bool isExecuted = ExecuteRecoverySignal(rSignal); if (isExecuted) { // // Increase Recovery Level ... mData[i].recoveryLevel++; mData[i].recoveryVolume = _volume * recoveryVolumeMultiplier; // // Try to Reverse Looking for Next Recovery // Position Type ... ENUM_POSITION_TYPE _type; bool isConverted = ToPositionType( _type, recoveryLookingType // ); if (isConverted) { mData[i].recoveryLookingType = GetOppositPositionType(_type); } } } } } } } // // Do Position Protecting ... void HandlePositionProtecting() { // if (!mAllowProtectPositions) { return; } // XPosition mainPositions[]; // XPosition positions[]; int positionsCount = mTrader.GetPositions( positions, NULL, // All Symbols ... NULL, // All Providers ... NULL, // All Periods ... NULL, // All Types ... true // Filter By Magic ... ); if (!IsValidSize(positions)) { return; } // // Filter Main Positions ... for (int i = 0; i < positionsCount; i++) { // XPosition iPosition = positions[i]; if (!iPosition.IsValid()) { continue; } // // Check Support or Recovery ... bool isSupport = IsSupport(iPosition.comment); bool isRecovery = ExtractRecoveredTicket(iPosition.comment) > 0; if (isSupport || isRecovery) { continue; } // AddRef( iPosition, mainPositions // ); } // int mainPositionsCount = ArraySize(mainPositions); if (!IsValidSize(mainPositionsCount)) { return; } // // Loop Through Main Positions ... for (int i = 0; i < mainPositionsCount; i++) { // XPosition iPosition = mainPositions[i]; if (!iPosition.IsValid()) { continue; } // // Find iPosition Related TradeData ... int idx = -1; bool hasItem = HasItem( iPosition.ticket, idx // ); if (!hasItem) { continue; } // XTradeData iData = mData[idx]; if (!iData.IsValid()) { continue; } // // Now we Have a Main Positions and // we Make Sure this Position has a TradeData Model ... // Next things is Extract it's Support Positions ... XPosition supports[]; for (int j = 0; j < positionsCount; j++) { // XPosition jPosition = positions[j]; // bool isSupport = IsSupport(jPosition.comment); if (!isSupport) { continue; } // ulong parentTicket = ExtractSupportedTicket(jPosition.comment); if (parentTicket != iPosition.ticket) { continue; } // AddRef( jPosition, supports // ); } // int supportsCount = ArraySize(supports); // // Collect Main Position Related Data ... // // Hold a Position and All of it's Supports ... XPosition iPack[]; // // Fill Pack ... AddRef( iPosition, iPack // ); // if (IsValidSize(supportsCount)) { // Copy( supports, iPack // ); } // int iPackCount = ArraySize(iPack); if (!IsValidSize(iPackCount)) { continue; } // double volume = 0; double profit = 0; double commission = 0; // // Calculate Required Datas ... for (int j = 0; j < iPackCount; j++) { // XPosition jPosition = iPack[j]; if (!jPosition.IsValid()) { continue; } // XPosition uPosition; bool hasPosition = mTrader.GetPosition( jPosition.ticket, uPosition // ); if (!hasPosition) { continue; } // volume += uPosition.volume; profit += uPosition.profit; // double jCommission = mTrader.GetPositionCommission(jPosition.ticket); commission += jCommission; } // // here we have to Check Protection Conditions ... // // Check Position State ... bool isInProfit = profit > 0; // // Based On Single Position ... if (iPackCount == 1) { // // Based on Profit ... if (isInProfit) { } // // Based On DrawDown ... else { } } // // Multiple Protected Positions ... else { // // Based on Profit ... if (isInProfit) { } // // Based On DrawDown ... else { } } } } // // Validate Signal For Execution ... bool CanExecute(XSignal &signal) { // bool result = false; // // Validate Signal ... result = signal.IsValid(); if (!result) { return result; } // // TODO: // Here we can apply Same type or Opposit Type // Signals behaviour ... // also check For Market Open ... // // Check Market ... // TODO: Fix this ... // result = mSymbolSession.CanTrade(signal.symbol); // if (!result) { // return result; // } // return result; } // bool ExecuteSignal( XSignal &signal, // Signal for Execution ENUM_X_SIGNAL_EXECUTION_RESULT &state, // Execution State bool ignorePolicies = false // Ignore Execution Policies ) { // bool result = false; // // Check Signal Validation ... result = signal.IsValid(); if (!result) { return result; } // // Filter Signals if Necessary ... result = CanExecute(signal); if (!result) { // state = X_SIGNAL_EXECUTION_FAILED_INVALID_PARAMS; return result; } // // Check Policies ... if (!ignorePolicies) { // bool isLong = IsLong(signal.type); // // Check Allow Trade Type ... result = isLong ? mAllowLong : mAllowShort; if (!result) { // state = X_SIGNAL_EXECUTION_FAILED_NOT_ALLOWED; return result; } // // Check Trades Count ... if (mMaxAllowedLongs > 0 || mMaxAllowedShorts > 0) { // XPosition longs[]; XPosition shorts[]; // // Counting Positions ... if (mUseMaxAllowedTradesPerSymbol) { // mTrader.GetPositions( longs, shorts, signal.symbol // ); } else { // mTrader.GetPositions( longs, shorts, NULL // All Symbols ... ); } // int longsCount = ArraySize(longs); int shortsCount = ArraySize(shorts); // result = // // Long ... isLong ? mMaxAllowedLongs <= 0 ? true : longsCount < mMaxAllowedLongs // // Short ... : mMaxAllowedShorts <= 0 ? true : shortsCount < mMaxAllowedShorts // ; if (!result) { // state = X_SIGNAL_EXECUTION_FAILED_MAX_REACHED; return result; } } // // Check Drawdown ... if (mMaxDrawdownPercentForOpenTrades > 0) { // drawdownPercent = GetMaxDrawdown(); // result = drawdownPercent <= 0 ? true : drawdownPercent < mMaxDrawdownPercentForOpenTrades; if (!result) { // state = X_SIGNAL_EXECUTION_FAILED_NO_EQUITY; return result; } } } // // Execute Signal ... result = mTrader.ExecuteSignal( signal, state // ); if (result) { // double commission = mTrader.GetPositionCommission(signal.positionId); // // Add Signal to Trade Handler ... AddData( signal, commission // ); // string msg = (signal.type == POSITION_TYPE_BUY ? "Long" : "Short") + " Signal Provided by: " + signal.provider + (signal.pushers > 1 ? " Pushers: " + ToString(signal.pushers) : "") + " on: " + signal.symbol + " in: " + ToString(signal.period) + " Executed Successfully ..."; Alert(msg); } // return result; } // // Protected ... protected: // // Props ... // bool mSaveSignals; // Save Signals bool mSaveTrades; // Save Trades bool mSaveConditions; // Save SL Conditions // XSymbolSessionParser mSymbolSession; // Check Symbol Session // bool mAllowLong; // Allow Long/Buy Trade Type bool mAllowShort; // Allow Short/Sell Trade Type int mMaxAllowedLongs; // Max Allowe Long/Buy Trades int mMaxAllowedShorts; // Max Allowe Short/Sell Trades bool mUseMaxAllowedTradesPerSymbol; // Use Max Allowed Trades Per Symbol double mMaxDrawdownPercentForOpenTrades; // Max Drawdown Percent for Open Trades // XSCTrade *mTrader; // Instance of Trader Class XTradeCollector *mCollector; // Instance of Trade Collector Class // // Trailling ... bool mAllowTrailStops; // Trail All Trades Stops bool mIgnoreTPOnTrail; // Ignore SL Trailed TP bool mTrailBasedOnProfit; // Do Trail Based on Profit Points double mTrailStartInPoint; // Trail Starts in Points of Profit double mTrailStepInPoint; // Profit Must Grows Point to do Trailling // // Recovery ... bool mAllowRecover; // Allow Signal Recovery int mMaxAllowedRecover; // Max Allowed Recovery double mRecoveryTPPoint; // Recovery TP in Points double mRecoverySLPoint; // Recovery SL in Points bool mForcePressuresInRecovery; // Use Direction Pressures In Recovery double mRecoveryVolumeMultiplier; // Recovery Volume Multiplier double mMaxAllowedRecoveryVolume; // Max Allowed Recovery Volume // // Hedging ... bool mAllowHedging; // Hedge Trades int mMinTradesForHedge; // Minimum Open Trades for Do Hedge double mHedgeVolumeFactor; // Hedging Volume Factor double mHedgeMinProfitPerVolumeFactor; // Hedging Min Required Profit Per Volume Factor // // Position Protecting ... // bool mAllowProtectPositions; // Allow Protect Positions // XTradeData mData[]; // Hold Trade Data // // Private ... private: // // Props ... int maxSameTimeTrades; // Max Same Time Trades double maxDrawdown; // Max Drawdown double drawdownPercent; // Drawdown Percent double staticBalanceForCalculateDrawdown; // Static Balance for Max Drawdown Calculation // // Count Data ... int Count() { return ArraySize(mData); } // // Add Item ... bool Add(XTradeData &item) { // bool result = false; // result = item.IsValid(); if (!result) { return result; } // int index = -1; if (item.ticket > 0) { // result = !HasItem( item.ticket, index // ); } else { // result = !HasItem( item.symbol, item.provider, item.period, item.type, index // ); } if (!result || IsValidIndex(index)) { // result = false; return result; } // AddRef( item, mData // ); // return result; } // // Find Item Index ... bool HasItem( ulong ticket, int &index // ) { // bool result = false; // index = -1; // int count = Count(); result = IsValidSize(count); if (!result) { return result; } // for (int i = 0; i < count; i++) { // result = mData[i].IsOwn(ticket); if (result) { // index = i; break; } } // return result; } // // Find Item Index ... bool HasItem( string symbol, string provider, ENUM_TIMEFRAMES period, ENUM_X_POSITION_TYPES type, int &index // ) { // bool result = false; // index = -1; // // Validate ... result = // IsValid(symbol) && IsValid(period) && IsValid(provider) && type != X_POSITION_TYPE_ALL && type != X_POSITION_TYPE_NONE // ; if (!result) { return result; } // int count = Count(); result = IsValidSize(count); if (!result) { return result; } // for (int i = 0; i < count; i++) { // result = mData[i].IsOwn( symbol, provider, period, type // ); if (result) { // index = i; break; } } // return result; } // void Save(int index) { // int count = Count(); if (!IsValidIndex(index) || index > count - 1) { return; } // // Save Trade ... if (mSaveTrades) { mCollector.Save(mData[index]); } // if (mSaveConditions) { mCollector.SaveConditions(mData[index]); } // // Remove Item From List ... ArrayRemove( mData, index, 1 // ); } // void SaveSignal(XTradeData &item) { // if (!mSaveSignals) { return; } // // Save Signal ... mCollector.SaveSignal(item); } // // Calculate Required Data for Hedging ... void CalculateHedgeData( double &profits, double &commissions, double &requiredProfitsForHedge // ) { // // Reset Values ... profits = 0; commissions = 0; requiredProfitsForHedge = 0; // // Validate Configurations ... if (mHedgeVolumeFactor <= 0 || mHedgeMinProfitPerVolumeFactor <= 0) { return; } // // Check Positions Exists For Hedging ... int count = Count(); if (!IsValidSize(count)) { return; } // double swaps = 0; double volumes = 0; for (int i = 0; i < count; i++) { // swaps += mData[i].swap; profits += mData[i].profit; volumes += mData[i].volume; commissions += mData[i].commission; } // // Calculate required Profits for Hedging ... requiredProfitsForHedge = ((volumes / mHedgeVolumeFactor) * mHedgeMinProfitPerVolumeFactor); requiredProfitsForHedge += -1 * (swaps); requiredProfitsForHedge -= commissions; } // // Calculate Required Data for Hedging ... void CalculateHedgeData( XPosition &positions[], double &swaps, double &profits, double &volumes, double &commissions, double &requiredProfitsForHedge // ) { // // Reset Values ... swaps = 0; profits = 0; volumes = 0; commissions = 0; requiredProfitsForHedge = 0; // // Validate Configurations ... if (mHedgeVolumeFactor <= 0 || mHedgeMinProfitPerVolumeFactor <= 0) { return; } // // Check Positions Exists For Hedging ... int count = ArraySize(positions); if (!IsValidSize(count)) { return; } // for (int i = 0; i < count; i++) { // XPosition iPosition = positions[i]; double iCommission = mTrader.GetPositionCommission(iPosition.ticket); // swaps += iPosition.swap; profits += iPosition.profit; volumes += iPosition.volume; commissions += MathAbs(iCommission); } // // Calculate required Profits for Hedging ... requiredProfitsForHedge = ((volumes / mHedgeVolumeFactor) * mHedgeMinProfitPerVolumeFactor); requiredProfitsForHedge += commissions; requiredProfitsForHedge += -1 * (swaps); } // bool FixRecoveredPositionTPSL(XPosition &position) { // bool result = false; // result = position.IsValid(); if (!result) { return result; } // double points = GetPoints(position.symbol); // // // // Try to Remove SL and TP of Recovery Signals ... // if (position.sl > 0 || position.tp > 0) // { // // // string comment = "EQM Recover Remove TP/SL"; // result = mTrader.Modify( // position.ticket, // 0, // 0, // comment // // ); // } // // Try to Remove TP of Recovery Signals ... if (position.tp > 0) { // double tp = 0; bool isLong = IsLong(position.type); double reward = MathAbs(position.tp - position.entry) / points; if (reward <= mRecoveryTPPoint) { // reward = (mRecoveryTPPoint * 2 * points); tp = isLong ? position.entry + reward : position.entry - reward; tp = NormalizePrice(tp, position.symbol); } // string comment = "EQM Recover Fix TP/SL"; result = mTrader.Modify( position.ticket, position.sl, tp, comment // ); } // return result; } // bool ExecuteRecoverySignal(XSignal &signal) { // bool result = false; // ENUM_X_SIGNAL_EXECUTION_RESULT state; result = mTrader.ExecuteSignal( signal, state, ORDER_TIME_GTC, NULL, false // ); // return result; } // }; //