From bb82a77f81ffbe7b7779537fa63aaa70949b5c58 Mon Sep 17 00:00:00 2001 From: Jan Korf Date: Mon, 28 Oct 2024 14:23:13 +0100 Subject: [PATCH] Trackers (#1438) Updated examples Updated CryptoExchange.Net to v8.1.0 Moved FormatSymbol to BinanceExchange class Added support Side setting on SharedTrade model Added BinanceTrackerFactory Added overload to Create method on BinanceOrderBookFactory support SharedSymbol parameter Fixed Shared rest GetTradeHistoryAsync pagination Added catch around HttpClientHandler.AutomaticDecompression setting as it's not support on Blazor WASM --- Binance.Net/Binance.Net.csproj | 2 +- Binance.Net/Binance.Net.xml | 65 +++++++++++ Binance.Net/BinanceExchange.cs | 28 ++++- Binance.Net/BinanceTrackerFactory.cs | 102 +++++++++++++++++ .../BinanceRestClientCoinFuturesApi.cs | 4 +- .../BinanceRestClientCoinFuturesApiShared.cs | 12 +- .../BinanceSocketClientCoinFuturesApi.cs | 4 +- ...BinanceSocketClientCoinFuturesApiShared.cs | 2 +- .../GeneralApi/BinanceRestClientGeneralApi.cs | 3 +- .../SpotApi/BinanceRestClientSpotApi.cs | 3 +- .../SpotApi/BinanceRestClientSpotApiShared.cs | 12 +- .../SpotApi/BinanceSocketClientSpotApi.cs | 3 +- .../BinanceSocketClientSpotApiShared.cs | 5 +- .../BinanceRestClientUsdFuturesApi.cs | 4 +- .../BinanceRestClientUsdFuturesApiShared.cs | 12 +- .../BinanceSocketClientUsdFuturesApi.cs | 4 +- .../BinanceSocketClientUsdFuturesApiShared.cs | 5 +- .../ServiceCollectionExtensions.cs | 12 +- .../Interfaces/IBinanceOrderBookFactory.cs | 9 ++ .../Interfaces/IBinanceTrackerFactory.cs | 34 ++++++ .../BinanceOrderBookFactory.cs | 25 ++++- Examples/Asp.NetCore.MVC/Asp.Net.csproj | 4 +- .../Binance.Examples.OrderBook.csproj | 18 +++ .../Binance.Examples.OrderBook/Program.cs | 52 +++++++++ .../Binance.Examples.Tracker.csproj | 18 +++ Examples/Binance.Examples.Tracker/Program.cs | 104 ++++++++++++++++++ .../Blazor.ClientSide.csproj | 10 +- .../Blazor.ServerSide.csproj | 7 +- Examples/ConsoleClient/ConsoleClient.csproj | 4 +- Examples/Examples.sln | 20 +++- Examples/Minimal WebApi/Minimal WebApi.csproj | 11 +- Examples/WpfClient/WpfClient.csproj | 9 +- 32 files changed, 548 insertions(+), 59 deletions(-) create mode 100644 Binance.Net/BinanceTrackerFactory.cs create mode 100644 Binance.Net/Interfaces/IBinanceTrackerFactory.cs create mode 100644 Examples/Binance.Examples.OrderBook/Binance.Examples.OrderBook.csproj create mode 100644 Examples/Binance.Examples.OrderBook/Program.cs create mode 100644 Examples/Binance.Examples.Tracker/Binance.Examples.Tracker.csproj create mode 100644 Examples/Binance.Examples.Tracker/Program.cs diff --git a/Binance.Net/Binance.Net.csproj b/Binance.Net/Binance.Net.csproj index a43ab5e5b..1dabbc7fc 100644 --- a/Binance.Net/Binance.Net.csproj +++ b/Binance.Net/Binance.Net.csproj @@ -48,10 +48,10 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + all runtime; build; native; contentfiles; analyzers; buildtransitive - \ No newline at end of file diff --git a/Binance.Net/Binance.Net.xml b/Binance.Net/Binance.Net.xml index cae5bc2a2..6480927ed 100644 --- a/Binance.Net/Binance.Net.xml +++ b/Binance.Net/Binance.Net.xml @@ -94,6 +94,16 @@ Urls to the API documentation + + + Format a base and quote asset to a Binance recognized symbol + + Base asset + Quote asset + Trading mode + Delivery time for delivery futures + + Rate limiter configuration for the Binance API @@ -148,6 +158,26 @@ + + + + + + ctor + + + + + ctor + + Service provider for resolving logging and clients + + + + + + + @@ -13261,6 +13291,14 @@ Coin Futures order book factory methods + + + Create a SymbolOrderBook for the symbol + + The symbol + Book options + + Create a Spot SymbolOrderBook @@ -13395,6 +13433,30 @@ The quantity of the best ask price in the order book + + + Tracker factory + + + + + Create a new kline tracker + + The symbol + Kline interval + The max amount of klines to retain + The max period the data should be retained + + + + + Create a new trade tracker for a symbol + + The symbol + The max amount of klines to retain + The max period the data should be retained + + Information about a trade @@ -29542,6 +29604,9 @@ + + + diff --git a/Binance.Net/BinanceExchange.cs b/Binance.Net/BinanceExchange.cs index 60358f298..26c570c6c 100644 --- a/Binance.Net/BinanceExchange.cs +++ b/Binance.Net/BinanceExchange.cs @@ -2,6 +2,7 @@ using CryptoExchange.Net.RateLimiting.Filters; using CryptoExchange.Net.RateLimiting.Guards; using CryptoExchange.Net.RateLimiting.Interfaces; +using CryptoExchange.Net.SharedApis; namespace Binance.Net { @@ -27,6 +28,25 @@ public static class BinanceExchange "https://binance-docs.github.io/apidocs/spot/en/#change-log" }; + /// + /// Format a base and quote asset to a Binance recognized symbol + /// + /// Base asset + /// Quote asset + /// Trading mode + /// Delivery time for delivery futures + /// + public static string FormatSymbol(string baseAsset, string quoteAsset, TradingMode tradingMode, DateTime? deliverTime = null) + { + if (tradingMode == TradingMode.Spot) + return baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); + + if (tradingMode.IsLinear()) + return baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + (deliverTime == null ? string.Empty : "_" + deliverTime.Value.ToString("yyMMdd")); + + return baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + (deliverTime == null ? "_PERP" : "_" + deliverTime.Value.ToString("yyMMdd")); + } + /// /// Rate limiter configuration for the Binance API /// @@ -61,15 +81,15 @@ private void Initialize() .AddGuard(new RateLimitGuard(RateLimitGuard.PerApiKeyPerEndpoint, new PathStartFilter("sapi/"), 180000, TimeSpan.FromMinutes(1), RateLimitWindowType.Fixed)); // Uid limit of 180000 request weight per minute to /sapi endpoints SpotSocket = new RateLimitGate("Spot Socket") .AddGuard(new RateLimitGuard(RateLimitGuard.PerHost, new IGuardFilter[] { new LimitItemTypeFilter(RateLimitItemType.Connection) }, 300, TimeSpan.FromMinutes(5), RateLimitWindowType.Fixed)) // 300 connections per 5 minutes per host - .AddGuard(new RateLimitGuard(RateLimitGuard.PerEndpoint, new IGuardFilter[] { new HostFilter("wss://stream.binance.com"), new LimitItemTypeFilter(RateLimitItemType.Request) }, 4, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)) // 5 requests per second per path (connection) + .AddGuard(new RateLimitGuard(RateLimitGuard.PerConnection, new IGuardFilter[] { new HostFilter("wss://stream.binance.com"), new LimitItemTypeFilter(RateLimitItemType.Request) }, 4, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)) // 5 requests per second per path (connection) .AddGuard(new RateLimitGuard(RateLimitGuard.PerHost, new IGuardFilter[] { new HostFilter("wss://ws-api.binance.com") }, 6000, TimeSpan.FromMinutes(1), RateLimitWindowType.Fixed, connectionWeight: 2)); // 6000 request weight per minute in total FuturesRest = new RateLimitGate("Futures Rest") .AddGuard(new RateLimitGuard(RateLimitGuard.PerHost, new IGuardFilter[] { new HostFilter("https://fapi.binance.com") }, 2400, TimeSpan.FromMinutes(1), RateLimitWindowType.Fixed)) // IP limit of 2400 request weight per minute to fapi.binance.com host .AddGuard(new RateLimitGuard(RateLimitGuard.PerHost, new IGuardFilter[] { new HostFilter("https://dapi.binance.com") }, 2400, TimeSpan.FromMinutes(1), RateLimitWindowType.Fixed)); // IP limit of 2400 request weight per minute to dapi.binance.com host FuturesSocket = new RateLimitGate("Futures Socket") - .AddGuard(new RateLimitGuard(RateLimitGuard.PerEndpoint, new IGuardFilter[] { new LimitItemTypeFilter(RateLimitItemType.Request), new HostFilter("wss://dstream.binance.com") }, 10, TimeSpan.FromSeconds(1), RateLimitWindowType.Fixed)) // 10 requests per second per path (connection) - .AddGuard(new RateLimitGuard(RateLimitGuard.PerEndpoint, new IGuardFilter[] { new LimitItemTypeFilter(RateLimitItemType.Request), new HostFilter("wss://fstream.binance.com") }, 10, TimeSpan.FromSeconds(1), RateLimitWindowType.Fixed)) // 10 requests per second per path (connection) - .AddGuard(new RateLimitGuard(RateLimitGuard.PerEndpoint, new IGuardFilter[] { new HostFilter("wss://ws-fapi.binance.com") }, 2400, TimeSpan.FromMinutes(1), RateLimitWindowType.Fixed, connectionWeight: 5)); + .AddGuard(new RateLimitGuard(RateLimitGuard.PerConnection, new IGuardFilter[] { new LimitItemTypeFilter(RateLimitItemType.Request), new HostFilter("wss://dstream.binance.com") }, 10, TimeSpan.FromSeconds(1), RateLimitWindowType.Fixed)) // 10 requests per second per path (connection) + .AddGuard(new RateLimitGuard(RateLimitGuard.PerConnection, new IGuardFilter[] { new LimitItemTypeFilter(RateLimitItemType.Request), new HostFilter("wss://fstream.binance.com") }, 10, TimeSpan.FromSeconds(1), RateLimitWindowType.Fixed)) // 10 requests per second per path (connection) + .AddGuard(new RateLimitGuard(RateLimitGuard.PerHost, new IGuardFilter[] { new HostFilter("wss://ws-fapi.binance.com") }, 2400, TimeSpan.FromMinutes(1), RateLimitWindowType.Fixed, connectionWeight: 5)); EndpointLimit.RateLimitTriggered += (x) => RateLimitTriggered?.Invoke(x); SpotRestIp.RateLimitTriggered += (x) => RateLimitTriggered?.Invoke(x); diff --git a/Binance.Net/BinanceTrackerFactory.cs b/Binance.Net/BinanceTrackerFactory.cs new file mode 100644 index 000000000..5eeaa55ca --- /dev/null +++ b/Binance.Net/BinanceTrackerFactory.cs @@ -0,0 +1,102 @@ +using Binance.Net.Clients; +using Binance.Net.Interfaces; +using Binance.Net.Interfaces.Clients; +using CryptoExchange.Net.SharedApis; +using CryptoExchange.Net.Trackers.Klines; +using CryptoExchange.Net.Trackers.Trades; +using Microsoft.Extensions.DependencyInjection; + +namespace Binance.Net +{ + /// + public class BinanceTrackerFactory : IBinanceTrackerFactory + { + private readonly IServiceProvider? _serviceProvider; + + /// + /// ctor + /// + public BinanceTrackerFactory() + { + } + + /// + /// ctor + /// + /// Service provider for resolving logging and clients + public BinanceTrackerFactory(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + /// + public IKlineTracker CreateKlineTracker(SharedSymbol symbol, SharedKlineInterval interval, int? limit = null, TimeSpan? period = null) + { + var restClient = _serviceProvider?.GetRequiredService() ?? new BinanceRestClient(); + var socketClient = _serviceProvider?.GetRequiredService() ?? new BinanceSocketClient(); + + IKlineRestClient sharedRestClient; + IKlineSocketClient sharedSocketClient; + if (symbol.TradingMode == TradingMode.Spot) + { + sharedRestClient = restClient.SpotApi.SharedClient; + sharedSocketClient = socketClient.SpotApi.SharedClient; + } + else if (symbol.TradingMode.IsLinear()) + { + sharedRestClient = restClient.UsdFuturesApi.SharedClient; + sharedSocketClient = socketClient.UsdFuturesApi.SharedClient; + } + else + { + sharedRestClient = restClient.CoinFuturesApi.SharedClient; + sharedSocketClient = socketClient.CoinFuturesApi.SharedClient; + } + + return new KlineTracker( + _serviceProvider?.GetRequiredService().CreateLogger(restClient.Exchange), + sharedRestClient, + sharedSocketClient, + symbol, + interval, + limit, + period + ); + } + + /// + public ITradeTracker CreateTradeTracker(SharedSymbol symbol, int? limit = null, TimeSpan? period = null) + { + var restClient = _serviceProvider?.GetRequiredService() ?? new BinanceRestClient(); + var socketClient = _serviceProvider?.GetRequiredService() ?? new BinanceSocketClient(); + + ITradeHistoryRestClient sharedRestClient; + ITradeSocketClient sharedSocketClient; + if (symbol.TradingMode == TradingMode.Spot) + { + sharedRestClient = restClient.SpotApi.SharedClient; + sharedSocketClient = socketClient.SpotApi.SharedClient; + } + else if (symbol.TradingMode.IsLinear()) + { + sharedRestClient = restClient.UsdFuturesApi.SharedClient; + sharedSocketClient = socketClient.UsdFuturesApi.SharedClient; + } + else + { + sharedRestClient = restClient.CoinFuturesApi.SharedClient; + sharedSocketClient = socketClient.CoinFuturesApi.SharedClient; + } + + return new TradeTracker( + _serviceProvider?.GetRequiredService().CreateLogger(restClient.Exchange), + null, + sharedRestClient, + sharedSocketClient, + symbol, + limit, + period + ); + } + } +} diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs index 36b164cc7..72b37abe4 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs @@ -77,9 +77,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden /// public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode tradingMode, DateTime? deliverTime = null) - { - return baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + (deliverTime == null ? "_PERP" : "_" + deliverTime.Value.ToString("yyMMdd")); - } + => BinanceExchange.FormatSymbol(baseAsset, quoteAsset, tradingMode, deliverTime); internal Uri GetUrl(string endpoint, string api, string? version = null) { diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs index 8a562cc61..55fd40b42 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -184,7 +184,10 @@ async Task>> IRecentTradeRestClient.G if (!result) return result.AsExchangeResult>(Exchange, null, default); - return result.AsExchangeResult>(Exchange, request.Symbol.TradingMode, result.Data.Select(x => new SharedTrade(x.BaseQuantity, x.Price, x.TradeTime)).ToArray()); + return result.AsExchangeResult>(Exchange, request.Symbol.TradingMode, result.Data.Select(x => new SharedTrade(x.BaseQuantity, x.Price, x.TradeTime) + { + Side = x.BuyerIsMaker ? SharedOrderSide.Buy : SharedOrderSide.Sell + }).ToArray()); } #endregion @@ -678,10 +681,13 @@ async Task>> ITradeHistoryRestClient. FromIdToken? nextToken = null; if (result.Data.Any() && result.Data.Last().TradeTime < request.EndTime) - nextToken = new FromIdToken(result.Data.Max(x => x.Id).ToString()); + nextToken = new FromIdToken((result.Data.Max(x => x.Id) + 1).ToString()); // Return - return result.AsExchangeResult>(Exchange, request.Symbol.TradingMode, result.Data.Where(x => x.TradeTime < request.EndTime).Select(x => new SharedTrade(x.Quantity, x.Price, x.TradeTime)).ToArray(), nextToken); + return result.AsExchangeResult>(Exchange, request.Symbol.TradingMode, result.Data.Where(x => x.TradeTime < request.EndTime).Select(x => new SharedTrade(x.Quantity, x.Price, x.TradeTime) + { + Side = x.BuyerIsMaker ? SharedOrderSide.Buy : SharedOrderSide.Sell + }).ToArray(), nextToken); } #endregion diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs index 525391fef..8b69812ed 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs @@ -71,9 +71,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden /// public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode tradingMode, DateTime? deliverTime = null) - { - return baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + (deliverTime == null ? "_PERP" : "_" + deliverTime.Value.ToString("yyMMdd")); - } + => BinanceExchange.FormatSymbol(baseAsset, quoteAsset, tradingMode, deliverTime); #region methods diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs index d7754da10..468b6af0f 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs @@ -65,7 +65,7 @@ async Task> ITradeSocketClient.SubscribeToTra return new ExchangeResult(Exchange, validationError); var symbol = request.Symbol.GetSymbol(FormatSymbol); - var result = await SubscribeToAggregatedTradeUpdatesAsync(symbol, update => handler(update.AsExchangeEvent>(Exchange, new[] { new SharedTrade(update.Data.Quantity, update.Data.Price, update.Data.TradeTime) })), ct:ct).ConfigureAwait(false); + var result = await SubscribeToAggregatedTradeUpdatesAsync(symbol, update => handler(update.AsExchangeEvent>(Exchange, new[] { new SharedTrade(update.Data.Quantity, update.Data.Price, update.Data.TradeTime) { Side = update.Data.BuyerIsMaker ? SharedOrderSide.Buy : SharedOrderSide.Sell } })), ct:ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); } diff --git a/Binance.Net/Clients/GeneralApi/BinanceRestClientGeneralApi.cs b/Binance.Net/Clients/GeneralApi/BinanceRestClientGeneralApi.cs index ac5c00bd9..81eb2f040 100644 --- a/Binance.Net/Clients/GeneralApi/BinanceRestClientGeneralApi.cs +++ b/Binance.Net/Clients/GeneralApi/BinanceRestClientGeneralApi.cs @@ -75,7 +75,8 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(); /// - public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode tradingMode, DateTime? deliverTime = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); + public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode tradingMode, DateTime? deliverTime = null) + => BinanceExchange.FormatSymbol(baseAsset, quoteAsset, tradingMode, deliverTime); internal Uri GetUrl(string endpoint) => new Uri(BaseAddress.AppendPath(endpoint)); diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApi.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApi.cs index 9da3594cf..11ed3f389 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApi.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApi.cs @@ -77,7 +77,8 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(); /// - public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode tradingMode, DateTime? deliverTime) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); + public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode tradingMode, DateTime? deliverTime = null) + => BinanceExchange.FormatSymbol(baseAsset, quoteAsset, tradingMode, deliverTime); #region helpers diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index bb10e8c6c..92dfd594c 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -147,7 +147,10 @@ async Task>> IRecentTradeRestClient.G return result.AsExchangeResult>(Exchange, null, default); // Return - return result.AsExchangeResult>(Exchange, TradingMode.Spot, result.Data.Select(x => new SharedTrade(x.BaseQuantity, x.Price, x.TradeTime)).ToArray()); + return result.AsExchangeResult>(Exchange, TradingMode.Spot, result.Data.Select(x => new SharedTrade(x.BaseQuantity, x.Price, x.TradeTime) + { + Side = x.BuyerIsMaker ? SharedOrderSide.Buy : SharedOrderSide.Sell + }).ToArray()); } #endregion @@ -177,10 +180,13 @@ async Task>> ITradeHistoryRestClient. FromIdToken? nextToken = null; if (result.Data.Any() && result.Data.Last().TradeTime < request.EndTime) - nextToken = new FromIdToken(result.Data.Max(x => x.Id).ToString()); + nextToken = new FromIdToken((result.Data.Max(x => x.Id) + 1).ToString()); // Return - return result.AsExchangeResult>(Exchange, TradingMode.Spot, result.Data.Where(x => x.TradeTime < request.EndTime).Select(x => new SharedTrade(x.Quantity, x.Price, x.TradeTime)).ToArray(), nextToken); + return result.AsExchangeResult>(Exchange, TradingMode.Spot, result.Data.Where(x => x.TradeTime < request.EndTime).Select(x => new SharedTrade(x.Quantity, x.Price, x.TradeTime) + { + Side = x.BuyerIsMaker ? SharedOrderSide.Buy : SharedOrderSide.Sell + }).ToArray(), nextToken); } #endregion diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs index 77d7e18ff..dac7f2759 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs @@ -63,7 +63,8 @@ internal BinanceSocketClientSpotApi(ILogger logger, BinanceSocketOptions options public IBinanceSocketClientSpotApiShared SharedClient => this; /// - public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode tradingMode, DateTime? deliverTime = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); + public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode tradingMode, DateTime? deliverTime = null) + => BinanceExchange.FormatSymbol(baseAsset, quoteAsset, tradingMode, deliverTime); /// protected override AuthenticationProvider CreateAuthenticationProvider(ApiCredentials credentials) diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs index 4ff04b215..8f9cb25c0 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs @@ -52,7 +52,10 @@ async Task> ITradeSocketClient.SubscribeToTra return new ExchangeResult(Exchange, validationError); var symbol = request.Symbol.GetSymbol(FormatSymbol); - var result = await ExchangeData.SubscribeToTradeUpdatesAsync(symbol, update => handler(update.AsExchangeEvent>(Exchange, new[] { new SharedTrade(update.Data.Quantity, update.Data.Price, update.Data.TradeTime) })), ct).ConfigureAwait(false); + var result = await ExchangeData.SubscribeToTradeUpdatesAsync(symbol, update => handler(update.AsExchangeEvent>(Exchange, new[] { new SharedTrade(update.Data.Quantity, update.Data.Price, update.Data.TradeTime) + { + Side = update.Data.BuyerIsMaker ? SharedOrderSide.Buy : SharedOrderSide.Sell + } })), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); } diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs index d7749bb67..06bf4e999 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs @@ -51,9 +51,7 @@ internal partial class BinanceRestClientUsdFuturesApi : RestApiClient, IBinanceR /// public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode tradingMode, DateTime? deliverTime = null) - { - return baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + (deliverTime == null ? string.Empty : "_" + deliverTime.Value.ToString("yyMMdd")); - } + => BinanceExchange.FormatSymbol(baseAsset, quoteAsset, tradingMode, deliverTime); #region constructor/destructor internal BinanceRestClientUsdFuturesApi(ILogger logger, HttpClient? httpClient, BinanceRestOptions options) diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs index fb9812c22..f769ec235 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -237,7 +237,10 @@ async Task>> IRecentTradeRestClient.G if (!result) return result.AsExchangeResult>(Exchange, null, default); - return result.AsExchangeResult>(Exchange, request.Symbol.TradingMode, result.Data.Select(x => new SharedTrade(x.BaseQuantity, x.Price, x.TradeTime)).ToArray()); + return result.AsExchangeResult>(Exchange, request.Symbol.TradingMode, result.Data.Select(x => new SharedTrade(x.BaseQuantity, x.Price, x.TradeTime) + { + Side = x.BuyerIsMaker ? SharedOrderSide.Buy : SharedOrderSide.Sell + }).ToArray()); } #endregion @@ -674,10 +677,13 @@ async Task>> ITradeHistoryRestClient. FromIdToken? nextToken = null; if (result.Data.Any() && result.Data.Last().TradeTime < request.EndTime) - nextToken = new FromIdToken(result.Data.Max(x => x.Id).ToString()); + nextToken = new FromIdToken((result.Data.Max(x => x.Id) + 1).ToString()); // Return - return result.AsExchangeResult>(Exchange, request.Symbol.TradingMode, result.Data.Where(x => x.TradeTime < request.EndTime).Select(x => new SharedTrade(x.Quantity, x.Price, x.TradeTime)).ToArray(), nextToken); + return result.AsExchangeResult>(Exchange, request.Symbol.TradingMode, result.Data.Where(x => x.TradeTime < request.EndTime).Select(x => new SharedTrade(x.Quantity, x.Price, x.TradeTime) + { + Side = x.BuyerIsMaker ? SharedOrderSide.Buy : SharedOrderSide.Sell + }).ToArray(), nextToken); } #endregion diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs index 716ba7888..35cb254bc 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs @@ -75,9 +75,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden /// public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode tradingMode, DateTime? deliverTime = null) - { - return baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + (deliverTime == null ? string.Empty: "_" + deliverTime.Value.ToString("yyMMdd")); - } + => BinanceExchange.FormatSymbol(baseAsset, quoteAsset, tradingMode, deliverTime); protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(); protected override IByteMessageAccessor CreateAccessor() => new SystemTextJsonByteMessageAccessor(); diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs index ec5b5ba7b..229912925 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs @@ -66,7 +66,10 @@ async Task> ITradeSocketClient.SubscribeToTra return new ExchangeResult(Exchange, validationError); var symbol = request.Symbol.GetSymbol(FormatSymbol); - var result = await ExchangeData.SubscribeToAggregatedTradeUpdatesAsync(symbol, update => handler(update.AsExchangeEvent>(Exchange, new[] { new SharedTrade(update.Data.Quantity, update.Data.Price, update.Data.TradeTime) })), ct:ct).ConfigureAwait(false); + var result = await ExchangeData.SubscribeToAggregatedTradeUpdatesAsync(symbol, update => handler(update.AsExchangeEvent>(Exchange, new[] { new SharedTrade(update.Data.Quantity, update.Data.Price, update.Data.TradeTime) + { + Side = update.Data.BuyerIsMaker ? SharedOrderSide.Buy : SharedOrderSide.Sell + } })), ct:ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); } diff --git a/Binance.Net/ExtensionMethods/ServiceCollectionExtensions.cs b/Binance.Net/ExtensionMethods/ServiceCollectionExtensions.cs index 1bca891a7..d9d572841 100644 --- a/Binance.Net/ExtensionMethods/ServiceCollectionExtensions.cs +++ b/Binance.Net/ExtensionMethods/ServiceCollectionExtensions.cs @@ -1,4 +1,5 @@ -using Binance.Net.Clients; +using Binance.Net; +using Binance.Net.Clients; using Binance.Net.Interfaces; using Binance.Net.Interfaces.Clients; using Binance.Net.Objects.Options; @@ -43,7 +44,13 @@ public static IServiceCollection AddBinance( options.Timeout = restOptions.RequestTimeout; }).ConfigurePrimaryHttpMessageHandler(() => { var handler = new HttpClientHandler(); - handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; + try + { + handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; + } + catch (PlatformNotSupportedException) + { } + if (restOptions.Proxy != null) { handler.Proxy = new WebProxy @@ -58,6 +65,7 @@ public static IServiceCollection AddBinance( services.AddTransient(); services.AddSingleton(); services.AddTransient(); + services.AddTransient(); services.AddTransient(x => x.GetRequiredService().SpotApi.CommonSpotClient); services.AddTransient(x => x.GetRequiredService().UsdFuturesApi.CommonFuturesClient); services.AddTransient(x => x.GetRequiredService().CoinFuturesApi.CommonFuturesClient); diff --git a/Binance.Net/Interfaces/IBinanceOrderBookFactory.cs b/Binance.Net/Interfaces/IBinanceOrderBookFactory.cs index 4be81b653..91983b708 100644 --- a/Binance.Net/Interfaces/IBinanceOrderBookFactory.cs +++ b/Binance.Net/Interfaces/IBinanceOrderBookFactory.cs @@ -1,4 +1,5 @@ using Binance.Net.Objects.Options; +using CryptoExchange.Net.SharedApis; namespace Binance.Net.Interfaces { @@ -20,6 +21,14 @@ public interface IBinanceOrderBookFactory /// public IOrderBookFactory CoinFutures { get; } + /// + /// Create a SymbolOrderBook for the symbol + /// + /// The symbol + /// Book options + /// + ISymbolOrderBook Create(SharedSymbol symbol, Action? options = null); + /// /// Create a Spot SymbolOrderBook /// diff --git a/Binance.Net/Interfaces/IBinanceTrackerFactory.cs b/Binance.Net/Interfaces/IBinanceTrackerFactory.cs new file mode 100644 index 000000000..b4a761c58 --- /dev/null +++ b/Binance.Net/Interfaces/IBinanceTrackerFactory.cs @@ -0,0 +1,34 @@ +using CryptoExchange.Net.SharedApis; +using CryptoExchange.Net.Trackers.Klines; +using CryptoExchange.Net.Trackers.Trades; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Binance.Net.Interfaces +{ + /// + /// Tracker factory + /// + public interface IBinanceTrackerFactory + { + /// + /// Create a new kline tracker + /// + /// The symbol + /// Kline interval + /// The max amount of klines to retain + /// The max period the data should be retained + /// + IKlineTracker CreateKlineTracker(SharedSymbol symbol, SharedKlineInterval interval, int? limit = null, TimeSpan? period = null); + + /// + /// Create a new trade tracker for a symbol + /// + /// The symbol + /// The max amount of klines to retain + /// The max period the data should be retained + /// + ITradeTracker CreateTradeTracker(SharedSymbol symbol, int? limit = null, TimeSpan? period = null); + } +} diff --git a/Binance.Net/SymbolOrderBooks/BinanceOrderBookFactory.cs b/Binance.Net/SymbolOrderBooks/BinanceOrderBookFactory.cs index 04e65b4e8..9558f7025 100644 --- a/Binance.Net/SymbolOrderBooks/BinanceOrderBookFactory.cs +++ b/Binance.Net/SymbolOrderBooks/BinanceOrderBookFactory.cs @@ -2,6 +2,7 @@ using Binance.Net.Interfaces.Clients; using Binance.Net.Objects.Options; using CryptoExchange.Net.OrderBook; +using CryptoExchange.Net.SharedApis; using Microsoft.Extensions.DependencyInjection; namespace Binance.Net.SymbolOrderBooks @@ -21,9 +22,15 @@ public BinanceOrderBookFactory(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; - Spot = new OrderBookFactory((symbol, options) => CreateSpot(symbol, options), (baseAsset, quoteAsset, options) => CreateSpot(baseAsset + quoteAsset, options)); - UsdFutures = new OrderBookFactory((symbol, options) => CreateUsdtFutures(symbol, options), (baseAsset, quoteAsset, options) => CreateUsdtFutures(baseAsset + quoteAsset, options)); - CoinFutures = new OrderBookFactory((symbol, options) => CreateCoinFutures(symbol, options), (baseAsset, quoteAsset, options) => CreateCoinFutures(baseAsset + quoteAsset, options)); + Spot = new OrderBookFactory( + CreateSpot, + (sharedSymbol, options) => CreateSpot(BinanceExchange.FormatSymbol(sharedSymbol.BaseAsset, sharedSymbol.QuoteAsset, sharedSymbol.TradingMode, sharedSymbol.DeliverTime), options)); + UsdFutures = new OrderBookFactory( + CreateUsdtFutures, + (sharedSymbol, options) => CreateUsdtFutures(BinanceExchange.FormatSymbol(sharedSymbol.BaseAsset, sharedSymbol.QuoteAsset, sharedSymbol.TradingMode, sharedSymbol.DeliverTime), options)); + CoinFutures = new OrderBookFactory( + CreateCoinFutures, + (sharedSymbol, options) => CreateCoinFutures(BinanceExchange.FormatSymbol(sharedSymbol.BaseAsset, sharedSymbol.QuoteAsset, sharedSymbol.TradingMode, sharedSymbol.DeliverTime), options)); } /// @@ -33,6 +40,18 @@ public BinanceOrderBookFactory(IServiceProvider serviceProvider) /// public IOrderBookFactory CoinFutures { get; } + /// + public ISymbolOrderBook Create(SharedSymbol symbol, Action? options = null) + { + var symbolName = BinanceExchange.FormatSymbol(symbol.BaseAsset, symbol.QuoteAsset, symbol.TradingMode, symbol.DeliverTime); + if (symbol.TradingMode == TradingMode.Spot) + return CreateSpot(symbolName, options); + if (symbol.TradingMode.IsLinear()) + return CreateUsdtFutures(symbolName, options); + + return CreateCoinFutures(symbolName, options); + } + /// public ISymbolOrderBook CreateSpot(string symbol, Action? options = null) => new BinanceSpotSymbolOrderBook(symbol, diff --git a/Examples/Asp.NetCore.MVC/Asp.Net.csproj b/Examples/Asp.NetCore.MVC/Asp.Net.csproj index 89dc0d585..fc226fa5e 100644 --- a/Examples/Asp.NetCore.MVC/Asp.Net.csproj +++ b/Examples/Asp.NetCore.MVC/Asp.Net.csproj @@ -1,11 +1,11 @@  - netcoreapp6.0 + netcoreapp8.0 - + diff --git a/Examples/Binance.Examples.OrderBook/Binance.Examples.OrderBook.csproj b/Examples/Binance.Examples.OrderBook/Binance.Examples.OrderBook.csproj new file mode 100644 index 000000000..344e64e5b --- /dev/null +++ b/Examples/Binance.Examples.OrderBook/Binance.Examples.OrderBook.csproj @@ -0,0 +1,18 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + + + + diff --git a/Examples/Binance.Examples.OrderBook/Program.cs b/Examples/Binance.Examples.OrderBook/Program.cs new file mode 100644 index 000000000..c01014178 --- /dev/null +++ b/Examples/Binance.Examples.OrderBook/Program.cs @@ -0,0 +1,52 @@ +using Binance.Net.Interfaces; +using CryptoExchange.Net; +using CryptoExchange.Net.SharedApis; +using Microsoft.Extensions.DependencyInjection; +using Spectre.Console; + +var collection = new ServiceCollection(); +collection.AddBinance(); +var provider = collection.BuildServiceProvider(); + +var bookFactory = provider.GetRequiredService(); + +// Create and start the order book +var book = bookFactory.Create(new SharedSymbol(TradingMode.Spot, "ETH", "USDT")); +var result = await book.StartAsync(); +if (!result.Success) +{ + Console.WriteLine(result); + return; +} + +// Create Spectre table +var table = new Table(); +table.ShowRowSeparators = true; +table.AddColumn("Bid Quantity", x => { x.RightAligned(); }) + .AddColumn("Bid Price", x => { x.RightAligned(); }) + .AddColumn("Ask Price", x => { x.LeftAligned(); }) + .AddColumn("Ask Quantity", x => { x.LeftAligned(); }); + +for(var i = 0; i < 10; i++) + table.AddEmptyRow(); + +await AnsiConsole.Live(table) + .StartAsync(async ctx => + { + while (true) + { + var snapshot = book.Book; + for (var i = 0; i < 10; i++) + { + var bid = snapshot.bids.ElementAt(i); + var ask = snapshot.asks.ElementAt(i); + table.UpdateCell(i, 0, ExchangeHelpers.Normalize(bid.Quantity).ToString()); + table.UpdateCell(i, 1, ExchangeHelpers.Normalize(bid.Price).ToString()); + table.UpdateCell(i, 2, ExchangeHelpers.Normalize(ask.Price).ToString()); + table.UpdateCell(i, 3, ExchangeHelpers.Normalize(ask.Quantity).ToString()); + } + + ctx.Refresh(); + await Task.Delay(500); + } + }); diff --git a/Examples/Binance.Examples.Tracker/Binance.Examples.Tracker.csproj b/Examples/Binance.Examples.Tracker/Binance.Examples.Tracker.csproj new file mode 100644 index 000000000..344e64e5b --- /dev/null +++ b/Examples/Binance.Examples.Tracker/Binance.Examples.Tracker.csproj @@ -0,0 +1,18 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + + + + diff --git a/Examples/Binance.Examples.Tracker/Program.cs b/Examples/Binance.Examples.Tracker/Program.cs new file mode 100644 index 000000000..5a0e4c7a9 --- /dev/null +++ b/Examples/Binance.Examples.Tracker/Program.cs @@ -0,0 +1,104 @@ +using Binance.Net.Interfaces; +using CryptoExchange.Net.SharedApis; +using Microsoft.Extensions.DependencyInjection; +using Spectre.Console; +using System.Globalization; + +var collection = new ServiceCollection(); +collection.AddBinance(); +var provider = collection.BuildServiceProvider(); + +var trackerFactory = provider.GetRequiredService(); + +// Create and start the tracker, keep track of the last 10 minutes +var tracker = trackerFactory.CreateTradeTracker(new SharedSymbol(TradingMode.Spot, "ETH", "USDT"), period: TimeSpan.FromMinutes(10)); +var result = await tracker.StartAsync(); +if (!result.Success) +{ + Console.WriteLine(result); + return; +} + +// Create Spectre table +var table = new Table(); +table.ShowRowSeparators = true; +table.AddColumn("5 Min Data").AddColumn("-5 Min", x => { x.RightAligned(); }) + .AddColumn("Now", x => { x.RightAligned(); }) + .AddColumn("Dif", x => { x.RightAligned(); }); + +table.AddRow("Count", "", "", ""); +table.AddRow("Average price", "", "", ""); +table.AddRow("Average weighted price", "", "", ""); +table.AddRow("Buy/Sell Ratio", "", "", ""); +table.AddRow("Volume", "", "", ""); +table.AddRow("Value", "", "", ""); +table.AddRow("Complete", "", "", ""); +table.AddRow("", "", "", ""); +table.AddRow("Status", "", "", ""); +table.AddRow("Synced From", "", "", ""); + +// Set default culture for currency display +CultureInfo ci = new CultureInfo("en-US"); +Thread.CurrentThread.CurrentCulture = ci; +Thread.CurrentThread.CurrentUICulture = ci; + +await AnsiConsole.Live(table) + .StartAsync(async ctx => + { + while (true) + { + // Get the stats from 10 minutes until 5 minutes ago + var secondLastMinute = tracker.GetStats(DateTime.UtcNow.AddMinutes(-10), DateTime.UtcNow.AddMinutes(-5)); + + // Get the stats from 5 minutes ago until now + var lastMinute = tracker.GetStats(DateTime.UtcNow.AddMinutes(-5)); + + // Get the differences between them + var compare = secondLastMinute.CompareTo(lastMinute); + + // Update the columns + UpdateDec(0, 1, secondLastMinute.TradeCount); + UpdateDec(0, 2, lastMinute.TradeCount); + UpdateStr(0, 3, $"[{(compare.TradeCountDif.Difference < 0 ? "red" : "green")}]{compare.TradeCountDif.Difference} / {compare.TradeCountDif.PercentageDifference}%[/]"); + + UpdateStr(1, 1, secondLastMinute.AveragePrice?.ToString("C")); + UpdateStr(1, 2, lastMinute.AveragePrice?.ToString("C")); + UpdateStr(1, 3, $"[{(compare.AveragePriceDif?.Difference < 0 ? "red" : "green")}]{compare.AveragePriceDif?.Difference?.ToString("C")} / {compare.AveragePriceDif?.PercentageDifference}%[/]"); + + UpdateStr(2, 1, secondLastMinute.VolumeWeightedAveragePrice?.ToString("C")); + UpdateStr(2, 2, lastMinute.VolumeWeightedAveragePrice?.ToString("C")); + UpdateStr(2, 3, $"[{(compare.VolumeWeightedAveragePriceDif?.Difference < 0 ? "red" : "green")}]{compare.VolumeWeightedAveragePriceDif?.Difference?.ToString("C")} / {compare.VolumeWeightedAveragePriceDif?.PercentageDifference}%[/]"); + + UpdateDec(3, 1, secondLastMinute.BuySellRatio); + UpdateDec(3, 2, lastMinute.BuySellRatio); + UpdateStr(3, 3, $"[{(compare.BuySellRatioDif?.Difference < 0 ? "red" : "green")}]{compare.BuySellRatioDif?.Difference} / {compare.BuySellRatioDif?.PercentageDifference}%[/]"); + + UpdateDec(4, 1, secondLastMinute.Volume); + UpdateDec(4, 2, lastMinute.Volume); + UpdateStr(4, 3, $"[{(compare.VolumeDif.Difference < 0 ? "red" : "green")}]{compare.VolumeDif.Difference} / {compare.VolumeDif.PercentageDifference}%[/]"); + + UpdateStr(5, 1, secondLastMinute.QuoteVolume.ToString("C")); + UpdateStr(5, 2, lastMinute.QuoteVolume.ToString("C")); + UpdateStr(5, 3, $"[{(compare.QuoteVolumeDif.Difference < 0 ? "red" : "green")}]{compare.QuoteVolumeDif.Difference?.ToString("C")} / {compare.QuoteVolumeDif.PercentageDifference}%[/]"); + + UpdateStr(6, 1, secondLastMinute.Complete.ToString()); + UpdateStr(6, 2, lastMinute.Complete.ToString()); + + UpdateStr(8, 1, tracker.Status.ToString()); + UpdateStr(9, 1, tracker.SyncedFrom?.ToString()); + + ctx.Refresh(); + await Task.Delay(500); + } + }); + + +void UpdateDec(int row, int col, decimal? val) +{ + table.UpdateCell(row, col, val?.ToString() ?? string.Empty); +} + +void UpdateStr(int row, int col, string? val) +{ + table.UpdateCell(row, col, val ?? string.Empty); +} diff --git a/Examples/Blazor.ClientSide/Blazor.ClientSide.csproj b/Examples/Blazor.ClientSide/Blazor.ClientSide.csproj index 28509e0e5..58a256e1c 100644 --- a/Examples/Blazor.ClientSide/Blazor.ClientSide.csproj +++ b/Examples/Blazor.ClientSide/Blazor.ClientSide.csproj @@ -1,18 +1,18 @@  - net6.0 + net8.0 3.0 - - - - + + + + diff --git a/Examples/Blazor.ServerSide/Blazor.ServerSide.csproj b/Examples/Blazor.ServerSide/Blazor.ServerSide.csproj index f7a08bfcd..2ffa46664 100644 --- a/Examples/Blazor.ServerSide/Blazor.ServerSide.csproj +++ b/Examples/Blazor.ServerSide/Blazor.ServerSide.csproj @@ -1,14 +1,11 @@  - net6.0 + net8.0 - - - - + diff --git a/Examples/ConsoleClient/ConsoleClient.csproj b/Examples/ConsoleClient/ConsoleClient.csproj index 58586366d..695879d16 100644 --- a/Examples/ConsoleClient/ConsoleClient.csproj +++ b/Examples/ConsoleClient/ConsoleClient.csproj @@ -2,13 +2,13 @@ Exe - net6.0 + net8.0 enable enable - + diff --git a/Examples/Examples.sln b/Examples/Examples.sln index 116015162..7ff547cba 100644 --- a/Examples/Examples.sln +++ b/Examples/Examples.sln @@ -25,7 +25,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleClient", "ConsoleCli EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WebApi", "WebApi", "{39C7949D-D9DC-4E18-9B2E-4090D1565315}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Minimal WebApi", "Minimal WebApi\Minimal WebApi.csproj", "{19981783-B5E5-4A46-BC98-08ABF82EAED4}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Minimal WebApi", "Minimal WebApi\Minimal WebApi.csproj", "{19981783-B5E5-4A46-BC98-08ABF82EAED4}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Binance.Net", "..\Binance.Net\Binance.Net.csproj", "{8C2483B9-6D2F-441E-AC30-1743B31CEA6D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Binance.Examples.OrderBook", "Binance.Examples.OrderBook\Binance.Examples.OrderBook.csproj", "{A369F38D-C3D2-4B4E-8517-5FD318AE65EA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Binance.Examples.Tracker", "Binance.Examples.Tracker\Binance.Examples.Tracker.csproj", "{59561A93-D840-41DC-8A30-1428325CC562}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -61,6 +67,18 @@ Global {19981783-B5E5-4A46-BC98-08ABF82EAED4}.Debug|Any CPU.Build.0 = Debug|Any CPU {19981783-B5E5-4A46-BC98-08ABF82EAED4}.Release|Any CPU.ActiveCfg = Release|Any CPU {19981783-B5E5-4A46-BC98-08ABF82EAED4}.Release|Any CPU.Build.0 = Release|Any CPU + {8C2483B9-6D2F-441E-AC30-1743B31CEA6D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8C2483B9-6D2F-441E-AC30-1743B31CEA6D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8C2483B9-6D2F-441E-AC30-1743B31CEA6D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8C2483B9-6D2F-441E-AC30-1743B31CEA6D}.Release|Any CPU.Build.0 = Release|Any CPU + {A369F38D-C3D2-4B4E-8517-5FD318AE65EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A369F38D-C3D2-4B4E-8517-5FD318AE65EA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A369F38D-C3D2-4B4E-8517-5FD318AE65EA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A369F38D-C3D2-4B4E-8517-5FD318AE65EA}.Release|Any CPU.Build.0 = Release|Any CPU + {59561A93-D840-41DC-8A30-1428325CC562}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {59561A93-D840-41DC-8A30-1428325CC562}.Debug|Any CPU.Build.0 = Debug|Any CPU + {59561A93-D840-41DC-8A30-1428325CC562}.Release|Any CPU.ActiveCfg = Release|Any CPU + {59561A93-D840-41DC-8A30-1428325CC562}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Examples/Minimal WebApi/Minimal WebApi.csproj b/Examples/Minimal WebApi/Minimal WebApi.csproj index fff3bb70f..425256d99 100644 --- a/Examples/Minimal WebApi/Minimal WebApi.csproj +++ b/Examples/Minimal WebApi/Minimal WebApi.csproj @@ -1,15 +1,18 @@ - + - net6.0 + net8.0 enable enable Minimal_WebApi - - + + + + + diff --git a/Examples/WpfClient/WpfClient.csproj b/Examples/WpfClient/WpfClient.csproj index 901460232..3f84b073c 100644 --- a/Examples/WpfClient/WpfClient.csproj +++ b/Examples/WpfClient/WpfClient.csproj @@ -2,7 +2,7 @@ WinExe - net6.0-windows + net8.0-windows enable true @@ -12,8 +12,11 @@ - - + + + + +