private void OpenNewPosition(Order order, decimal volume) { if (order.ExecutionPrice == null) { _log.WriteWarning(nameof(OpenNewPosition), order.ToJson(), "Execution price is null. Position was not opened"); return; } var position = new Position(order.Id, order.Code, order.AssetPairId, volume, order.AccountId, order.TradingConditionId, order.AccountAssetId, order.Price, order.MatchingEngineId, order.Executed.Value, order.Id, order.OrderType, order.Volume, order.ExecutionPrice.Value, order.FxRate, order.EquivalentAsset, order.EquivalentRate, order.RelatedOrders, order.LegalEntity, order.Originator, order.ExternalProviderId, order.FxAssetPairId, order.FxToAssetPairDirection, order.AdditionalInfo, order.ForceOpen); var defaultMatchingEngine = _meRouter.GetMatchingEngineForClose(position.OpenMatchingEngineId); var closePrice = defaultMatchingEngine.GetPriceForClose(position.AssetPairId, position.Volume, position.ExternalProviderId); position.UpdateClosePrice(closePrice ?? order.ExecutionPrice.Value); var isPositionAlreadyExist = _ordersCache.Positions.GetPositionsByInstrumentAndAccount( position.AssetPairId, position.AccountId).Any(p => p.Direction == position.Direction); _ordersCache.Positions.Add(position); var metadata = new PositionOpenMetadata { ExistingPositionIncreased = isPositionAlreadyExist }; SendPositionHistoryEvent(position, PositionHistoryTypeContract.Open, 0, order.AdditionalInfo, metadata: metadata); ActivateRelatedOrders(position); }
private void SendPositionHistoryEvent(Position position, PositionHistoryTypeContract historyType, decimal chargedPnl, string orderAdditionalInfo, Order dealOrder = null, decimal?dealVolume = null, PositionOpenMetadata metadata = null) { DealContract deal = null; if (dealOrder != null && dealVolume != null) { var sign = position.Volume > 0 ? 1 : -1; var accountBaseAssetAccuracy = AssetsConstants.DefaultAssetAccuracy; var fpl = Math.Round((dealOrder.ExecutionPrice.Value - position.OpenPrice) * dealOrder.FxRate * dealVolume.Value * sign, accountBaseAssetAccuracy); var balanceDelta = fpl - Math.Round(chargedPnl, accountBaseAssetAccuracy); var dealId = historyType == PositionHistoryTypeContract.Close ? position.Id : _identityGenerator.GenerateAlphanumericId(); deal = new DealContract { DealId = dealId, PositionId = position.Id, Volume = dealVolume.Value, Created = dealOrder.Executed.Value, OpenTradeId = position.OpenTradeId, OpenOrderType = position.OpenOrderType.ToType <OrderTypeContract>(), OpenOrderVolume = position.OpenOrderVolume, OpenOrderExpectedPrice = position.ExpectedOpenPrice, CloseTradeId = dealOrder.Id, CloseOrderType = dealOrder.OrderType.ToType <OrderTypeContract>(), CloseOrderVolume = dealOrder.Volume, CloseOrderExpectedPrice = dealOrder.Price, OpenPrice = position.OpenPrice, OpenFxPrice = position.OpenFxPrice, ClosePrice = dealOrder.ExecutionPrice.Value, CloseFxPrice = dealOrder.FxRate, Fpl = fpl, PnlOfTheLastDay = balanceDelta, AdditionalInfo = dealOrder.AdditionalInfo, Originator = dealOrder.Originator.ToType <OriginatorTypeContract>() }; var account = _accountsCacheService.Get(position.AccountId); _cqrsSender.PublishEvent(new PositionClosedEvent(account.Id, account.ClientId, deal.DealId, position.AssetPairId, balanceDelta)); _accountUpdateService.FreezeUnconfirmedMargin(position.AccountId, deal.DealId, balanceDelta) .GetAwaiter().GetResult(); //todo consider making this async or pass to broker } var positionContract = _convertService.Convert <Position, PositionContract>(position, o => o.ConfigureMap(MemberList.Destination).ForMember(x => x.TotalPnL, c => c.Ignore())); positionContract.TotalPnL = position.GetFpl(); var historyEvent = new PositionHistoryEvent { PositionSnapshot = positionContract, Deal = deal, EventType = historyType, Timestamp = _dateService.Now(), ActivitiesMetadata = metadata?.ToJson(), OrderAdditionalInfo = orderAdditionalInfo, }; _rabbitMqNotifyService.PositionHistory(historyEvent); }