Skip to content

Commit bb82a77

Browse files
authored
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
1 parent 2a9ad8d commit bb82a77

32 files changed

+548
-59
lines changed

Binance.Net/Binance.Net.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,10 @@
4848
<PrivateAssets>all</PrivateAssets>
4949
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
5050
</PackageReference>
51+
<PackageReference Include="CryptoExchange.Net" Version="8.1.0" />
5152
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0">
5253
<PrivateAssets>all</PrivateAssets>
5354
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
5455
</PackageReference>
55-
<PackageReference Include="CryptoExchange.Net" Version="8.0.3" />
5656
</ItemGroup>
5757
</Project>

Binance.Net/Binance.Net.xml

+65
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Binance.Net/BinanceExchange.cs

+24-4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using CryptoExchange.Net.RateLimiting.Filters;
33
using CryptoExchange.Net.RateLimiting.Guards;
44
using CryptoExchange.Net.RateLimiting.Interfaces;
5+
using CryptoExchange.Net.SharedApis;
56

67
namespace Binance.Net
78
{
@@ -27,6 +28,25 @@ public static class BinanceExchange
2728
"https://binance-docs.github.io/apidocs/spot/en/#change-log"
2829
};
2930

31+
/// <summary>
32+
/// Format a base and quote asset to a Binance recognized symbol
33+
/// </summary>
34+
/// <param name="baseAsset">Base asset</param>
35+
/// <param name="quoteAsset">Quote asset</param>
36+
/// <param name="tradingMode">Trading mode</param>
37+
/// <param name="deliverTime">Delivery time for delivery futures</param>
38+
/// <returns></returns>
39+
public static string FormatSymbol(string baseAsset, string quoteAsset, TradingMode tradingMode, DateTime? deliverTime = null)
40+
{
41+
if (tradingMode == TradingMode.Spot)
42+
return baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant();
43+
44+
if (tradingMode.IsLinear())
45+
return baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + (deliverTime == null ? string.Empty : "_" + deliverTime.Value.ToString("yyMMdd"));
46+
47+
return baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + (deliverTime == null ? "_PERP" : "_" + deliverTime.Value.ToString("yyMMdd"));
48+
}
49+
3050
/// <summary>
3151
/// Rate limiter configuration for the Binance API
3252
/// </summary>
@@ -61,15 +81,15 @@ private void Initialize()
6181
.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
6282
SpotSocket = new RateLimitGate("Spot Socket")
6383
.AddGuard(new RateLimitGuard(RateLimitGuard.PerHost, new IGuardFilter[] { new LimitItemTypeFilter(RateLimitItemType.Connection) }, 300, TimeSpan.FromMinutes(5), RateLimitWindowType.Fixed)) // 300 connections per 5 minutes per host
64-
.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)
84+
.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)
6585
.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
6686
FuturesRest = new RateLimitGate("Futures Rest")
6787
.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
6888
.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
6989
FuturesSocket = new RateLimitGate("Futures Socket")
70-
.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)
71-
.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)
72-
.AddGuard(new RateLimitGuard(RateLimitGuard.PerEndpoint, new IGuardFilter[] { new HostFilter("wss://ws-fapi.binance.com") }, 2400, TimeSpan.FromMinutes(1), RateLimitWindowType.Fixed, connectionWeight: 5));
90+
.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)
91+
.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)
92+
.AddGuard(new RateLimitGuard(RateLimitGuard.PerHost, new IGuardFilter[] { new HostFilter("wss://ws-fapi.binance.com") }, 2400, TimeSpan.FromMinutes(1), RateLimitWindowType.Fixed, connectionWeight: 5));
7393

7494
EndpointLimit.RateLimitTriggered += (x) => RateLimitTriggered?.Invoke(x);
7595
SpotRestIp.RateLimitTriggered += (x) => RateLimitTriggered?.Invoke(x);

Binance.Net/BinanceTrackerFactory.cs

