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