예제 #1
0
        public Task CloseGroupAsync([FromQuery] string assetPairId = null, [FromQuery] string accountId = null,
                                    [FromQuery] PositionDirectionContract?direction = null, [FromBody] PositionCloseRequest request = null)
        {
            if (string.IsNullOrWhiteSpace(accountId))
            {
                throw new ArgumentNullException(nameof(accountId), "AccountId must be set.");
            }

            var operationId = string.IsNullOrWhiteSpace(request?.CorrelationId)
                ? _identityGenerator.GenerateGuid()
                : request.CorrelationId;

            var originator = GetOriginator(request?.Originator);

            _cqrsSender.SendCommandToSelf(new StartLiquidationInternalCommand
            {
                OperationId     = operationId,
                CreationTime    = _dateService.Now(),
                AccountId       = accountId,
                AssetPairId     = assetPairId,
                Direction       = direction?.ToType <PositionDirection>(),
                QuoteInfo       = null,
                LiquidationType = LiquidationType.Forced,
                OriginatorType  = originator,
                AdditionalInfo  = request?.AdditionalInfo,
            });

            _operationsLogService.AddLog("Position liquidation started", string.Empty,
                                         $"instrument = [{assetPairId}], account = [{accountId}], direction = [{direction}], request = [{request.ToJson()}]",
                                         $"Started operation {operationId}");

            return(Task.CompletedTask);
        }
예제 #2
0
 public void StartSpecialLiquidation(string[] positionIds, [CanBeNull] string accountId)
 {
     _cqrsSender.SendCommandToSelf(new StartSpecialLiquidationInternalCommand
     {
         OperationId    = _identityGenerator.GenerateGuid(),
         CreationTime   = _dateService.Now(),
         PositionIds    = positionIds,
         AccountId      = accountId,
         AdditionalInfo = LykkeConstants.LiquidationBySystemAdditionalInfo,
         OriginatorType = OriginatorType.System
     });
 }
        public Task Delete([Body] List <string> accountIds)
        {
            accountIds.RequiredNotNullOrEmpty(nameof(accountIds), $"{nameof(accountIds)} must be set.");

            _cqrsSender.SendCommandToSelf(new DeleteAccountsCommand
            {
                OperationId = Guid.NewGuid().ToString("N"),
                Timestamp   = _systemClock.UtcNow.UtcDateTime,
                AccountIds  = accountIds,
                Comment     = "Started from API for test purposes.",
            });

            return(Task.CompletedTask);
        }
예제 #4
0
        public Task ResumeLiquidation(string accountId, string comment)
        {
            var account = _accountsCacheService.Get(accountId);

            var liquidation = account.LiquidationOperationId;

            if (string.IsNullOrEmpty(liquidation))
            {
                throw new InvalidOperationException("Account is not in liquidation state");
            }

            _cqrsSender.SendCommandToSelf(new ResumeLiquidationInternalCommand
            {
                OperationId  = liquidation,
                CreationTime = DateTime.UtcNow,
                IsCausedBySpecialLiquidation = false,
                Comment = comment
            });

            return(Task.CompletedTask);
        }
예제 #5
0
파일: TradingEngine.cs 프로젝트: alpo-8/MT
        private void CommitStopOut(MarginTradingAccount account, InstrumentBidAskPair quote)
        {
            if (account.IsInLiquidation())
            {
                return;
            }

            var liquidationType = account.GetUsedMargin() == account.GetCurrentlyUsedMargin()
                ? LiquidationType.Normal
                : LiquidationType.Mco;

            _cqrsSender.SendCommandToSelf(new StartLiquidationInternalCommand
            {
                OperationId     = _identityGenerator.GenerateGuid(),//TODO: use quote correlationId
                AccountId       = account.Id,
                CreationTime    = _dateService.Now(),
                QuoteInfo       = quote?.ToJson(),
                LiquidationType = liquidationType,
                OriginatorType  = OriginatorType.System,
            });

            _stopOutEventChannel.SendEvent(this, new StopOutEventArgs(account));
        }