+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
using Binance.Net.Clients;
2+
using Binance.Net.Interfaces;
3+
using Binance.Net.Interfaces.Clients;
4+
using CryptoExchange.Net.SharedApis;
5+
using CryptoExchange.Net.Trackers.Klines;
6+
using CryptoExchange.Net.Trackers.Trades;
7+
using Microsoft.Extensions.DependencyInjection;
8+
9+
namespace Binance.Net
10+
{
11+
/// <inheritdoc />
12+
public class BinanceTrackerFactory : IBinanceTrackerFactory
13+
{
14+
private readonly IServiceProvider? _serviceProvider;
15+
16+
/// <summary>
17+
/// ctor
18+
/// </summary>
19+
public BinanceTrackerFactory()
20+
{
21+
}
22+
23+
/// <summary>
24+
/// ctor
25+
/// </summary>
26+
/// <param name="serviceProvider">Service provider for resolving logging and clients</param>
27+
public BinanceTrackerFactory(IServiceProvider serviceProvider)
28+
{
29+
_serviceProvider = serviceProvider;
30+
}
31+
32+
/// <inheritdoc />
33+
public IKlineTracker CreateKlineTracker(SharedSymbol symbol, SharedKlineInterval interval, int? limit = null, TimeSpan? period = null)
34+
{
35+
var restClient = _serviceProvider?.GetRequiredService<IBinanceRestClient>() ?? new BinanceRestClient();
36+
var socketClient = _serviceProvider?.GetRequiredService<IBinanceSocketClient>() ?? new BinanceSocketClient();
37+
38+
IKlineRestClient sharedRestClient;
39+
IKlineSocketClient sharedSocketClient;
40+
if (symbol.TradingMode == TradingMode.Spot)
41+
{
42+
sharedRestClient = restClient.SpotApi.SharedClient;
43+
sharedSocketClient = socketClient.SpotApi.SharedClient;
44+
}
45+
else if (symbol.TradingMode.IsLinear())
46+
{
47+
sharedRestClient = restClient.UsdFuturesApi.SharedClient;
48+
sharedSocketClient = socketClient.UsdFuturesApi.SharedClient;
49+
}
50+
else
51+
{
52+
sharedRestClient = restClient.CoinFuturesApi.SharedClient;
53+
sharedSocketClient = socketClient.CoinFuturesApi.SharedClient;
54+
}
55+
56+
return new KlineTracker(
57+
_serviceProvider?.GetRequiredService<ILoggerFactory>().CreateLogger(restClient.Exchange),
58+
sharedRestClient,
59+
sharedSocketClient,
60+
symbol,
61+
interval,
62+
limit,
63+
period
64+
);
65+
}
66+
67+
/// <inheritdoc />
68+
public ITradeTracker CreateTradeTracker(SharedSymbol symbol, int? limit = null, TimeSpan? period = null)
69+
{
70+
var restClient = _serviceProvider?.GetRequiredService<IBinanceRestClient>() ?? new BinanceRestClient();
71+
var socketClient = _serviceProvider?.GetRequiredService<IBinanceSocketClient>() ?? new BinanceSocketClient();
72+
73+
ITradeHistoryRestClient sharedRestClient;
74+
ITradeSocketClient sharedSocketClient;
75+
if (symbol.TradingMode == TradingMode.Spot)
76+
{
77+
sharedRestClient = restClient.SpotApi.SharedClient;
78+
sharedSocketClient = socketClient.SpotApi.SharedClient;
79+
}
80+
else if (symbol.TradingMode.IsLinear())
81+
{
82+
sharedRestClient = restClient.UsdFuturesApi.SharedClient;
83+
sharedSocketClient = socketClient.UsdFuturesApi.SharedClient;
84+
}
85+
else
86+
{
87+
sharedRestClient = restClient.CoinFuturesApi.SharedClient;
88+
sharedSocketClient = socketClient.CoinFuturesApi.SharedClient;
89+
}
90+
91+
return new TradeTracker(
92+
_serviceProvider?.GetRequiredService<ILoggerFactory>().CreateLogger(restClient.Exchange),
93+
null,
94+
sharedRestClient,
95+
sharedSocketClient,
96+
symbol,
97+
limit,
98+
period
99+
);
100+
}
101+
}
102+
}

Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs

