private async Task CompleteAssetSettlementAsync(AssetSettlement assetSettlement) { try { AssetHedgeSettings assetHedgeSettings = await _assetHedgeSettingsService.GetByAssetIdAsync(assetSettlement.AssetId); if (!assetSettlement.IsDirect && !assetSettlement.IsExternal) { // In this case position will be closed automatically by hedge limit order. } else { await _positionService.CloseAsync(assetSettlement.AssetId, assetHedgeSettings.Exchange, assetSettlement.ActualAmount, assetSettlement.ActualPrice); } assetSettlement.Status = AssetSettlementStatus.Completed; } catch (Exception exception) { _log.ErrorWithDetails(exception, "An error occurred while completing asset settlement", assetSettlement); assetSettlement.Error = SettlementError.Unknown; } await _settlementRepository.UpdateAsync(assetSettlement); }
private async Task ClosePositionsAsync(IEnumerable <Position> positions, PositionType positionType) { foreach (IGrouping <string, Position> group in positions.GroupBy(o => o.AssetPairId)) { var startedAt = DateTime.UtcNow; MarketMakerState marketMakerState = await _marketMakerStateService.GetStateAsync(); if (marketMakerState.Status != MarketMakerStatus.Active) { continue; } Instrument instrument = await _instrumentService.GetByAssetPairIdAsync(group.Key); decimal originalVolume = group.Sum(o => o.Volume); decimal volume = Math.Round(originalVolume, instrument.VolumeAccuracy); if (volume < instrument.MinVolume) { _log.InfoWithDetails("The volume of open positions is less than min volume", new { instrument.AssetPairId, positionType, volume, instrument.MinVolume }); continue; } ExternalTrade externalTrade = await ExecuteLimitOrderAsync(group.Key, volume, positionType); if (externalTrade != null) { await _positionService.CloseAsync(group.ToArray(), externalTrade); await _remainingVolumeService.RegisterVolumeAsync(group.Key, (originalVolume - externalTrade.Volume) *GetSign(positionType)); } var finishedAt = DateTime.UtcNow; _log.Info("HedgeService.ClosePositionsAsync() completed.", new { AssetPairId = instrument.AssetPairId, TradeIds = positions.Select(x => x.TradeId).ToList(), StartedAt = startedAt, FinishedAt = finishedAt, Latency = (finishedAt - startedAt).TotalMilliseconds }); PrometheusMetrics.HedgeAssetPairLatency.Inc((finishedAt - startedAt).TotalMilliseconds); } }
private async Task <bool> ExecuteAsync(InternalOrder internalOrder) { ExternalTrade externalTrade = null; string error = null; try { externalTrade = await _externalExchangeService.ExecuteLimitOrderAsync(internalOrder.AssetPairId, internalOrder.Volume, internalOrder.Price, internalOrder.Type); } catch (NotEnoughLiquidityException) { error = Errors.NotEnoughLiquidity; } catch (Exception) { error = "An unexpected error occurred while executing order"; } if (!string.IsNullOrEmpty(error)) { internalOrder.Status = InternalOrderStatus.Failed; internalOrder.RejectReason = error; await _internalOrderRepository.UpdateAsync(internalOrder); return(false); } // ReSharper disable once PossibleNullReferenceException internalOrder.ExecutedPrice = externalTrade.Price; internalOrder.ExecutedVolume = externalTrade.Volume; internalOrder.TradeId = externalTrade.Id; internalOrder.Status = InternalOrderStatus.Executed; await _internalOrderRepository.UpdateAsync(internalOrder); await _positionService.CloseAsync(internalOrder, externalTrade); return(true); }
private async Task ClosePositionsAsync(IEnumerable <Position> positions, PositionType positionType) { foreach (IGrouping <string, Position> group in positions.GroupBy(o => o.AssetPairId)) { MarketMakerState marketMakerState = await _marketMakerStateService.GetStateAsync(); if (marketMakerState.Status != MarketMakerStatus.Active) { continue; } Instrument instrument = await _instrumentService.GetByAssetPairIdAsync(group.Key); decimal originalVolume = group.Sum(o => o.Volume); decimal volume = Math.Round(originalVolume, instrument.VolumeAccuracy); if (volume < instrument.MinVolume) { _log.InfoWithDetails("The volume of open positions is less than min volume", new { instrument.AssetPairId, positionType, volume, instrument.MinVolume }); continue; } ExternalTrade externalTrade = await ExecuteLimitOrderAsync(group.Key, volume, positionType); if (externalTrade != null) { await _positionService.CloseAsync(group.ToArray(), externalTrade); await _remainingVolumeService.RegisterVolumeAsync(group.Key, (originalVolume - volume) *GetSign(positionType)); } } }