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)); }
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)); }
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; }
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); }); }
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(); }
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); }
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; }
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(); }
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); }
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); }