Beispiel #1
0
        public decimal CalculateOvernightUsedMargin(IMarginTradingAccount account)
        {
            var positions           = GetPositions(account.Id);
            var accuracy            = _assetsCache.GetAssetAccuracy(account.BaseAssetId);
            var positionsMargin     = positions.Sum(item => item.GetOvernightMarginMaintenance());
            var pendingOrdersMargin = 0;// pendingOrders.Sum(item => item.GetMarginInit());

            return(Math.Round(positionsMargin + pendingOrdersMargin, accuracy));
        }
Beispiel #2
0
        public decimal GetInitMarginForOrder(Order order)
        {
            var accountAsset =
                _tradingInstrumentsCache.GetTradingInstrument(order.TradingConditionId, order.AssetPairId);
            var marginRate = _cfdCalculatorService.GetQuoteRateForBaseAsset(order.AccountAssetId, order.AssetPairId,
                                                                            order.LegalEntity, order.Direction == OrderDirection.Buy);
            var accountBaseAssetAccuracy = _assetsCache.GetAssetAccuracy(order.AccountAssetId);

            return(Math.Round(
                       GetMargins(accountAsset, Math.Abs(order.Volume), marginRate).MarginInit,
                       accountBaseAssetAccuracy));
        }
Beispiel #3
0
        private void UpdateAccount(IMarginTradingAccount account,
                                   ICollection <Order> activeOrders,
                                   ICollection <Order> pendingOrders)
        {
            var accuracy = _assetsCache.GetAssetAccuracy(account.BaseAssetId);
            var activeOrdersMaintenanceMargin = activeOrders.Sum(item => item.GetMarginMaintenance());
            var activeOrdersInitMargin        = activeOrders.Sum(item => item.GetMarginInit());
            var pendingOrdersMargin           = pendingOrders.Sum(item => item.GetMarginInit());

            account.AccountFpl.PnL = Math.Round(activeOrders.Sum(x => x.GetTotalFpl()), accuracy);

            account.AccountFpl.UsedMargin         = Math.Round(activeOrdersMaintenanceMargin + pendingOrdersMargin, accuracy);
            account.AccountFpl.MarginInit         = Math.Round(activeOrdersInitMargin + pendingOrdersMargin, accuracy);
            account.AccountFpl.OpenPositionsCount = activeOrders.Count;

            var accountGroup = _accountGroupCacheService.GetAccountGroup(account.TradingConditionId, account.BaseAssetId);

            if (accountGroup == null)
            {
                throw new Exception(string.Format(MtMessages.AccountGroupForTradingConditionNotFound,
                                                  account.TradingConditionId, account.BaseAssetId));
            }

            account.AccountFpl.MarginCallLevel = accountGroup.MarginCall;
            account.AccountFpl.StopoutLevel    = accountGroup.StopOut;
            account.AccountFpl.CalculatedHash  = account.AccountFpl.ActualHash;
        }
Beispiel #4
0
        void IEventConsumer <StopOutEventArgs> .ConsumeEvent(object sender, StopOutEventArgs ea)
        {
            var account   = ea.Account;
            var orders    = ea.Orders;
            var eventTime = _dateService.Now();
            var accountMarginEventMessage = AccountMarginEventMessageConverter.Create(account, true, eventTime);
            var accuracy = _assetsCache.GetAssetAccuracy(account.BaseAssetId);
            var totalPnl = Math.Round(orders.Sum(x => x.GetTotalFpl()), accuracy);

            _threadSwitcher.SwitchThread(async() =>
            {
                _operationsLogService.AddLog("stopout", account.ClientId, account.Id, "", ea.ToJson());

                var marginEventTask = _rabbitMqNotifyService.AccountMarginEvent(accountMarginEventMessage);

                _notifyService.NotifyAccountStopout(account.ClientId, account.Id, orders.Length, totalPnl);

                var notificationTask = SendMarginEventNotification(account.ClientId,
                                                                   string.Format(MtMessages.Notifications_StopOutNotification, orders.Length, totalPnl,
                                                                                 account.BaseAssetId));

                var clientEmail = await _clientAccountService.GetEmail(account.ClientId);

                var emailTask = !string.IsNullOrEmpty(clientEmail)
                    ? _emailService.SendStopOutEmailAsync(clientEmail, account.BaseAssetId, account.Id)
                    : Task.CompletedTask;

                await Task.WhenAll(marginEventTask, notificationTask, emailTask);
            });
        }
