/// <summary>
        /// Update current instance with new information.
        /// </summary>
        public void Update(PositionInfo other)
        {
            _symbol = other.Symbol;

            if (other.Volume.HasValue)
            {
                _volume = other.Volume;
            }

            if (other.Result.HasValue)
            {
                _result = other.Result;
            }

            if (other.PendingBuyVolume.HasValue)
            {
                _pendingBuyVolume = other.PendingBuyVolume;
            }

            if (other.Price.HasValue)
            {
                _price = other.Price;
            }

            if (other.Basis.HasValue)
            {
                _basis = other.Basis;
            }

            if (other.ClosedResult.HasValue)
            {
                _closedResult = other.ClosedResult;
            }

            if (other.MarketValue.HasValue)
            {
                _marketValue = other.MarketValue;
            }

            if (other._commission.HasValue)
            {
                _commission = other._commission;
            }

            if (other._pendingBuyVolume.HasValue)
            {
                _pendingBuyVolume = other._pendingBuyVolume;
            }

            if (other._pendingSellVolume.HasValue)
            {
                _pendingSellVolume = other._pendingSellVolume;
            }
        }
        /// <summary>
        /// Helper, converts from MBT to OFxP object.
        /// </summary>
        PositionInfo? ConvertToPositionInfo(MbtPosition position)
        {
            PositionInfo result = new PositionInfo();

            Symbol? symbol = _adapter.GetSymbolByName(position.Symbol, true);
            if (symbol.HasValue == false)
            {
                return null;
            }

            result.Symbol = symbol.Value;
            result.Volume = position.CloseableShares;
            result.Commission = (decimal)Math.Round(position.Commission, 4);
            result.PendingBuyVolume = position.PendingBuyShares;
            result.PendingSellVolume = position.PendingSellShares;
            result.Result = (decimal)Math.Round(position.RealizedPNL, 4);

            return result;
        }
 public void UpdatePositionsInfo(AccountInfo account, PositionInfo[] positionsInfo)
 {
     lock (this)
     {// Will only add it once, the remaining will just return false.
         if (_subscribers.Count > 0)
         {
             // Establish account subscribers and deliver them the update.
             this.SendRespondingToMany(_subscribers, new PositionsInformationUpdateResponseMessage(account, positionsInfo, true));
         }
     }
 }
 void RaisePositionsUpdateEvent(AccountInfo info, PositionInfo[] positionsInfo)
 {
     if (PositionsUpdateEvent != null)
     {
         PositionsUpdateEvent(this, info, positionsInfo);
     }
 }
        /// <summary>
        /// Helper.
        /// </summary>
        bool RecalculatePositionBasis(ref PositionInfo position, int volumeChange, decimal newBasis)
        {
            if (position.Volume == 0)
            {
                position.Basis = newBasis;
                position.Volume = volumeChange;
                return true;
            }

            if ((position.Volume > 0 && volumeChange > 0)
                || (position.Volume < 0 && volumeChange < 0))
            {// Same direction, basis recalculated as corresponding average.
                decimal currentSum = position.Volume.Value * position.Basis.Value;
                decimal newSum = volumeChange * newBasis;

                position.Volume = position.Volume + volumeChange;
                position.Basis = Math.Round((currentSum + newSum) / position.Volume.Value, 4);
            }
            else
            {// Different direction.
                if (Math.Abs(position.Volume.Value) < Math.Abs(volumeChange))
                {// New volume has overtaken existing volume.
                    position.Basis = newBasis;
                    position.Volume = position.Volume + volumeChange;
                }
                else
                {// New volume is only part of existing volume, basis remains unchaged.
                    position.Volume = position.Volume + volumeChange;
                }
            }

            if (position.Volume == 0)
            {
                position.Basis = 0;
            }

            return true;
        }
        void _provider_PositionsUpdateEvent(IOrderSink provider, AccountInfo accountInfo, PositionInfo[] positionsInfos)
        {
            foreach (PositionInfo info in positionsInfos)
            {
                if (info.Symbol.IsEmpty)
                {
                    SystemMonitor.Warning("Empty symboled position.");
                    continue;
                }

                Position position = ObtainPositionBySymbol(info.Symbol);
                if (position != null)
                {
                    position.UpdateInfo(info);
                }
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public bool UpdateInfo(PositionInfo info)
        {
            lock (this)
            {
                _info.Update(info);
            }

            RecalculateParameters(false);

            if (this.UpdateEvent != null)
            {
                UpdateEvent(this);
            }

            return true;
        }
        /// <summary>
        /// 
        /// </summary>
        void RecalculateParameters(bool fullRecalculation)
        {
            if (fullRecalculation)
            {
                ISourceOrderExecution provider = _provider;
                if (provider == null || Symbol.IsEmpty)
                {
                    Symbol symbol = Symbol;
                    _info = PositionInfo.Empty;
                    _info.Symbol = symbol;

                    return;
                }

                OnRecalculateParameters(provider, fullRecalculation);
            }

            lock (this)
            {
                if (_price.HasValue)
                {
                    _info.MarketValue = _price * Volume;
                }
            }

            if (UpdateEvent != null)
            {
                UpdateEvent(this);
            }
        }
 /// <summary>
 /// 
 /// </summary>
 public PositionsInformationUpdateResponseMessage(AccountInfo accountInfo, 
     PositionInfo[] positionsInformations, bool operationResult)
     : base(accountInfo, operationResult)
 {
     _positionsInformations = positionsInformations;
 }
        /// <summary>
        /// Helper, converts from MBT to OFxP object.
        /// </summary>
        PositionInfo? ConvertToPositionInfo(MbtPosition position, MBTradingQuote quotes)
        {
            PositionInfo result = new PositionInfo();

            Symbol? symbol = _adapter.GetSymbolByName(position.Symbol, true);
            if (symbol.HasValue == false)
            {
                return null;
            }

            result.Symbol = symbol.Value;
            result.Volume = position.AggregatePosition;/*position.CloseableShares;*/
            result.Commission = (decimal)Math.Round(position.Commission, IntegrationAdapter.AdvisedAccountDecimalsPrecision);
            result.PendingBuyVolume = position.PendingBuyShares;
            result.PendingSellVolume = position.PendingSellShares;
            result.MarketValue = 0;
            result.ClosedResult = (decimal)Math.Round(position.RealizedPNL, 4);

            if (quotes.SessionsQuotes.ContainsKey(symbol.Value.Name))
            {
                double openPnL, basis;
                if (CalculatePositionOpenPnLAndBasis(position, quotes.SessionsQuotes[symbol.Value.Name].Quote, out openPnL, out basis))
                {
                    result.Result = (decimal)Math.Round(openPnL, IntegrationAdapter.AdvisedAccountDecimalsPrecision);
                    result.Basis = (decimal)basis;
                }
            }

            return result;
        }
 void _provider_PositionUpdateEvent(IOrderSink provider, AccountInfo accountInfo, PositionInfo[] positionInfo)
 {
     WinFormsHelper.BeginFilteredManagedInvoke(this, TimeSpan.FromMilliseconds(250), UpdateUI);
 }
        List<PositionInfo> Managed_ProcessPositions()
        {
            List<PositionInfo> result = new List<PositionInfo>();

            TradeDeskAut desk = _desk;
            if (desk == null)
            {
                return result;
            }

            TableAut tradesTable = (TableAut)desk.FindMainTable("summary");
            foreach (RowAut row in (RowsEnumAut)tradesTable.Rows)
            {
                // The unique number of the instrument that has open position(s).
                string offerID = (string)row.CellValue("OfferID");

                // The sequence number of the instrument in the list of instruments displayed to the Trading Station user.
                int defaultSortOrder = (int)row.CellValue("DefaultSortOrder");

                // The symbol indicating the instrument. For example, EUR/USD, USD/JPY, GBP/USD.
                string instrument = (string)row.CellValue("Instrument");

                // The current profit and loss on all positions opened in the instrument with the direction "sell". Commissions and interest are not taken into consideration. The SellNetP/L is expressed in the account currency.
                double sellNetPL = (double)row.CellValue("SellNetPL");

                // The trade amount of all positions opened in the instrument with the direction "sell".
                //The SellAmountK is expressed in the base currency of the instrument. For example, the value 50 for EUR/USD means that the total trade amount of all sell positions opened in EUR/USD is 50,000 Euros.
                double sellAmountK = (double)row.CellValue("SellAmountK");

                // The average open price of positions opened in the instrument with the direction "sell".
                double sellAverageOpen = (double)row.CellValue("SellAvgOpen");

                // The current market price at which all sell positions opened in the instrument can be closed.
                double buyClose = (double)row.CellValue("BuyClose");

                // The current market price at which all buy positions opened in the instrument can be closed.
                double sellClose = (double)row.CellValue("SellClose");

                // The average open price of positions opened in the instrument with the direction "buy".
                double buyAverageOpen = (double)row.CellValue("BuyAvgOpen");

                // The trade amount of all positions opened in the instrument with the direction "buy".
                //The BuyAmountK is expressed in the base currency of the instrument. For example, the value 50 for EUR/USD means that the total trade amount of all buy positions opened in EUR/USD is 50,000 Euros.
                double buyAmountK = (double)row.CellValue("BuyAmountK");

                // The current profit and loss on all positions opened in the instrument with the direction "buy". Commissions and interest are not taken into consideration. The BuyNetP/L is expressed in the account currency.
                double buyNetPL = (double)row.CellValue("BuyNetPL");

                // The trade amount of all positions (both buy and sell) opened in the instrument. The AmountK is expressed in the base currency of the instrument. For example, the value 50 for EUR/USD means that the total trade amount of all positions opened in EUR/USD is 50,000 Euros.
                double amountK = (double)row.CellValue("AmountK");

                // The current profit and loss on all positions (both buy and sell) opened in the instrument, including commissions and interest. The GrossPL is expressed in the account currency.
                double grossPL = (double)row.CellValue("GrossPL");

                // The current profit and loss on all positions (both buy and sell) opened in the instrument, without taking into consideration the commissions and interest. The NetPL is expressed in the account currency.
                double NetPL = (double)row.CellValue("NetPL");

                // Not currently available.
                // The current profit and loss (in pips) on all positions opened in the instrument with the direction "sell". Commissions and interest are not taken into consideration.
                //double sellNetPLPip = (double)row.CellValue("SellNetPLPip");

                // Not currently available.
                // The current profit and loss (in pips) on all positions opened in the instrument with the direction "buy". Commissions and interest are not taken into consideration.
                //double buyNetPLPip = (double)row.CellValue("BuyNetPLPip");

                PositionInfo info = new PositionInfo(new Symbol(Symbol.SymbolGroup.Forex, instrument), (decimal)(amountK * 1000),
                    (decimal)(buyAmountK > 0 ? Math.Round(buyNetPL, IntegrationAdapter.AdvisedAccountDecimalsPrecision) : Math.Round(sellNetPL, IntegrationAdapter.AdvisedAccountDecimalsPrecision)), null, null, null,
                    (decimal)(buyAmountK > 0 ? buyAverageOpen : sellAverageOpen), (decimal)(Math.Round(grossPL, IntegrationAdapter.AdvisedAccountDecimalsPrecision)), null, null);

                result.Add(info);
            }

            return result;
        }
        /// <summary>
        /// Update position parameters.
        /// </summary>
        /// <param name="symbol"></param>
        /// <param name="volumeChange">*Directional* volume change, 0 for no change.</param>
        /// <param name="operationResultMessage"></param>
        /// <returns></returns>
        bool UpdatePosition(Symbol symbol, int volumeChange, out string operationResultMessage)
        {
            if (_manager == null || _dataDelivery == null || _dataDelivery.SourceId.IsEmpty)
            {
                operationResultMessage = "Not initialized properly for operation.";
                return(false);
            }

            IQuoteProvider quotes = _manager.ObtainQuoteProvider(_dataDelivery.SourceId, symbol);

            if (quotes == null)
            {
                operationResultMessage = "Failed to find corresponding quotation provider.";
                return(false);
            }

            // Update the position corresponding to this order.
            Position position = _tradeEntities.GetPositionBySymbol(symbol, true);

            if (position == null)
            {
                operationResultMessage = "Failed to find corresponding position.";
                return(false);
            }

            PositionInfo updatedPositionInfo = position.Info;

            if (updatedPositionInfo.Volume.HasValue == false)
            {
                updatedPositionInfo.Volume = 0;
            }

            updatedPositionInfo.PendingBuyVolume  = 0;
            updatedPositionInfo.PendingSellVolume = 0;

            if (volumeChange != 0)
            {
                //decimal initialPositionResult = updatedPositionInfo.Result.Value;

                decimal?operationBasis = quotes.GetOrderOpenQuote(volumeChange > 0);
                if (operationBasis.HasValue == false)
                {
                    operationResultMessage = "Failed to establish order operation basis price.";
                    return(false);
                }
                else
                {
                    SystemMonitor.CheckError(updatedPositionInfo.Basis.HasValue, "Position has no properly assigned basis price.");
                }

                if (RecalculatePositionBasis(ref updatedPositionInfo, volumeChange, operationBasis.Value) == false)
                {
                    operationResultMessage = "Failed to recalculate position parameters.";
                    return(false);
                }
            }

            decimal?pendingPrice = quotes.GetOrderCloseQuote(updatedPositionInfo.Volume > 0);

            if (updatedPositionInfo.Volume.HasValue && updatedPositionInfo.Volume != 0 &&
                pendingPrice.HasValue && updatedPositionInfo.Basis.HasValue)
            {
                updatedPositionInfo.Result = (pendingPrice.Value - updatedPositionInfo.Basis.Value) * updatedPositionInfo.Volume.Value;
            }
            else
            {
                updatedPositionInfo.Result = 0;
            }

            bool positionClosing = (position.Volume > 0 && volumeChange < 0) || (position.Volume < 0 && volumeChange > 0);

            if (volumeChange != 0 && positionClosing && position.Info.Result.HasValue && updatedPositionInfo.Result.HasValue)
            {// Update the account upon closing some (or all) of the position volume.
                _runningAccountBalance += position.Info.Result.Value - updatedPositionInfo.Result.Value;
            }

            position.UpdateInfo(updatedPositionInfo);

            operationResultMessage = string.Empty;
            return(true);
        }