예제 #6
0
        public Dictionary <string, (PositionCloseResult, Order)> StartLiquidation(string accountId,
                                                                                  OriginatorType originator, string additionalInfo, string operationId)
        {
            var result = new Dictionary <string, (PositionCloseResult, Order)>();

            var command = new StartLiquidationInternalCommand
            {
                OperationId     = operationId,
                CreationTime    = _dateService.Now(),
                AccountId       = accountId,
                LiquidationType = LiquidationType.Forced,
                OriginatorType  = originator,
                AdditionalInfo  = additionalInfo
            };

            _cqrsSender.SendCommandToSelf(command);

            var positions = _ordersCache.Positions.GetPositionsByAccountIds(accountId);

            var openPositions = new List <Position>();

            foreach (var position in positions)
            {
                switch (position.Status)
                {
                case PositionStatus.Active:
                    openPositions.Add(position);
                    break;

                case PositionStatus.Closing:
                    result.Add(position.Id, (PositionCloseResult.ClosingIsInProgress, null));
                    break;

                case PositionStatus.Closed:
                    result.Add(position.Id, (PositionCloseResult.Closed, null));
                    break;

                default:
                    throw new InvalidOperationException($"Position state {position.Status.ToString()} is not handled");
                }
            }

            foreach (var group in openPositions.GroupBy(p => p.AssetPairId))
            {
                // if asset pair is not available for trading, we will not try to close these positions
                if (_assetPairDayOffService.IsAssetTradingDisabled(group.Key))
                {
                    continue;
                }

                var positionGroup = group.ToArray();

                // if the net volume can be liquidated, we assume that positions will be closed without special liquidation
                if (CheckIfNetVolumeCanBeLiquidated(group.Key, positionGroup, out _))
                {
                    positionGroup.ForEach(p => result.Add(p.Id, (PositionCloseResult.Closed, null)));
                }
                else
                {
                    positionGroup.ForEach(p => result.Add(p.Id, (PositionCloseResult.ClosingStarted, null)));
                }
            }

            return(result);
        }
예제 #7
0
        public async Task <RfqResumeErrorCode> ResumeAsync(string operationId, PauseCancellationSource source, Initiator initiator)
        {
            if (string.IsNullOrEmpty(operationId))
            {
                throw new ArgumentNullException(nameof(operationId));
            }

            var locker = _lock.GetOrAdd(operationId, new SemaphoreSlim(1, 1));

            await locker.WaitAsync();

            try
            {
                var executionInfo = await _executionInfoRepository
                                    .GetAsync <SpecialLiquidationOperationData>(SpecialLiquidationSaga.OperationName, operationId);

                if (executionInfo == null)
                {
                    return(RfqResumeErrorCode.NotFound);
                }

                var activePause = (await _pauseRepository.FindAsync(
                                       operationId,
                                       SpecialLiquidationSaga.OperationName,
                                       ActivePredicate))
                                  .SingleOrDefault();

                if (activePause == null)
                {
                    await _log.WriteInfoAsync(nameof(RfqPauseService), nameof(ResumeAsync), null,
                                              $"The active pause for operation id [{operationId}] and name [{SpecialLiquidationSaga.OperationName}] was not found");

                    return(RfqResumeErrorCode.NotPaused);
                }

                // Manual resume is allowed for manually paused RFQ only
                if (source == PauseCancellationSource.Manual && activePause.Source != PauseSource.Manual)
                {
                    await _log.WriteWarningAsync(nameof(RfqPauseService), nameof(ResumeAsync), null,
                                                 $"Manual resume is allowed for manually paused RFQ only");

                    return(RfqResumeErrorCode.ManualResumeDenied);
                }

                if (activePause.Oid == null)
                {
                    throw new InvalidOperationException("Pause oid is required to update");
                }

                var updated = await _pauseRepository.UpdateAsync(
                    activePause.Oid.Value,
                    activePause.EffectiveSince ?? throw new InvalidOperationException("Activated pause must have an [Effective Since] value"),
                    PauseState.PendingCancellation,
                    _dateService.Now(),
                    null,
                    initiator,
                    source);

                if (updated)
                {
                    _cqrsSender.SendCommandToSelf(new ResumePausedSpecialLiquidationCommand {
                        OperationId = operationId
                    });
                }
                else
                {
                    await _log.WriteWarningAsync(nameof(RfqPauseService), nameof(ResumeAsync), null,
                                                 $"Couldn't cancel active pause for operation id [{operationId}] and name [{SpecialLiquidationSaga.OperationName}] due to database issues");

                    return(RfqResumeErrorCode.Persistence);
                }

                // todo: add audit log
            }
            finally
            {
                locker.Release();
            }

            return(RfqResumeErrorCode.None);
        }