Esempio n. 1
0
        public async Task Handle(FailLiquidationInternalCommand command,
                                 IEventPublisher publisher)
        {
            var executionInfo = await _operationExecutionInfoRepository.GetAsync <LiquidationOperationData>(
                operationName : LiquidationSaga.OperationName,
                id : command.OperationId);

            if (executionInfo?.Data == null)
            {
                return;
            }

            _accountUpdateService.RemoveLiquidationStateIfNeeded(executionInfo.Data.AccountId,
                                                                 $"Liquidation [{command.OperationId}] failed ({command.Reason})", command.OperationId,
                                                                 executionInfo.Data.LiquidationType);

            _chaosKitty.Meow(
                $"{nameof(FailLiquidationInternalCommand)}:" +
                $"Publish_LiquidationFailedInternalEvent:" +
                $"{command.OperationId}");

            publisher.PublishEvent(new LiquidationFailedEvent
            {
                OperationId                     = command.OperationId,
                CreationTime                    = _dateService.Now(),
                Reason                          = command.Reason,
                LiquidationType                 = command.LiquidationType.ToType <LiquidationTypeContract>(),
                AccountId                       = executionInfo.Data.AccountId,
                AssetPairId                     = executionInfo.Data.AssetPairId,
                Direction                       = executionInfo.Data.Direction?.ToType <PositionDirectionContract>(),
                QuoteInfo                       = executionInfo.Data.QuoteInfo,
                ProcessedPositionIds            = executionInfo.Data.ProcessedPositionIds,
                LiquidatedPositionIds           = executionInfo.Data.LiquidatedPositionIds,
                OpenPositionsRemainingOnAccount = _ordersCache.Positions.GetPositionsByAccountIds(executionInfo.Data.AccountId).Count,
                CurrentTotalCapital             = _accountsCache.Get(executionInfo.Data.AccountId).GetTotalCapital(),
            });

            _liquidationEndEventChannel.SendEvent(this, new LiquidationEndEventArgs
            {
                OperationId           = command.OperationId,
                CreationTime          = _dateService.Now(),
                AccountId             = executionInfo.Data.AccountId,
                LiquidatedPositionIds = executionInfo.Data.LiquidatedPositionIds,
                FailReason            = command.Reason,
            });
        }
Esempio n. 2
0
        public async Task ExecuteAsync(IEventPublisher failurePublisher, string accountId, string operationId, string reason)
        {
            if (failurePublisher == null)
            {
                throw new ArgumentNullException(nameof(failurePublisher));
            }

            if (string.IsNullOrEmpty(accountId))
            {
                throw new ArgumentNullException(nameof(accountId));
            }

            if (string.IsNullOrEmpty(operationId))
            {
                throw new ArgumentNullException(nameof(operationId));
            }

            var executionInfo = await _operationExecutionInfoRepository.GetAsync <LiquidationOperationData>(
                LiquidationSaga.OperationName,
                operationId);

            if (executionInfo?.Data == null)
            {
                await _log.WriteWarningAsync(nameof(LiquidationFailureExecutor),
                                             nameof(ExecuteAsync),
                                             new { operationId, accountId }.ToJson(),
                                             $"Unable to execute failure. Liquidation execution info was not found.");

                return;
            }

            _accountUpdateService.RemoveLiquidationStateIfNeeded(accountId, reason, operationId, executionInfo.Data.LiquidationType);

            var account = _accountsCache.Get(accountId);

            failurePublisher.PublishEvent(new LiquidationFailedEvent
            {
                OperationId                     = operationId,
                CreationTime                    = _dateService.Now(),
                Reason                          = reason,
                LiquidationType                 = executionInfo.Data.LiquidationType.ToType <LiquidationTypeContract>(),
                AccountId                       = executionInfo.Data.AccountId,
                AssetPairId                     = executionInfo.Data.AssetPairId,
                Direction                       = executionInfo.Data.Direction?.ToType <PositionDirectionContract>(),
                QuoteInfo                       = executionInfo.Data.QuoteInfo,
                ProcessedPositionIds            = executionInfo.Data.ProcessedPositionIds,
                LiquidatedPositionIds           = executionInfo.Data.LiquidatedPositionIds,
                OpenPositionsRemainingOnAccount = _ordersCache.Positions.GetPositionsByAccountIds(executionInfo.Data.AccountId).Count,
                CurrentTotalCapital             = account.GetTotalCapital(),
            });

            await _log.WriteInfoAsync(nameof(LiquidationFailureExecutor),
                                      nameof(ExecuteAsync),
                                      new { account, operationId, reason }.ToJson(),
                                      $"Successfully published {nameof(LiquidationFailedEvent)} event");

            _liquidationEndEventChannel.SendEvent(this, new LiquidationEndEventArgs
            {
                OperationId           = operationId,
                CreationTime          = _dateService.Now(),
                AccountId             = executionInfo.Data.AccountId,
                LiquidatedPositionIds = executionInfo.Data.LiquidatedPositionIds,
                FailReason            = reason,
            });

            await _log.WriteInfoAsync(nameof(LiquidationFailureExecutor),
                                      nameof(ExecuteAsync),
                                      new { account, operationId, reason }.ToJson(),
                                      $"Successfully published {nameof(LiquidationEndEventArgs)} event");
        }
