private async Task <IReadOnlyCollection <HedgeLimitOrder> > CreateLimitOrdersAsync(
            IEnumerable <AssetInvestment> assetInvestments)
        {
            HedgeSettings hedgeSettings = await _hedgeSettingsService.GetAsync();

            var hedgeLimitOrders = new List <HedgeLimitOrder>();

            foreach (AssetInvestment assetInvestment in assetInvestments)
            {
                AssetHedgeSettings assetHedgeSettings =
                    await _assetHedgeSettingsService.EnsureAsync(assetInvestment.AssetId);

                LimitOrderType limitOrderType = assetInvestment.RemainingAmount > 0
                    ? LimitOrderType.Sell
                    : LimitOrderType.Buy;

                if (!CanCreateHedgeLimitOrder(assetInvestment, assetHedgeSettings, hedgeSettings, limitOrderType))
                {
                    continue;
                }

                decimal commonThresholdUp = limitOrderType == LimitOrderType.Buy
                    ? hedgeSettings.ThresholdUpBuy
                    : hedgeSettings.ThresholdUpSell;

                LimitOrderPrice limitOrderPrice = LimitOrderPriceCalculator.Calculate(assetInvestment.Quote,
                                                                                      Math.Abs(assetInvestment.RemainingAmount), limitOrderType,
                                                                                      assetHedgeSettings.ThresholdUp ?? commonThresholdUp, hedgeSettings.MarketOrderMarkup);

                decimal price = limitOrderPrice.Price;

                decimal volume = Math.Abs(assetInvestment.RemainingAmount / assetInvestment.Quote.Mid);

                HedgeLimitOrder hedgeLimitOrder = HedgeLimitOrder.Create(assetHedgeSettings.Exchange,
                                                                         assetHedgeSettings.AssetId, assetHedgeSettings.AssetPairId, limitOrderType, limitOrderPrice.Type,
                                                                         price, volume);

                hedgeLimitOrder.Context = assetInvestment.ToJson();

                hedgeLimitOrders.Add(hedgeLimitOrder);
            }

            return(hedgeLimitOrders);
        }
        public async Task <HedgeSettingsModel> GetHedgeSettingsAsync()
        {
            HedgeSettings hedgeSettings = await _hedgeSettingsService.GetAsync();

            return(Mapper.Map <HedgeSettingsModel>(hedgeSettings));
        }
        private async Task <IReadOnlyCollection <PositionReport> > CreateReports()
        {
            IReadOnlyCollection <Position> positions = await _positionService.GetAllAsync();

            IReadOnlyCollection <AssetInvestment> assetInvestments = _investmentService.GetAll();

            IReadOnlyCollection <HedgeLimitOrder> hedgeLimitOrders = _hedgeLimitOrderService.GetAll();

            HedgeSettings hedgeSettings = await _hedgeSettingsService.GetAsync();

            IReadOnlyCollection <AssetHedgeSettings>
            assetsHedgeSettings = await _assetHedgeSettingsService.GetAllAsync();

            string[] assets = positions.Select(o => o.AssetId)
                              .Union(assetInvestments.Select(o => o.AssetId))
                              .Union(assetsHedgeSettings.Select(o => o.AssetId))
                              .ToArray();

            var positionReports = new List <PositionReport>();

            foreach (string assetId in assets)
            {
                AssetHedgeSettings assetHedgeSettings = await _assetHedgeSettingsService.EnsureAsync(assetId);

                Position currentPosition = positions
                                           .SingleOrDefault(o => o.AssetId == assetId && o.Exchange == assetHedgeSettings.Exchange);

                HedgeLimitOrder hedgeLimitOrder = hedgeLimitOrders.SingleOrDefault(o => o.AssetId == assetId);

                AssetInvestment assetInvestment = assetInvestments.SingleOrDefault(o => o.AssetId == assetId);

                decimal?volumeInUsd = null;

                if (currentPosition != null)
                {
                    volumeInUsd = GetVolumeInUsd(currentPosition.AssetId, currentPosition.Exchange,
                                                 currentPosition.Volume);
                }

                Quote assetQuote;

                if (assetInvestment == null)
                {
                    assetQuote = _rateService.GetQuoteUsd(assetHedgeSettings.AssetId, assetHedgeSettings.Exchange);
                }
                else
                {
                    assetQuote = assetInvestment.Quote;
                }

                positionReports.Add(new PositionReport
                {
                    AssetId         = assetId,
                    Exchange        = assetHedgeSettings.Exchange,
                    Quote           = assetQuote,
                    Volume          = currentPosition?.Volume,
                    VolumeInUsd     = volumeInUsd,
                    OppositeVolume  = currentPosition?.OppositeVolume,
                    PnL             = volumeInUsd.HasValue ? currentPosition.OppositeVolume + volumeInUsd : null,
                    HedgeLimitOrder = hedgeLimitOrder,
                    AssetInvestment = assetInvestment,
                    Error           = ValidateAssetHedgeSettings(assetHedgeSettings)
                                      ?? ValidateInvestments(assetInvestment)
                                      ?? ValidateThresholdCritical(assetInvestment, hedgeSettings, assetHedgeSettings)
                                      ?? ValidateQuote(assetQuote)
                });

                IEnumerable <Position> otherPositions = positions
                                                        .Where(o => o.AssetId == assetId && o.Exchange != assetHedgeSettings.Exchange);

                foreach (Position position in otherPositions)
                {
                    Quote otherPositionQuote = _rateService.GetQuoteUsd(position.AssetId, position.Exchange);

                    volumeInUsd = GetVolumeInUsd(position.AssetId, position.Exchange, position.Volume);

                    positionReports.Add(new PositionReport
                    {
                        AssetId         = assetId,
                        Exchange        = position.Exchange,
                        Quote           = otherPositionQuote,
                        Volume          = position.Volume,
                        VolumeInUsd     = volumeInUsd,
                        OppositeVolume  = position.OppositeVolume,
                        PnL             = volumeInUsd.HasValue ? position.OppositeVolume + volumeInUsd : null,
                        HedgeLimitOrder = null,
                        AssetInvestment = null,
                        Error           = ValidateAssetHedgeSettings(assetHedgeSettings)
                                          ?? ValidateQuote(otherPositionQuote)
                    });
                }
            }

            foreach (PositionReport positionReport in positionReports)
            {
                if (positionReport.Exchange == ExchangeNames.Virtual)
                {
                    positionReport.ActualPnL = -1 * positionReport.PnL;
                }
                else
                {
                    positionReport.ActualPnL = positionReport.PnL;
                }
            }

            return(positionReports
                   .OrderBy(o => o.AssetId)
                   .ToArray());
        }