public Task <InternalOrderBookModel> GetInternalAsync(string assetPair) { InternalOrderBook orderBook = _internalOrderBookService.GetByAssetPair(assetPair); if (orderBook == null) { throw new ValidationApiException(HttpStatusCode.NotFound, "Order book does not exist"); } return(Task.FromResult(Mapper.Map <InternalOrderBookModel>(orderBook))); }
private static bool AreEqual(InternalOrderBook a, InternalOrderBook b) { if (a == null && b == null) { return(true); } if (a == null || b == null) { return(false); } if (a.AssetPair != b.AssetPair) { return(false); } return(AreEqual(a.SellLevels, b.SellLevels) && AreEqual(a.BuyLevels, b.BuyLevels)); }
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 async Task Create_Order_Book_With_Out_Arbitrage() { // arrange _assetPairs.Add(new AssetPairModel { Name = "BTCUSD", PriceAccuracy = 3 }); _externalOrderBooks.AddRange(new[] { new ExternalOrderBook { Exchange = "Exchange1", AssetPair = "BTCUSD", Timestamp = DateTime.UtcNow, SellLevels = new List <ExternalOrderBookLevel> { new ExternalOrderBookLevel { Price = 3.9626635m, Volume = 3 }, new ExternalOrderBookLevel { Price = 2.1341931m, Volume = 2 }, new ExternalOrderBookLevel { Price = 1.8762345m, Volume = 1 } }, BuyLevels = new List <ExternalOrderBookLevel> { new ExternalOrderBookLevel { Price = 1.5761689m, Volume = 1 }, new ExternalOrderBookLevel { Price = 1.0341931m, Volume = 2 }, new ExternalOrderBookLevel { Price = 0.5626635m, Volume = 3 } } }, new ExternalOrderBook { Exchange = "Exchange2", AssetPair = "BTCUSD", Timestamp = DateTime.UtcNow, SellLevels = new List <ExternalOrderBookLevel> { new ExternalOrderBookLevel { Price = 3.963m, Volume = 3 }, new ExternalOrderBookLevel { Price = 2.136m, Volume = 2 }, new ExternalOrderBookLevel { Price = 1.877m, Volume = 1 } }, BuyLevels = new List <ExternalOrderBookLevel> { new ExternalOrderBookLevel { Price = 1.576m, Volume = 1 }, new ExternalOrderBookLevel { Price = 1.035m, Volume = 2 }, new ExternalOrderBookLevel { Price = 0.562m, Volume = 3 } } } }); var expectedInternalOrderBook = new InternalOrderBook { AssetPair = "BTCUSD", Timestamp = DateTime.UtcNow, SellLevels = new List <OrderBookLevel> { new OrderBookLevel { Price = 3.963m, Volume = 6 }, new OrderBookLevel { Price = 2.136m, Volume = 2 }, new OrderBookLevel { Price = 2.135m, Volume = 2 }, new OrderBookLevel { Price = 1.877m, Volume = 2 } }, BuyLevels = new List <OrderBookLevel> { new OrderBookLevel { Price = 1.576m, Volume = 2 }, new OrderBookLevel { Price = 1.034m, Volume = 2 }, new OrderBookLevel { Price = 1.035m, Volume = 2 }, new OrderBookLevel { Price = 0.562m, Volume = 6 } } }; // act await _service.UpdateAsync("BTCUSD"); var actualInternalOrderBook = _service.GetByAssetPair("BTCUSD"); // assert Assert.IsTrue(AreEqual(expectedInternalOrderBook, actualInternalOrderBook)); }