Beispiel #5
0
        public void UpdateOrderFpl(IOrder order, FplData fplData)
        {
            fplData.AccountBaseAssetAccuracy = _assetsCache.GetAssetAccuracy(order.AccountAssetId);
            fplData.QuoteRate = _cfdCalculatorService.GetQuoteRateForQuoteAsset(order.AccountAssetId, order.Instrument);

            var fpl = order.GetOrderType() == OrderDirection.Buy
                ? (order.ClosePrice - order.OpenPrice) * fplData.QuoteRate * order.GetMatchedVolume()
                : (order.OpenPrice - order.ClosePrice) * fplData.QuoteRate * order.GetMatchedVolume();

            fplData.Fpl = Math.Round(fpl, fplData.AccountBaseAssetAccuracy);

            var accountAsset = _accountAssetsCacheService.GetAccountAsset(order.TradingConditionId, order.AccountAssetId, order.Instrument);

            fplData.MarginInit        = Math.Round(order.ClosePrice * order.GetMatchedVolume() * fplData.QuoteRate / accountAsset.LeverageInit, fplData.AccountBaseAssetAccuracy);
            fplData.MarginMaintenance = Math.Round(order.ClosePrice * order.GetMatchedVolume() * fplData.QuoteRate / accountAsset.LeverageMaintenance, fplData.AccountBaseAssetAccuracy);

            fplData.OpenCrossPrice  = Math.Round(order.OpenPrice * fplData.QuoteRate, order.AssetAccuracy);
            fplData.CloseCrossPrice = Math.Round(order.ClosePrice * fplData.QuoteRate, order.AssetAccuracy);

            fplData.OpenPrice     = order.OpenPrice;
            fplData.ClosePrice    = order.ClosePrice;
            fplData.SwapsSnapshot = order.GetSwaps();

            fplData.CalculatedHash = fplData.ActualHash;

            fplData.TotalFplSnapshot = order.GetTotalFpl(fplData.SwapsSnapshot);

            var account = _accountsCacheService.Get(order.ClientId, order.AccountId);

            account.CacheNeedsToBeUpdated();
        }
