Beispiel #1
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;
        }
        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(),
            });
        }
Beispiel #3
0
 public static void CacheNeedsToBeUpdated(this IMarginTradingAccount account)
 {
     if (account is MarginTradingAccount accountInstance)
     {
         accountInstance.AccountFpl.ActualHash++;
     }
 }
Beispiel #4
0
        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()));
        }
Beispiel #6
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;
        }
 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()
     });
 }
Beispiel #8
0
        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());
        }
Beispiel #9
0
        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));
        }
Beispiel #10
0
        private void NotifyAccountStatsChanged(IMarginTradingAccount account)
        {
            var stats = account.ToRabbitMqContract(_marginSettings.IsLive);

            _rabbitMqNotifyService.UpdateAccountStats(new AccountStatsUpdateMessage {
                Accounts = new[] { stats }
            });
        }
Beispiel #11
0
 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
Beispiel #12
0
 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}");
     }
 }
Beispiel #13
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 #14
0
        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));
        }
Beispiel #15
0
        }//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
Beispiel #16
0
        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);
        }
Beispiel #17
0
 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,
     });
 }
Beispiel #19
0
        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();
            }
        }
Beispiel #20
0
        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());
        }
Beispiel #21
0
        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);
        }
Beispiel #22
0
        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());
        }
Beispiel #23
0
 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,
     });
 }
Beispiel #24
0
        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++;
            }
        }
Beispiel #25
0
        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!");
                }
            }
        }
Beispiel #26
0
        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);
        }
Beispiel #27
0
 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,
     });
 }
Beispiel #28
0
        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);
        }
Beispiel #29
0
 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
     });
 }
Beispiel #30
0
        //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());
        }