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);
        }
Example #4
0
        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));
                }
            }
        }