Beispiel #6
0
        private string GetPushMessage(IOrder order)
        {
            var message        = string.Empty;
            var volume         = Math.Abs(order.Volume);
            var type           = order.GetOrderType() == OrderDirection.Buy ? "Long" : "Short";
            var assetPair      = _assetPairsCache.GetAssetPairByIdOrDefault(order.Instrument);
            var instrumentName = assetPair?.Name ?? order.Instrument;

            switch (order.Status)
            {
            case OrderStatus.WaitingForExecution:
                message = string.Format(MtMessages.Notifications_PendingOrderPlaced, type, instrumentName, volume, Math.Round(order.ExpectedOpenPrice ?? 0, order.AssetAccuracy));
                break;

            case OrderStatus.Active:
                message = order.ExpectedOpenPrice.HasValue
                        ? string.Format(MtMessages.Notifications_PendingOrderTriggered, type, instrumentName, volume,
                                        Math.Round(order.OpenPrice, order.AssetAccuracy))
                        : string.Format(MtMessages.Notifications_OrderPlaced, type, instrumentName, volume,
                                        Math.Round(order.OpenPrice, order.AssetAccuracy));
                break;

            case OrderStatus.Closed:
                var reason = string.Empty;

                switch (order.CloseReason)
                {
                case OrderCloseReason.StopLoss:
                    reason = MtMessages.Notifications_WithStopLossPhrase;
                    break;

                case OrderCloseReason.TakeProfit:
                    reason = MtMessages.Notifications_WithTakeProfitPhrase;
                    break;
                }

                var accuracy = _assetsCache.GetAssetAccuracy(order.AccountAssetId);

                message = order.ExpectedOpenPrice.HasValue &&
                          (order.CloseReason == OrderCloseReason.Canceled ||
                           order.CloseReason == OrderCloseReason.CanceledBySystem ||
                           order.CloseReason == OrderCloseReason.CanceledByBroker)
                        ? string.Format(MtMessages.Notifications_PendingOrderCanceled, type, instrumentName, volume)
                        : string.Format(MtMessages.Notifications_OrderClosed, type, instrumentName, volume, reason,
                                        order.GetTotalFpl().ToString($"F{accuracy}"),
                                        order.AccountAssetId);
                break;

            case OrderStatus.Rejected:
                break;

            case OrderStatus.Closing:
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            return(message);
        }
Beispiel #7
0
        public void UpdateAccount(IMarginTradingAccount account, AccountFpl accountFpl, Order[] orders = null)
        {
            if (orders == null)
            {
                orders = _ordersCache.ActiveOrders.GetOrdersByAccountIds(account.Id).ToArray();
            }

            var accuracy = _assetsCache.GetAssetAccuracy(account.BaseAssetId);

            accountFpl.PnL = Math.Round(orders.Sum(x => x.GetTotalFpl()), accuracy);

            accountFpl.UsedMargin = Math.Round(orders.Sum(item => item.GetMarginMaintenance()),
                                               accuracy);
            accountFpl.MarginInit = Math.Round(orders.Sum(item => item.GetMarginInit()),
                                               accuracy);
            accountFpl.OpenPositionsCount = orders.Length;

            var accountGroup = _accountGroupCacheService.GetAccountGroup(account.TradingConditionId, account.BaseAssetId);

            if (accountGroup == null)
            {
                throw new Exception(string.Format(MtMessages.AccountGroupForTradingConditionNotFound, account.TradingConditionId, account.BaseAssetId));
            }

            accountFpl.MarginCallLevel = accountGroup.MarginCall;
            accountFpl.StopoutLevel    = accountGroup.StopOut;
            accountFpl.CalculatedHash  = accountFpl.ActualHash;
        }
Beispiel #8
0
        private void UpdateOrderFplData(IOrder order, FplData fplData)
        {
            fplData.AccountBaseAssetAccuracy = _assetsCache.GetAssetAccuracy(order.AccountAssetId);
            fplData.FplRate = _cfdCalculatorService.GetQuoteRateForQuoteAsset(order.AccountAssetId, order.Instrument,
                                                                              order.LegalEntity, order.Volume * (order.ClosePrice - order.OpenPrice) > 0);

            var fpl = (order.ClosePrice - order.OpenPrice) * fplData.FplRate * order.Volume;

            fplData.Fpl = Math.Round(fpl, fplData.AccountBaseAssetAccuracy);

            CalculateMargin(order, fplData);

            fplData.OpenPrice     = order.OpenPrice;
            fplData.ClosePrice    = order.ClosePrice;
            fplData.SwapsSnapshot = order.GetSwaps();

            fplData.CalculatedHash = fplData.ActualHash;

            fplData.TotalFplSnapshot = order.GetTotalFpl(fplData.SwapsSnapshot);

            _accountsCacheService.Get(order.ClientId, order.AccountId).CacheNeedsToBeUpdated();
        }
Beispiel #9
0
        private decimal GetSwaps(string accountAssetId, string instrument, OrderDirection type, DateTime?openDate, DateTime?closeDate, decimal volume, decimal swapRate)
        {
            decimal result = 0;

            if (openDate.HasValue)
            {
                var close   = closeDate ?? DateTime.UtcNow;
                var seconds = (decimal)(close - openDate.Value).TotalSeconds;

                const int secondsInYear = 31536000;
                var       quote         = _calculator.GetQuoteRateForBaseAsset(accountAssetId, instrument);
                var       swaps         = quote * volume * swapRate * seconds / secondsInYear;
                result = Math.Round(swaps, _assetsCache.GetAssetAccuracy(accountAssetId));
            }

            return(result);
        }
Beispiel #10
0
        private void SendPositionHistoryEvent(Position position, PositionHistoryTypeContract historyType, decimal
                                              chargedPnl, 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 = _assetsCache.GetAssetAccuracy(position.AccountAssetId);

                var fpl = Math.Round((dealOrder.ExecutionPrice.Value - position.OpenPrice) *
                                     dealOrder.FxRate * dealVolume.Value * sign, accountBaseAssetAccuracy);
                var balanceDelta = Math.Round(fpl - chargedPnl, accountBaseAssetAccuracy);

                deal = new DealContract
                {
                    DealId                  = _identityGenerator.GenerateAlphanumericId(),
                    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()
            };

            _rabbitMqNotifyService.PositionHistory(historyEvent);
        }