public Task UpdateAsync(string assetPair) { string exchangeName = _settingsService.GetExchangeName(); AssetPairModel assetPairSettings = _marketInstrumentService.GetAssetPair(assetPair, exchangeName); if (assetPairSettings == null) { throw new FailedOperationException("Asset pair not found"); } IReadOnlyList <ExternalOrderBook> externalOrderBooks = _externalOrderBookService.GetByAssetPair(assetPair); var sellLevels = new Dictionary <decimal, decimal>(); decimal ask = decimal.MaxValue; foreach (ExternalOrderBook externalOrderBook in externalOrderBooks) { foreach (ExternalOrderBookLevel priceLevel in externalOrderBook.SellLevels) { decimal price = priceLevel.Price.TruncateDecimalPlaces(assetPairSettings.PriceAccuracy, true); if (!sellLevels.ContainsKey(price)) { sellLevels[price] = 0; } sellLevels[price] += priceLevel.Volume; if (ask > price) { ask = price; } } } var buyLevels = new Dictionary <decimal, decimal>(); decimal bid = decimal.MinValue; foreach (ExternalOrderBook externalOrderBook in externalOrderBooks) { foreach (ExternalOrderBookLevel priceLevel in externalOrderBook.BuyLevels) { decimal price = priceLevel.Price.TruncateDecimalPlaces(assetPairSettings.PriceAccuracy); if (!buyLevels.ContainsKey(price)) { buyLevels[price] = 0; } buyLevels[price] += priceLevel.Volume; if (bid < price) { bid = price; } } } if (ask <= bid) { decimal mid = Math.Round((ask + bid) / 2, assetPairSettings.PriceAccuracy); var basisPoint = (decimal)Math.Pow(.1, assetPairSettings.PriceAccuracy); ask = mid + basisPoint; bid = mid - basisPoint; } var sellOrderBookLevels = new List <OrderBookLevel>(); var bestSellLevel = new OrderBookLevel { Price = ask }; foreach (var(price, volume) in sellLevels) { if (price <= ask) { bestSellLevel.Volume += volume; } else { sellOrderBookLevels.Add(new OrderBookLevel { Price = price, Volume = volume }); } } if (bestSellLevel.Volume > 0) { sellOrderBookLevels.Add(bestSellLevel); } var buyOrderBookLevels = new List <OrderBookLevel>(); var bestBuyLevel = new OrderBookLevel { Price = bid }; foreach (var(price, volume) in buyLevels) { if (price >= bid) { bestBuyLevel.Volume += volume; } else { buyOrderBookLevels.Add(new OrderBookLevel { Price = price, Volume = volume }); } } if (bestBuyLevel.Volume > 0) { buyOrderBookLevels.Add(bestBuyLevel); } var internalOrderBook = new InternalOrderBook { AssetPair = assetPairSettings.Name, Timestamp = DateTime.UtcNow, SellLevels = sellOrderBookLevels .OrderBy(o => o.Price) .ToList(), BuyLevels = buyOrderBookLevels .OrderByDescending(o => o.Price) .ToList() }; _orderBooks.AddOrUpdate(assetPair, internalOrderBook, (key, value) => internalOrderBook); return(Task.CompletedTask); }
public Task UpdateAsync(string assetPair) { string exchangeName = _settingsService.GetExchangeName(); AssetPairModel assetPairSettings = _marketInstrumentService.GetAssetPair(assetPair, exchangeName); if (assetPairSettings == null) { throw new FailedOperationException("Asset pair not found"); } IReadOnlyList <ExternalOrderBook> externalOrderBooks = _externalOrderBookService.GetByAssetPair(assetPair); var sellLevels = new Dictionary <decimal, Dictionary <string, ExternalOrderBookLevel> >(); foreach (ExternalOrderBook externalOrderBook in externalOrderBooks) { foreach (ExternalOrderBookLevel priceLevel in externalOrderBook.SellLevels) { decimal price = priceLevel.Price.TruncateDecimalPlaces(assetPairSettings.PriceAccuracy, true); if (!sellLevels.ContainsKey(price)) { sellLevels[price] = new Dictionary <string, ExternalOrderBookLevel>(); } sellLevels[price][externalOrderBook.Exchange] = priceLevel; } } var buyLevels = new Dictionary <decimal, Dictionary <string, ExternalOrderBookLevel> >(); foreach (ExternalOrderBook externalOrderBook in externalOrderBooks) { foreach (ExternalOrderBookLevel priceLevel in externalOrderBook.BuyLevels) { decimal price = priceLevel.Price.TruncateDecimalPlaces(assetPairSettings.PriceAccuracy); if (!buyLevels.ContainsKey(price)) { buyLevels[price] = new Dictionary <string, ExternalOrderBookLevel>(); } buyLevels[price][externalOrderBook.Exchange] = priceLevel; } } var aggregatedOrderBook = new AggregatedOrderBook { AssetPair = assetPair, Timestamp = DateTime.UtcNow, SellLevels = sellLevels .Select(priceLevel => new AggregatedOrderBookLevel { Price = priceLevel.Key, Volume = priceLevel.Value.Sum(exchangeVolume => exchangeVolume.Value.Volume), ExchangeVolumes = priceLevel.Value .Select(o => new AggregatedOrderBookVolume(o.Key, o.Value.OriginalPrice, o.Value.Volume)) .ToList() }) .OrderBy(o => o.Price) .ToList(), BuyLevels = buyLevels .Select(priceLevel => new AggregatedOrderBookLevel { Price = priceLevel.Key, Volume = priceLevel.Value.Sum(exchangeVolume => exchangeVolume.Value.Volume), ExchangeVolumes = priceLevel.Value .Select(o => new AggregatedOrderBookVolume(o.Key, o.Value.OriginalPrice, o.Value.Volume)) .ToList() }) .OrderByDescending(o => o.Price) .ToList() }; _orderBooks.AddOrUpdate(assetPair, aggregatedOrderBook, (key, value) => aggregatedOrderBook); return(Task.CompletedTask); }