Esempio n. 3
0
        public async Task Handle(AccountChangedEvent e)
        {
            var executionInfo = await _operationExecutionInfoRepository.GetOrAddAsync(
                operationName : OperationName,
                operationId : e.OperationId,
                factory : () => new OperationExecutionInfo <OperationData>(
                    operationName: OperationName,
                    id: e.OperationId,
                    lastModified: _dateService.Now(),
                    data: new OperationData {
                State = OperationState.Initiated
            }
                    ));

            if (executionInfo.Data.SwitchState(OperationState.Initiated, OperationState.Finished))
            {
                var updatedAccount = Convert(e.Account);

                switch (e.EventType)
                {
                case AccountChangedEventTypeContract.Created:
                    _accountsCacheService.TryAddNew(MarginTradingAccount.Create(updatedAccount));
                    break;

                case AccountChangedEventTypeContract.Updated:
                {
                    var account = _accountsCacheService.TryGet(e.Account.Id);
                    if (await ValidateAccount(account, e) &&
                        await _accountsCacheService.UpdateAccountChanges(updatedAccount.Id,
                                                                         updatedAccount.TradingConditionId, updatedAccount.WithdrawTransferLimit,
                                                                         updatedAccount.IsDisabled, updatedAccount.IsWithdrawalDisabled, e.ChangeTimestamp))
                    {
                        _accountUpdateService.RemoveLiquidationStateIfNeeded(e.Account.Id,
                                                                             "Trading conditions changed");
                    }
                    break;
                }

                case AccountChangedEventTypeContract.BalanceUpdated:
                {
                    if (e.BalanceChange != null)
                    {
                        var account = _accountsCacheService.TryGet(e.Account.Id);
                        if (await ValidateAccount(account, e))
                        {
                            switch (e.BalanceChange.ReasonType)
                            {
                            case AccountBalanceChangeReasonTypeContract.Withdraw:
                                await _accountUpdateService.UnfreezeWithdrawalMargin(updatedAccount.Id,
                                                                                     e.BalanceChange.Id);

                                break;

                            case AccountBalanceChangeReasonTypeContract.UnrealizedDailyPnL:
                                if (_ordersCache.Positions.TryGetPositionById(e.BalanceChange.EventSourceId,
                                                                              out var position))
                                {
                                    position.ChargePnL(e.BalanceChange.Id, e.BalanceChange.ChangeAmount);
                                }
                                else
                                {
                                    _log.WriteWarning("AccountChangedEvent Handler", e.ToJson(),
                                                      $"Position [{e.BalanceChange.EventSourceId} was not found]");
                                }
                                break;

                            case AccountBalanceChangeReasonTypeContract.RealizedPnL:
                                await _accountUpdateService.UnfreezeUnconfirmedMargin(e.Account.Id,
                                                                                      e.BalanceChange.EventSourceId);

                                break;
                            }

                            if (await _accountsCacheService.UpdateAccountBalance(updatedAccount.Id,
                                                                                 e.BalanceChange.Balance, e.ChangeTimestamp))
                            {
                                _accountUpdateService.RemoveLiquidationStateIfNeeded(e.Account.Id,
                                                                                     "Balance updated");
                                _accountBalanceChangedEventChannel.SendEvent(this,
                                                                             new AccountBalanceChangedEventArgs(updatedAccount));
                            }
                        }
                    }
                    else
                    {
                        _log.WriteWarning("AccountChangedEvent Handler", e.ToJson(), "BalanceChange info is empty");
                    }

                    break;
                }

                case AccountChangedEventTypeContract.Deleted:
                    //account deletion from cache is double-handled by CQRS flow
                    _accountsCacheService.Remove(e.Account.Id);
                    break;

                default:
                    await _log.WriteErrorAsync(nameof(AccountsProjection), nameof(AccountChangedEvent),
                                               e.ToJson(), new Exception("AccountChangedEventTypeContract was in incorrect state"));

                    break;
                }

                _chaosKitty.Meow(e.OperationId);

                await _operationExecutionInfoRepository.Save(executionInfo);
            }
        }