+1-3
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden
7777

7878
/// <inheritdoc />
7979
public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode tradingMode, DateTime? deliverTime = null)
80-
{
81-
return baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + (deliverTime == null ? "_PERP" : "_" + deliverTime.Value.ToString("yyMMdd"));
82-
}
80+
=> BinanceExchange.FormatSymbol(baseAsset, quoteAsset, tradingMode, deliverTime);
8381

8482
internal Uri GetUrl(string endpoint, string api, string? version = null)
8583
{

Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs

+9-3
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,10 @@ async Task<ExchangeWebResult<IEnumerable<SharedTrade>>> IRecentTradeRestClient.G
184184
if (!result)
185185
return result.AsExchangeResult<IEnumerable<SharedTrade>>(Exchange, null, default);
186186

187-
return result.AsExchangeResult<IEnumerable<SharedTrade>>(Exchange, request.Symbol.TradingMode, result.Data.Select(x => new SharedTrade(x.BaseQuantity, x.Price, x.TradeTime)).ToArray());
187+
return result.AsExchangeResult<IEnumerable<SharedTrade>>(Exchange, request.Symbol.TradingMode, result.Data.Select(x => new SharedTrade(x.BaseQuantity, x.Price, x.TradeTime)
188+
{
189+
Side = x.BuyerIsMaker ? SharedOrderSide.Buy : SharedOrderSide.Sell
190+
}).ToArray());
188191
}
189192

190193
#endregion
@@ -678,10 +681,13 @@ async Task<ExchangeWebResult<IEnumerable<SharedTrade>>> ITradeHistoryRestClient.
678681

679682
FromIdToken? nextToken = null;
680683
if (result.Data.Any() && result.Data.Last().TradeTime < request.EndTime)
681-
nextToken = new FromIdToken(result.Data.Max(x => x.Id).ToString());
684+
nextToken = new FromIdToken((result.Data.Max(x => x.Id) + 1).ToString());
682685

683686
// Return
684-
return result.AsExchangeResult<IEnumerable<SharedTrade>>(Exchange, request.Symbol.TradingMode, result.Data.Where(x => x.TradeTime < request.EndTime).Select(x => new SharedTrade(x.Quantity, x.Price, x.TradeTime)).ToArray(), nextToken);
687+
return result.AsExchangeResult<IEnumerable<SharedTrade>>(Exchange, request.Symbol.TradingMode, result.Data.Where(x => x.TradeTime < request.EndTime).Select(x => new SharedTrade(x.Quantity, x.Price, x.TradeTime)
688+
{
689+
Side = x.BuyerIsMaker ? SharedOrderSide.Buy : SharedOrderSide.Sell
690+
}).ToArray(), nextToken);
685691
}
686692
#endregion
687693

Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs

+1-3
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden
7171

7272
/// <inheritdoc />
7373
public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode tradingMode, DateTime? deliverTime = null)
74-
{
75-
return baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + (deliverTime == null ? "_PERP" : "_" + deliverTime.Value.ToString("yyMMdd"));
76-
}
74+
=> BinanceExchange.FormatSymbol(baseAsset, quoteAsset, tradingMode, deliverTime);
7775

7876
#region methods
7977

Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ async Task<ExchangeResult<UpdateSubscription>> ITradeSocketClient.SubscribeToTra
6565
return new ExchangeResult<UpdateSubscription>(Exchange, validationError);
6666

6767
var symbol = request.Symbol.GetSymbol(FormatSymbol);
68-
var result = await SubscribeToAggregatedTradeUpdatesAsync(symbol, update => handler(update.AsExchangeEvent<IEnumerable<SharedTrade>>(Exchange, new[] { new SharedTrade(update.Data.Quantity, update.Data.Price, update.Data.TradeTime) })), ct:ct).ConfigureAwait(false);
68+
var result = await SubscribeToAggregatedTradeUpdatesAsync(symbol, update => handler(update.AsExchangeEvent<IEnumerable<SharedTrade>>(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);
6969

7070
return new ExchangeResult<UpdateSubscription>(Exchange, result);
7171
}

0 commit comments

Comments
 (0)