private static void SubscribeToStreams(BinanceWebsocketClient client) { client.Streams.PongStream.Subscribe(x => Log.Information($"Pong received ({x.Message})")); client.Streams.AggregateTradesStream.Subscribe(response => { var trade = response.Data; Log.Information($"Trade aggreg [{trade.Symbol}] [{trade.Side}] " + $"price: {trade.Price} size: {trade.Quantity}"); }); client.Streams.TradesStream.Subscribe(response => { var trade = response.Data; Log.Information($"Trade normal [{trade.Symbol}] [{trade.Side}] " + $"price: {trade.Price} size: {trade.Quantity}"); }); client.Streams.OrderBookPartialStream.Subscribe(response => { var ob = response.Data; Log.Information($"Order book snapshot [{ob.Symbol}] " + $"bid: {ob.Bids.FirstOrDefault()?.Price:F} " + $"ask: {ob.Asks.FirstOrDefault()?.Price:F}"); }); client.Streams.OrderBookDiffStream.Subscribe(response => { var ob = response.Data; Log.Information($"Order book diff [{ob.Symbol}] " + $"bid: {ob.Bids.FirstOrDefault()?.Price:F} " + $"ask: {ob.Asks.FirstOrDefault()?.Price:F}"); }); }
private static async Task<ICryptoOrderBook> StartBinance(string pair, bool optimized, bool l2Optimized) { var url = BinanceValues.ApiWebsocketUrl; var communicator = new BinanceWebsocketCommunicator(url) { Name = "Binance" }; var client = new BinanceWebsocketClient(communicator); client.SetSubscriptions( new OrderBookDiffSubscription(pair) ); var source = new BinanceOrderBookSource(client); var orderBook = l2Optimized ? new CryptoOrderBookL2(pair, source) : (ICryptoOrderBook)new CryptoOrderBook(pair, source); if (optimized) { ConfigureOptimized(source, orderBook); } _ = communicator.Start(); // Binance is special // We need to load snapshot in advance manually via REST call _ = source.LoadSnapshot(communicator, pair); return orderBook; }
public async Task ConnectToSource_ShouldHandleOrderBookCorrectly() { var url = BinanceValues.ApiWebsocketUrl; using (var communicator = new BinanceWebsocketCommunicator(url)) { using (var client = new BinanceWebsocketClient(communicator)) { var pair = "BTCUSDT"; client.SetSubscriptions( new OrderBookDiffSubscription(pair) ); var source = new BinanceOrderBookSource(client); var orderBook = new CryptoOrderBook(pair, source); await communicator.Start(); // Binance is special // We need to load snapshot in advance manually via REST call await source.LoadSnapshot(pair); await Task.Delay(TimeSpan.FromSeconds(5)); Assert.True(orderBook.BidPrice > 0); Assert.True(orderBook.AskPrice > 0); Assert.NotEmpty(orderBook.BidLevels); Assert.NotEmpty(orderBook.AskLevels); } } }
public async Task AutoSnapshotReloading_ShouldWorkAfterTimeout() { var url = BinanceValues.ApiWebsocketUrl; using (var communicator = new BinanceWebsocketCommunicator(url)) { using (var client = new BinanceWebsocketClient(communicator)) { var pair = "BTCUSDT"; client.SetSubscriptions( new OrderBookDiffSubscription(pair) ); var source = new BinanceOrderBookSource(client) { LoadSnapshotEnabled = true }; var orderBook = new CryptoOrderBook(pair, source) { SnapshotReloadTimeout = TimeSpan.FromSeconds(5), SnapshotReloadEnabled = true }; await Task.Delay(TimeSpan.FromSeconds(13)); Assert.True(orderBook.BidPrice > 0); Assert.True(orderBook.AskPrice > 0); Assert.NotEmpty(orderBook.BidLevels); Assert.NotEmpty(orderBook.AskLevels); } } }
public async Task Connect_ShouldWorkAndReceiveResponse() { var url = BinanceValues.ApiWebsocketUrl; using (var communicator = new BinanceWebsocketCommunicator(url)) { TradeResponse received = null; var receivedEvent = new ManualResetEvent(false); using (var client = new BinanceWebsocketClient(communicator)) { client.Streams.TradesStream.Subscribe(response => { received = response; receivedEvent.Set(); }); client.SetSubscriptions( new TradeSubscription("btcusdt") ); await communicator.Start(); receivedEvent.WaitOne(TimeSpan.FromSeconds(30)); Assert.NotNull(received); } } }
private void SetSubscriptions(BinanceWebsocketClient client, string pair) { client.SetSubscriptions( new TradeSubscription(pair), new OrderBookPartialSubscription(pair, 20) ); }
public async Task OnStart_ShouldStreamMessagesFromFile() { var files = new[] { "data/binance_raw_xbtusd_2018-11-13.txt" }; foreach (var file in files) { var exist = File.Exists(file); Skip.If(!exist, $"The file '{file}' doesn't exist. Don't forget to decompress gzip file!"); } var trades = new List <Trade>(); var communicator = new BinanceFileCommunicator(); communicator.FileNames = files; communicator.Delimiter = ";;"; var client = new BinanceWebsocketClient(communicator); client.Streams.TradesStream.Subscribe(response => { trades.Add(response.Data); }); await communicator.Start(); Assert.Equal(44259, trades.Count); }
/// <summary> /// Change client and resubscribe to the new streams /// </summary> public void ChangeClient(BinanceWebsocketClient client) { CryptoValidations.ValidateInput(client, nameof(client)); _client = client; _subscription?.Dispose(); Subscribe(); }
private void OnStop() { _pingSubscription?.Dispose(); _client.Dispose(); _communicator.Dispose(); _client = null; _communicator = null; Clear(); }
private void StartPingCheck(BinanceWebsocketClient client) { //_pingSubscription = Observable // .Interval(TimeSpan.FromSeconds(5)) // .Subscribe(async x => // { // _pingRequest = DateTime.UtcNow; // await client.Send(new PingRequest()); // }); }
static void Main(string[] args) { InitLogging(); AppDomain.CurrentDomain.ProcessExit += CurrentDomainOnProcessExit; AssemblyLoadContext.Default.Unloading += DefaultOnUnloading; Console.CancelKeyPress += ConsoleOnCancelKeyPress; Console.WriteLine("|=======================|"); Console.WriteLine("| BINANCE CLIENT |"); Console.WriteLine("|=======================|"); Console.WriteLine(); Log.Debug("===================================="); Log.Debug(" STARTING "); Log.Debug("===================================="); var url = BinanceValues.ApiWebsocketUrl; using (var communicator = new BinanceWebsocketCommunicator(url)) { communicator.Name = "Binance-1"; communicator.ReconnectTimeout = TimeSpan.FromMinutes(10); communicator.ReconnectionHappened.Subscribe(type => Log.Information($"Reconnection happened, type: {type}")); using (var client = new BinanceWebsocketClient(communicator)) { SubscribeToStreams(client, communicator); client.SetSubscriptions( new TradeSubscription("btcusdt"), //new TradeSubscription("ethbtc"), //new TradeSubscription("bnbusdt"), new AggregateTradeSubscription("bnbusdt"), new OrderBookPartialSubscription("btcusdt", 5), //new OrderBookPartialSubscription("bnbusdt", 10), new OrderBookDiffSubscription("ltcusdt") ); communicator.Start().Wait(); ExitEvent.WaitOne(); } } Log.Debug("===================================="); Log.Debug(" STOPPING "); Log.Debug("===================================="); Log.CloseAndFlush(); }
private static (ITradeSource, IWebsocketClient) GetBinance(string pair) { var url = BinanceValues.ApiWebsocketUrl; var communicator = new BinanceWebsocketCommunicator(url) { Name = "Binance" }; var client = new BinanceWebsocketClient(communicator); var source = new BinanceTradeSource(client); client.SetSubscriptions( new TradeSubscription(pair) ); return(source, communicator); }
private static void SubscribeToStreams(BinanceWebsocketClient client, IBinanceCommunicator comm) { client.Streams.PongStream.Subscribe(x => Log.Information($"Pong received ({x.Message})")); client.Streams.FundingStream.Subscribe(response => { var funding = response.Data; Log.Information($"Funding: [{funding.Symbol}] rate:[{funding.FundingRate}] " + $"mark price: {funding.MarkPrice} next funding: {funding.NextFundingTime} " + $"index price {funding.IndexPrice}"); }); client.Streams.AggregateTradesStream.Subscribe(response => { var trade = response.Data; Log.Information($"Trade aggreg [{trade.Symbol}] [{trade.Side}] " + $"price: {trade.Price} size: {trade.Quantity}"); }); client.Streams.TradesStream.Subscribe(response => { var trade = response.Data; Log.Information($"Trade normal [{trade.Symbol}] [{trade.Side}] " + $"price: {trade.Price} size: {trade.Quantity}"); }); client.Streams.OrderBookPartialStream.Subscribe(response => { var ob = response.Data; Log.Information($"Order book snapshot [{ob.Symbol}] " + $"bid: {ob.Bids.FirstOrDefault()?.Price:F} " + $"ask: {ob.Asks.FirstOrDefault()?.Price:F}"); Task.Delay(500).Wait(); //OrderBookPartialResponse.StreamFakeSnapshot(response.Data, comm); }); client.Streams.OrderBookDiffStream.Subscribe(response => { var ob = response.Data; Log.Information($"Order book diff [{ob.Symbol}] " + $"bid: {ob.Bids.FirstOrDefault()?.Price:F} " + $"ask: {ob.Asks.FirstOrDefault()?.Price:F}"); }); }
private async Task OnStart() { var pair = _view.Pair; if (string.IsNullOrWhiteSpace(pair)) { pair = _defaultPair; } pair = pair.ToUpper(); _tradeStatsComputer = new TradeStatsComputer(); _orderBookStatsComputer = new OrderBookStatsComputer(); var url = BinanceValues.ApiWebsocketUrl; _communicator = new BinanceWebsocketCommunicator(url); _client = new BinanceWebsocketClient(_communicator); Subscribe(_client); _communicator.ReconnectionHappened.Subscribe(type => { _view.Status($"Reconnected (type: {type})", StatusType.Info); }); _communicator.DisconnectionHappened.Subscribe(type => { if (type == DisconnectionType.Error) { _view.Status($"Disconnected by error, next try in {_communicator.ErrorReconnectTimeoutMs/1000} sec", StatusType.Error); return; } _view.Status($"Disconnected (type: {type})", StatusType.Warning); }); SetSubscriptions(_client, pair); await _communicator.Start(); StartPingCheck(_client); }
private void Subscribe(BinanceWebsocketClient client) { client.Streams.TradesStream.ObserveOn(TaskPoolScheduler.Default).Subscribe(HandleTrades); client.Streams.OrderBookPartialStream.ObserveOn(TaskPoolScheduler.Default).Subscribe(HandleOrderBook); client.Streams.PongStream.ObserveOn(TaskPoolScheduler.Default).Subscribe(HandlePong); }
private static void SubscribeToStreams(BinanceWebsocketClient client, IBinanceCommunicator comm) { client.Streams.PongStream.Subscribe(x => Log.Information($"Pong received ({x.Message})")); client.Streams.FundingStream.Subscribe(response => { var funding = response.Data; Log.Information($"Funding: [{funding.Symbol}] rate:[{funding.FundingRate}] " + $"mark price: {funding.MarkPrice} next funding: {funding.NextFundingTime} " + $"index price {funding.IndexPrice}"); }); client.Streams.AggregateTradesStream.Subscribe(response => { var trade = response.Data; Log.Information($"Trade aggreg [{trade.Symbol}] [{trade.Side}] " + $"price: {trade.Price} size: {trade.Quantity}"); }); client.Streams.TradesStream.Subscribe(response => { var trade = response.Data; Log.Information($"Trade normal [{trade.Symbol}] [{trade.Side}] " + $"price: {trade.Price} size: {trade.Quantity}"); }); client.Streams.OrderBookPartialStream.Subscribe(response => { var ob = response.Data; Log.Information($"Order book snapshot [{ob.Symbol}] " + $"bid: {ob.Bids.FirstOrDefault()?.Price:F} " + $"ask: {ob.Asks.FirstOrDefault()?.Price:F}"); Task.Delay(500).Wait(); //OrderBookPartialResponse.StreamFakeSnapshot(response.Data, comm); }); client.Streams.OrderBookDiffStream.Subscribe(response => { var ob = response.Data; Log.Information($"Order book diff [{ob.Symbol}] " + $"bid: {ob.Bids.FirstOrDefault()?.Price:F} " + $"ask: {ob.Asks.FirstOrDefault()?.Price:F}"); }); client.Streams.BookTickerStream.Subscribe(response => { var ob = response.Data; Log.Information($"Book ticker [{ob.Symbol}] " + $"Best ask price: {ob.BestAskPrice} " + $"Best ask qty: {ob.BestAskQty} " + $"Best bid price: {ob.BestBidPrice} " + $"Best bid qty: {ob.BestBidQty}"); }); client.Streams.KlineStream.Subscribe(response => { var ob = response.Data; Log.Information($"Kline [{ob.Symbol}] " + $"Kline start time: {ob.StartTime} " + $"Kline close time: {ob.CloseTime} " + $"Interval: {ob.Interval} " + $"First trade ID: {ob.FirstTradeId} " + $"Last trade ID: {ob.LastTradeId} " + $"Open price: {ob.OpenPrice} " + $"Close price: {ob.ClosePrice} " + $"High price: {ob.HighPrice} " + $"Low price: {ob.LowPrice} " + $"Base asset volume: {ob.BaseAssetVolume} " + $"Number of trades: {ob.NumberTrades} " + $"Is this kline closed?: {ob.IsClose} " + $"Quote asset volume: {ob.QuoteAssetVolume} " + $"Taker buy base: {ob.TakerBuyBaseAssetVolume} " + $"Taker buy quote: {ob.TakerBuyQuoteAssetVolume} " + $"Ignore: {ob.Ignore} "); }); client.Streams.MiniTickerStream.Subscribe(response => { var ob = response.Data; Log.Information($"Mini-ticker [{ob.Symbol}] " + $"Open price: {ob.OpenPrice} " + $"Close price: {ob.ClosePrice} " + $"High price: {ob.HighPrice} " + $"Low price: {ob.LowPrice} " + $"Base asset volume: {ob.BaseAssetVolume} " + $"Quote asset volume: {ob.QuoteAssetVolume}"); }); }
/// <inheritdoc /> public BinanceOrderBookSource(BinanceWebsocketClient client) { _httpClient.BaseAddress = new Uri("https://www.binance.com"); ChangeClient(client); }
/// <inheritdoc /> public BinanceTradeSource(BinanceWebsocketClient client) { ChangeClient(client); }