@page "/OrderBooks" @using System.Collections.Concurrent @using System.Timers @using Binance.Net.Interfaces @using BingX.Net.Interfaces @using Bitfinex.Net.Interfaces @using Bitget.Net.Interfaces; @using BitMart.Net.Interfaces; @using BitMEX.Net.Interfaces; @using Bybit.Net.Interfaces @using CoinEx.Net.Interfaces @using Coinbase.Net.Interfaces @using CryptoExchange.Net.Interfaces @using CryptoCom.Net.Interfaces @using GateIo.Net.Interfaces @using HTX.Net.Interfaces @using HyperLiquid.Net.Interfaces @using Kraken.Net.Interfaces @using Kucoin.Net.Clients @using Kucoin.Net.Interfaces @using Mexc.Net.Interfaces @using OKX.Net.Interfaces; @using WhiteBit.Net.Interfaces @inject IBinanceOrderBookFactory binanceFactory @inject IBingXOrderBookFactory bingXFactory @inject IBitfinexOrderBookFactory bitfinexFactory @inject IBitgetOrderBookFactory bitgetFactory @inject IBitMartOrderBookFactory bitmartFactory @inject IBitMEXOrderBookFactory bitmexFactory @inject IBybitOrderBookFactory bybitFactory @inject ICoinbaseOrderBookFactory coinbaseFactory @inject ICoinExOrderBookFactory coinExFactory @inject ICryptoComOrderBookFactory cryptocomFactory @inject IGateIoOrderBookFactory gateioFactory @inject IHTXOrderBookFactory htxFactory @inject IHyperLiquidOrderBookFactory hyperLiquidFactory @inject IKrakenOrderBookFactory krakenFactory @inject IKucoinOrderBookFactory kucoinFactory @inject IMexcOrderBookFactory mexcFactory @inject IOKXOrderBookFactory okxFactory @inject IWhiteBitOrderBookFactory whitebitFactory @implements IDisposable

ETH-BTC books, live updates:

@foreach(var book in _books.OrderBy(p => p.Key)) {

@book.Key

@if (book.Value.AskCount >= 3 && book.Value.BidCount >= 3) { for (var i = 0; i < 3; i++) {
@book.Value.Bids.ElementAt(i).Price - @book.Value.Asks.ElementAt(i).Price
} }
}
@code{ private Dictionary _books = new Dictionary(); private Timer _timer; protected override async Task OnInitializedAsync() { // Since the Kucoin order book stream needs authentication we will need to provide API credentials beforehand KucoinRestClient.SetDefaultOptions(options => { options.ApiCredentials = new Kucoin.Net.Objects.KucoinApiCredentials("KEY", "SECRET", "PASSPHRASE"); }); _books = new Dictionary { { "Binance", binanceFactory.CreateSpot("ETHBTC") }, { "BingX", bingXFactory.CreateSpot("ETH-BTC") }, { "Bitfinex", bitfinexFactory.Create("tETHBTC") }, { "Bitget", bitgetFactory.CreateSpot("ETHBTC") }, { "BitMart", bitmartFactory.CreateSpot("ETH_BTC", null) }, { "BitMEX", bitmexFactory.Create("ETH_XBT") }, { "Bybit", bybitFactory.Create("ETHBTC", Bybit.Net.Enums.Category.Spot) }, { "Coinbase", coinbaseFactory.Create("ETH-BTC", null) }, { "CoinEx", coinExFactory.CreateSpot("ETHBTC") }, { "CryptoCom", cryptocomFactory.Create("ETH_BTC") }, { "GateIo", gateioFactory.CreateSpot("ETH_BTC") }, { "HTX", htxFactory.CreateSpot("ethbtc") }, // HyperLiquid does not support the ETH/BTC pair //{ "HyperLiquid", hyperLiquidFactory.Create("ETH/BTC") }, { "Kraken", krakenFactory.CreateSpot("ETH/BTC") }, { "Kucoin", kucoinFactory.CreateSpot("ETH-BTC") }, { "Mexc", mexcFactory.CreateSpot("ETHBTC") }, { "OKX", okxFactory.Create("ETH-BTC") }, { "WhiteBit", whitebitFactory.CreateV4("ETH_BTC") }, }; await Task.WhenAll(_books.Select(b => b.Value.StartAsync())); // Use a manual update timer so the page isn't refreshed too often _timer = new Timer(500); _timer.Start(); _timer.Elapsed += (o, e) => InvokeAsync(StateHasChanged); } public void Dispose() { _timer.Stop(); _timer.Dispose(); foreach (var book in _books.Where(b => b.Value.Status != CryptoExchange.Net.Objects.OrderBookStatus.Disconnected)) // It's not necessary to wait for this _ = book.Value.StopAsync(); } }