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; }
public static MarginEventMessage Create(IMarginTradingAccount account, MarginEventTypeContract eventType, DateTime eventTime) { return(new MarginEventMessage { EventId = Guid.NewGuid().ToString("N"), EventTime = eventTime, EventType = eventType, AccountId = account.Id, TradingConditionId = account.TradingConditionId, BaseAssetId = account.BaseAssetId, Balance = account.Balance, WithdrawTransferLimit = account.WithdrawTransferLimit, MarginCall1Level = account.GetMarginCall1Level(), MarginCall2Level = account.GetMarginCall2Level(), StopOutLevel = account.GetStopOutLevel(), TotalCapital = account.GetTotalCapital(), FreeMargin = account.GetFreeMargin(), MarginAvailable = account.GetMarginAvailable(), UsedMargin = account.GetUsedMargin(), MarginInit = account.GetMarginInit(), PnL = account.GetPnl(), OpenPositionsCount = account.GetOpenPositionsCount(), MarginUsageLevel = account.GetMarginUsageLevel(), }); }
public static void CacheNeedsToBeUpdated(this IMarginTradingAccount account) { if (account is MarginTradingAccount accountInstance) { accountInstance.AccountFpl.ActualHash++; } }
private void UpdateAccount(IMarginTradingAccount account, ICollection <Position> positions, ICollection <Order> pendingOrders) { account.AccountFpl.CalculatedHash = account.AccountFpl.ActualHash; var accuracy = _assetsCache.GetAssetAccuracy(account.BaseAssetId); var positionsMaintenanceMargin = positions.Sum(item => item.GetMarginMaintenance()); var positionsInitMargin = positions.Sum(item => item.GetMarginInit()); var pendingOrdersMargin = 0;// pendingOrders.Sum(item => item.GetMarginInit()); account.AccountFpl.PnL = Math.Round(positions.Sum(x => x.GetTotalFpl()), accuracy); account.AccountFpl.UnrealizedDailyPnl = Math.Round(positions.Sum(x => x.GetTotalFpl() - x.ChargedPnL), accuracy); account.AccountFpl.UsedMargin = Math.Round(positionsMaintenanceMargin + pendingOrdersMargin, accuracy); account.AccountFpl.MarginInit = Math.Round(positionsInitMargin + pendingOrdersMargin, accuracy); account.AccountFpl.InitiallyUsedMargin = positions.Sum(p => p.GetInitialMargin()); account.AccountFpl.OpenPositionsCount = positions.Count; account.AccountFpl.ActiveOrdersCount = pendingOrders.Count; var tradingCondition = _tradingConditionsCache.GetTradingCondition(account.TradingConditionId); account.AccountFpl.MarginCall1Level = tradingCondition.MarginCall1; account.AccountFpl.MarginCall2Level = tradingCondition.MarginCall2; account.AccountFpl.StopOutLevel = tradingCondition.StopOut; }
public async Task <MtBackendResponse <MarginTradingAccountModel> > SetTradingCondition( [FromBody] SetTradingConditionModel model) { if (!_tradingConditionsCacheService.IsTradingConditionExists(model.TradingConditionId)) { return(MtBackendResponse <MarginTradingAccountModel> .Error( $"No trading condition {model.TradingConditionId} found in cache")); } var tradingCondition = _tradingConditionsCacheService.GetTradingCondition(model.TradingConditionId); IMarginTradingAccount account = _accountsCacheService.TryGet(model.ClientId, model.AccountId); if (account == null) { return(MtBackendResponse <MarginTradingAccountModel> .Error( $"Account for client [{model.ClientId}] with id [{model.AccountId}] was not found")); } if (tradingCondition.LegalEntity != account.LegalEntity) { return(MtBackendResponse <MarginTradingAccountModel> .Error( $"Account for client [{model.ClientId}] with id [{model.AccountId}] has LegalEntity " + $"[{account.LegalEntity}], but trading condition wit id [{tradingCondition.Id}] has " + $"LegalEntity [{tradingCondition.LegalEntity}]")); } account = await _accountManager.SetTradingCondition(model.ClientId, model.AccountId, model.TradingConditionId); return(MtBackendResponse <MarginTradingAccountModel> .Ok(account.ToBackendContract())); }
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; }
public static AccountStatContract ConvertToContract(this IMarginTradingAccount account) { return(new AccountStatContract { AccountId = account.Id, BaseAssetId = account.BaseAssetId, Balance = account.Balance, LastBalanceChangeTime = account.LastBalanceChangeTime, MarginCallLevel = account.GetMarginCall1Level(), StopOutLevel = account.GetStopOutLevel(), TotalCapital = account.GetTotalCapital(), FreeMargin = account.GetFreeMargin(), MarginAvailable = account.GetMarginAvailable(), UsedMargin = account.GetUsedMargin(), CurrentlyUsedMargin = account.GetCurrentlyUsedMargin(), InitiallyUsedMargin = account.GetInitiallyUsedMargin(), MarginInit = account.GetMarginInit(), PnL = account.GetPnl(), UnrealizedDailyPnl = account.GetUnrealizedDailyPnl(), OpenPositionsCount = account.GetOpenPositionsCount(), ActiveOrdersCount = account.GetActiveOrdersCount(), MarginUsageLevel = account.GetMarginUsageLevel(), LegalEntity = account.LegalEntity, IsInLiquidation = account.IsInLiquidation(), MarginNotificationLevel = account.GetAccountLevel().ToString() }); }
public void NotifyAccountUpdated(IMarginTradingAccount account) { _rabbitMqNotifyService.AccountUpdated(account); var queueName = QueueHelper.BuildQueueName(_marginSettings.RabbitMqQueues.AccountChanged.ExchangeName, _marginSettings.Env); _consoleWriter.WriteLine($"send account changed to queue {queueName}"); _operationsLogService.AddLog($"queue {queueName}", account.ClientId, account.Id, null, account.ToJson()); }
public static decimal GetUsedMargin(this IMarginTradingAccount account) { var fplData = account.GetAccountFpl(); //According to ESMA MCO rule a stop-out added at 50% of the initially invested margin //So if the 50% of the initially invested margin (accumulated per the account), is bigger than the recalculated 100%, than this margin requirement is the reference for the free capital determination and the liquidation level. return(Math.Max(fplData.UsedMargin, fplData.InitiallyUsedMargin / 2)); }
private void NotifyAccountStatsChanged(IMarginTradingAccount account) { var stats = account.ToRabbitMqContract(_marginSettings.IsLive); _rabbitMqNotifyService.UpdateAccountStats(new AccountStatsUpdateMessage { Accounts = new[] { stats } }); }
public static Position CreateOpenedPosition(string assetPairId, IMarginTradingAccount account, string tradingConditionId, decimal volume, decimal openPrice, decimal openFxPrice = 1) { return(new Position(Guid.NewGuid().ToString("N"), 0, assetPairId, volume, account.Id, tradingConditionId, account.BaseAssetId, null, MatchingEngineConstants.DefaultMm, DateTime.UtcNow, "OpenTrade", OrderType .Market, volume, openPrice, openFxPrice, "USD", openPrice, new List <RelatedOrderInfo>(), "LYKKETEST", OriginatorType.Investor, "", assetPairId, FxToAssetPairDirection.Straight, "")); }//todo assetPairId is used as FxAssetPairId which is not very correct
private void CheckTransferLimits(IMarginTradingAccount account, decimal amount) { //withdraw can not be more then limit if (amount < 0 && account.WithdrawTransferLimit < Math.Abs(amount)) { throw new Exception( $"Can not transfer {Math.Abs(amount)}. Current limit is {account.WithdrawTransferLimit}"); } }
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)); }
private Task AccountChanged(IMarginTradingAccount account, AccountEventTypeEnum eventType) { var message = new AccountChangedMessage { Account = account.ToFullBackendContract(_settings.IsLive), EventType = eventType, }; return(TryProduceMessageAsync(_settings.RabbitMqQueues.AccountChanged.ExchangeName, message)); }
}//todo assetPairId is used as FxAssetPairId which is not very correct public static Order CreateNewOrder(OrderType orderType, string assetPairId, IMarginTradingAccount account, string tradingConditionId, decimal volume, OrderFillType fillType = OrderFillType.FillOrKill, DateTime?validity = null, decimal?price = null, bool forceOpen = false, string parentOrderId = null, string parentPositionId = null, DateTime?created = null) { created = created ?? DateTime.UtcNow; return(new Order(Guid.NewGuid().ToString("N"), 0, assetPairId, volume, created.Value, created.Value, validity, account.Id, tradingConditionId, account.BaseAssetId, price, "EUR", fillType, null, "LYKKETEST", forceOpen, orderType, parentOrderId, parentPositionId, OriginatorType.Investor, 1, 1, assetPairId, FxToAssetPairDirection.Straight, OrderStatus.Placed, null, Guid.NewGuid().ToString())); }//todo assetPairId is used as FxAssetPairId which is not very correct
private async Task <bool> ValidateAccount(IMarginTradingAccount account, AccountChangedEvent e) { if (account == null) { await _log.WriteWarningAsync(nameof(AccountsProjection), e.ToJson(), $"Account with id {e.Account.Id} was not found"); return(false); } return(true); }
public static MarginTradingAccountModel ToBackendContract(this IMarginTradingAccount src) { return(new MarginTradingAccountModel { Id = src.Id, ClientId = src.ClientId, TradingConditionId = src.TradingConditionId, BaseAssetId = src.BaseAssetId, Balance = src.Balance, WithdrawTransferLimit = src.WithdrawTransferLimit, LegalEntity = src.LegalEntity, }); }
public static MarginTradingAccountEntity Create(IMarginTradingAccount src) { return(new MarginTradingAccountEntity { PartitionKey = GeneratePartitionKey(src.ClientId), RowKey = GenerateRowKey(src.Id), TradingConditionId = src.TradingConditionId, BaseAssetId = src.BaseAssetId, Balance = (double)src.Balance, WithdrawTransferLimit = (double)src.WithdrawTransferLimit, LegalEntity = src.LegalEntity, }); }
public async Task <string> UpdateBalanceAsync(IMarginTradingAccount account, decimal amount, AccountHistoryType historyType, string comment, string eventSourceId = null, bool changeTransferLimit = false, string auditLog = null) { if (historyType == AccountHistoryType.Deposit && changeTransferLimit) { CheckDepositLimits(account, amount); } if (changeTransferLimit) { CheckTransferLimits(account, amount); } var semaphore = GetSemaphore(account); await semaphore.WaitAsync(); try { var updatedAccount = await _repository.UpdateBalanceAsync(account.ClientId, account.Id, amount, changeTransferLimit); _acountBalanceChangedEventChannel.SendEvent(this, new AccountBalanceChangedEventArgs(updatedAccount)); //todo: move to separate event consumers _accountsCacheService.UpdateBalance(updatedAccount); _clientNotifyService.NotifyAccountUpdated(updatedAccount); var transactionId = Guid.NewGuid().ToString("N"); await _rabbitMqNotifyService.AccountHistory( transactionId, account.Id, account.ClientId, amount, updatedAccount.Balance, updatedAccount.WithdrawTransferLimit, historyType, _equivalentPricesService.GetUsdEquivalent(amount, account.BaseAssetId, account.LegalEntity), comment, eventSourceId, account.LegalEntity, auditLog); return(transactionId); } finally { semaphore.Release(); } }
private static AccountFpl GetAccountFpl(this IMarginTradingAccount account) { if (account is MarginTradingAccount accountInstance) { if (accountInstance.AccountFpl.ActualHash != accountInstance.AccountFpl.CalculatedHash) { ContainerProvider.Container.Resolve <IAccountUpdateService>().UpdateAccount(account); } return(accountInstance.AccountFpl); } return(new AccountFpl()); }
public static decimal GetMarginUsageLevel(this IMarginTradingAccount account) { var totalCapital = account.GetTotalCapital(); var usedMargin = account.GetUsedMargin(); //Anton Belkin said 100 is ok ) if (usedMargin <= 0) { return(100); } return(totalCapital / usedMargin); }
private static AccountFpl GetAccountFpl(this IMarginTradingAccount account) { if (account is MarginTradingAccount accountInstance) { if (accountInstance.AccountFpl.ActualHash != accountInstance.AccountFpl.CalculatedHash) { MtServiceLocator.AccountUpdateService.UpdateAccount(account); } return(accountInstance.AccountFpl); } return(new AccountFpl()); }
private static DataReaderAccountBackendContract ToBackendContract(IMarginTradingAccount src, bool isLive) { return(new DataReaderAccountBackendContract { Id = src.Id, ClientId = src.ClientId, TradingConditionId = src.TradingConditionId, BaseAssetId = src.BaseAssetId, Balance = src.Balance, WithdrawTransferLimit = src.WithdrawTransferLimit, IsLive = isLive, LegalEntity = src.LegalEntity, }); }
public static void CacheNeedsToBeUpdated(this IMarginTradingAccount account) { var accountInstance = account as MarginTradingAccount; if (accountInstance != null) { if (accountInstance.AccountFpl == null) { accountInstance.AccountFpl = new AccountFpl(); } accountInstance.AccountFpl.ActualHash++; } }
private void CheckDepositLimits(IMarginTradingAccount account, decimal amount) { //limit can not be more then max after deposit if (amount > 0) { var accountGroup = _accountGroupCacheService.GetAccountGroup(account.TradingConditionId, account.BaseAssetId); if (accountGroup.DepositTransferLimit > 0 && accountGroup.DepositTransferLimit < account.Balance + amount) { throw new Exception( $"Margin Trading is in beta testing. The cash-ins are temporarily limited when Total Capital exceeds {accountGroup.DepositTransferLimit} {accountGroup.BaseAssetId}. Thank you for using Lykke Margin Trading, the limit will be cancelled soon!"); } } }
public static AccountLevel GetAccountLevel(this IMarginTradingAccount account) { var marginUsageLevel = account.GetMarginUsageLevel(); if (marginUsageLevel <= account.GetStopOutLevel()) { return(AccountLevel.StopOUt); } if (marginUsageLevel <= account.GetMarginCallLevel()) { return(AccountLevel.MarginCall); } return(AccountLevel.None); }
public static MarginTradingAccount Create(IMarginTradingAccount src, AccountFpl accountFpl) { return(new MarginTradingAccount { Id = src.Id, TradingConditionId = src.TradingConditionId, ClientId = src.ClientId, BaseAssetId = src.BaseAssetId, Balance = src.Balance, WithdrawTransferLimit = src.WithdrawTransferLimit, AccountFpl = accountFpl ?? new AccountFpl() { ActualHash = 1 }, LegalEntity = src.LegalEntity, }); }
private async Task <bool> UpdateAccount(IMarginTradingAccount account, bool toDisablementState, Action <string> failHandler, DateTime commandTime) { try { await _accountsCacheService.UpdateAccountChanges(account.Id, account.TradingConditionId, account.WithdrawTransferLimit, toDisablementState, toDisablementState, commandTime); } catch (Exception exception) { await _log.WriteErrorAsync(nameof(DeleteAccountsCommandsHandler), nameof(DeleteAccountsCommandsHandler), exception.Message, exception); failHandler(exception.Message); return(false); } return(true); }
public static MarginTradingAccount Create(IMarginTradingAccount src, AccountFpl accountFpl = null) { return(new MarginTradingAccount { Id = src.Id, TradingConditionId = src.TradingConditionId, ClientId = src.ClientId, BaseAssetId = src.BaseAssetId, Balance = src.Balance, WithdrawTransferLimit = src.WithdrawTransferLimit, AccountFpl = accountFpl ?? new AccountFpl { ActualHash = 1 }, LegalEntity = src.LegalEntity, IsDisabled = src.IsDisabled, IsDeleted = src.IsDeleted, LastUpdateTime = src.LastUpdateTime, LastBalanceChangeTime = src.LastBalanceChangeTime, IsWithdrawalDisabled = src.IsWithdrawalDisabled }); }
//TODO: optimize private static AccountFpl GetAccountFpl(this IMarginTradingAccount account) { var accountInstance = account as MarginTradingAccount; if (accountInstance != null) { if (accountInstance.AccountFpl == null) { accountInstance.AccountFpl = new AccountFpl(); accountInstance.CacheNeedsToBeUpdated(); } if (accountInstance.AccountFpl.ActualHash != accountInstance.AccountFpl.CalculatedHash) { MtServiceLocator.AccountUpdateService.UpdateAccount(account, accountInstance.AccountFpl); } return(accountInstance.AccountFpl); } return(new AccountFpl()); }