public async Task <ApiMarketsResult> GetMarkets(string baseMarket, int hours) { hours = Math.Min(hours, 168); var cacheResult = await CacheService.GetOrSetHybridAsync(CacheKey.ApiMarkets(baseMarket, hours), TimeSpan.FromSeconds(20), async() => { var lastTime = DateTime.UtcNow.AddHours(-hours); var tradePairs = await TradePairReader.GetTradePairs().ConfigureAwait(false); if (!tradePairs.Any()) { return new ApiMarketsResult { Error = $"Markets not found", Success = true, } } ; var markets = string.IsNullOrEmpty(baseMarket) ? tradePairs : tradePairs.Where(x => x.BaseSymbol == baseMarket).ToList(); using (var context = ExchangeDataContextFactory.CreateReadOnlyContext()) { var allTrades = await context.Trade .AsNoTracking() .Where(x => (x.Status == Enums.TradeStatus.Partial || x.Status == Enums.TradeStatus.Pending)) .Select(x => new { TradePairId = x.TradePairId, Type = x.Type, Rate = x.Rate, Amount = x.Amount }).ToListNoLockAsync().ConfigureAwait(false); var allTradeHistory = await context.TradeHistory .AsNoTracking() .Where(x => x.Timestamp > lastTime) .Select(x => new { Id = x.Id, TradePairId = x.TradePairId, Rate = x.Rate, Amount = x.Amount }) .OrderBy(x => x.Id) .ToListNoLockAsync().ConfigureAwait(false); var results = new ConcurrentBag <ApiMarket>(); foreach (var tradePair in markets) { var trades = allTrades .Where(x => x.TradePairId == tradePair.TradePairId) .Select(x => new { Type = x.Type, Rate = x.Rate, Amount = x.Amount }).ToList(); var tradeHistory = allTradeHistory .Where(x => x.TradePairId == tradePair.TradePairId) .Select(x => new { Id = x.Id, Rate = x.Rate, Amount = x.Amount }) .OrderBy(x => x.Id) .ToList(); var ask = 0m; var bid = 0m; var buyVolume = 0m; var sellVolume = 0m; var buyBaseVolume = 0m; var sellBaseVolume = 0m; if (trades.Any()) { var sellOrders = trades.Where(x => x.Type == Enums.TradeHistoryType.Sell).OrderBy(x => x.Rate).ToList(); if (sellOrders.Any()) { ask = sellOrders.First().Rate; sellVolume = Math.Round(sellOrders.Sum(x => x.Amount), 8); sellBaseVolume = Math.Round(sellOrders.Sum(x => x.Amount *x.Rate), 8); } var buyOrders = trades.Where(x => x.Type == Enums.TradeHistoryType.Buy).OrderByDescending(x => x.Rate).ToList(); if (buyOrders.Any()) { bid = buyOrders.First().Rate; buyVolume = Math.Round(buyOrders.Sum(x => x.Amount), 8); buyBaseVolume = Math.Round(buyOrders.Sum(x => x.Amount *x.Rate), 8); } } var change = 0m; var volume = 0m; var baseVolume = 0m; var open = tradePair.LastTrade; var close = tradePair.LastTrade; var high = tradePair.LastTrade; var low = tradePair.LastTrade; var last = tradePair.LastTrade; if (tradeHistory.Any()) { var firstTrade = tradeHistory.FirstOrDefault(); var lastTrade = tradeHistory.LastOrDefault(); high = tradeHistory.Max(x => x.Rate); low = tradeHistory.Min(x => x.Rate); open = firstTrade.Rate; close = lastTrade.Rate; last = lastTrade.Rate; change = open.GetPercentChanged(close); volume = tradeHistory.Sum(x => x.Amount); baseVolume = Math.Round(tradeHistory.Sum(x => x.Amount *x.Rate), 8); } results.Add(new ApiMarket { Label = tradePair.Market.Replace("_", "/"), TradePairId = tradePair.TradePairId, Change = open.GetPercentChanged(close), AskPrice = ask, BidPrice = bid, BuyVolume = buyVolume, SellVolume = sellVolume, LastPrice = last, High = high, Low = low, Volume = volume, Open = open, Close = close, BaseVolume = baseVolume, BuyBaseVolume = buyBaseVolume, SellBaseVolume = sellBaseVolume }); } return(new ApiMarketsResult { Success = true, Data = results.OrderBy(x => x.Label).ToList() }); } });