Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trackers #19

Merged
merged 3 commits into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion BingX.Net/BingX.Net.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="CryptoExchange.Net" Version="8.1.0" />
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="CryptoExchange.Net" Version="8.0.3" />
</ItemGroup>
</Project>
65 changes: 65 additions & 0 deletions BingX.Net/BingX.Net.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions BingX.Net/BingXExchange.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using CryptoExchange.Net.RateLimiting;
using CryptoExchange.Net.RateLimiting.Guards;
using CryptoExchange.Net.RateLimiting.Interfaces;
using CryptoExchange.Net.SharedApis;
using System;
using System.Collections.Generic;

Expand Down Expand Up @@ -29,6 +30,19 @@ public static class BingXExchange
"https://bingx-api.github.io/docs"
};

/// <summary>
/// Format a base and quote asset to a BingX recognized symbol
/// </summary>
/// <param name="baseAsset">Base asset</param>
/// <param name="quoteAsset">Quote asset</param>
/// <param name="tradingMode">Trading mode</param>
/// <param name="deliverTime">Delivery time for delivery futures</param>
/// <returns></returns>
public static string FormatSymbol(string baseAsset, string quoteAsset, TradingMode tradingMode, DateTime? deliverTime = null)
{
return baseAsset.ToUpperInvariant() + "-" + quoteAsset.ToUpperInvariant();
}

/// <summary>
/// Rate limiter configuration for the BingX API
/// </summary>
Expand Down
92 changes: 92 additions & 0 deletions BingX.Net/BingXTrackerFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
using BingX.Net.Clients;
using BingX.Net.Interfaces;
using BingX.Net.Interfaces.Clients;
using CryptoExchange.Net.SharedApis;
using CryptoExchange.Net.Trackers.Klines;
using CryptoExchange.Net.Trackers.Trades;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;

namespace BingX.Net
{
/// <inheritdoc />
public class BingXTrackerFactory : IBingXTrackerFactory
{
private readonly IServiceProvider? _serviceProvider;

/// <summary>
/// ctor
/// </summary>
public BingXTrackerFactory()
{
}

/// <summary>
/// ctor
/// </summary>
/// <param name="serviceProvider">Service provider for resolving logging and clients</param>
public BingXTrackerFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}

/// <inheritdoc />
public IKlineTracker CreateKlineTracker(SharedSymbol symbol, SharedKlineInterval interval, int? limit = null, TimeSpan? period = null)
{
var restClient = _serviceProvider?.GetRequiredService<IBingXRestClient>() ?? new BingXRestClient();
var socketClient = _serviceProvider?.GetRequiredService<IBingXSocketClient>() ?? new BingXSocketClient();

IKlineRestClient sharedRestClient;
IKlineSocketClient sharedSocketClient;
if (symbol.TradingMode == TradingMode.Spot)
{
sharedRestClient = restClient.SpotApi.SharedClient;
sharedSocketClient = socketClient.SpotApi.SharedClient;
}
else
{
sharedRestClient = restClient.PerpetualFuturesApi.SharedClient;
sharedSocketClient = socketClient.PerpetualFuturesApi.SharedClient;
}

return new KlineTracker(
_serviceProvider?.GetRequiredService<ILoggerFactory>().CreateLogger(restClient.Exchange),
sharedRestClient,
sharedSocketClient,
symbol,
interval,
limit,
period
);
}

/// <inheritdoc />
public ITradeTracker CreateTradeTracker(SharedSymbol symbol, int? limit = null, TimeSpan? period = null)
{
var restClient = _serviceProvider?.GetRequiredService<IBingXRestClient>() ?? new BingXRestClient();
var socketClient = _serviceProvider?.GetRequiredService<IBingXSocketClient>() ?? new BingXSocketClient();

IRecentTradeRestClient sharedRestClient;
ITradeSocketClient sharedSocketClient;
if (symbol.TradingMode == TradingMode.Spot) {
sharedRestClient = restClient.SpotApi.SharedClient;
sharedSocketClient = socketClient.SpotApi.SharedClient;
}
else {
sharedRestClient = restClient.PerpetualFuturesApi.SharedClient;
sharedSocketClient = socketClient.PerpetualFuturesApi.SharedClient;
}

return new TradeTracker(
_serviceProvider?.GetRequiredService<ILoggerFactory>().CreateLogger(restClient.Exchange),
sharedRestClient,
null,
sharedSocketClient,
symbol,
limit,
period
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ internal BingXRestClientPerpetualFuturesApi(ILogger logger, HttpClient? httpClie
#endregion

/// <inheritdoc />
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)
=> BingXExchange.FormatSymbol(baseAsset, quoteAsset, tradingMode, deliverTime);

public IBingXRestClientPerpetualFuturesApiShared SharedClient => this;

/// <inheritdoc />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,10 @@ async Task<ExchangeWebResult<IEnumerable<SharedTrade>>> IRecentTradeRestClient.G
if (!result)
return result.AsExchangeResult<IEnumerable<SharedTrade>>(Exchange, null, default);

return result.AsExchangeResult<IEnumerable<SharedTrade>>(Exchange, request.Symbol.TradingMode, result.Data.Reverse().Select(x => new SharedTrade(x.Quantity, x.Price, x.Timestamp)).ToArray());
return result.AsExchangeResult<IEnumerable<SharedTrade>>(Exchange, request.Symbol.TradingMode, result.Data.Reverse().Select(x => new SharedTrade(x.Quantity, x.Price, x.Timestamp)
{
Side = x.BuyerIsMaker ? SharedOrderSide.Buy : SharedOrderSide.Sell
}).ToArray());
}

#endregion
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ internal BingXSocketClientPerpetualFuturesApi(ILogger logger, BingXSocketOptions
#endregion

/// <inheritdoc />
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)
=> BingXExchange.FormatSymbol(baseAsset, quoteAsset, tradingMode, deliverTime);

/// <inheritdoc />
protected override AuthenticationProvider CreateAuthenticationProvider(ApiCredentials credentials)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,42 @@ async Task<ExchangeResult<UpdateSubscription>> ITradeSocketClient.SubscribeToTra
return new ExchangeResult<UpdateSubscription>(Exchange, validationError);

var symbol = request.Symbol.GetSymbol(FormatSymbol);
var result = await SubscribeToTradeUpdatesAsync(symbol, update => handler(update.AsExchangeEvent<IEnumerable<SharedTrade>>(Exchange, update.Data.Select(x => new SharedTrade(x.Quantity, x.Price, x.TradeTime)).ToArray())), ct).ConfigureAwait(false);
var result = await SubscribeToTradeUpdatesAsync(symbol, update => handler(update.AsExchangeEvent<IEnumerable<SharedTrade>>(Exchange, update.Data.Select(x => new SharedTrade(x.Quantity, x.Price, x.TradeTime)
{
Side = x.BuyerIsMaker ? SharedOrderSide.Buy : SharedOrderSide.Sell
}).ToArray())), ct).ConfigureAwait(false);

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

#endregion

#region Kline client
SubscribeKlineOptions IKlineSocketClient.SubscribeKlineOptions { get; } = new SubscribeKlineOptions(false);
async Task<ExchangeResult<UpdateSubscription>> IKlineSocketClient.SubscribeToKlineUpdatesAsync(SubscribeKlineRequest request, Action<ExchangeEvent<SharedKline>> handler, CancellationToken ct)
{
var interval = (Enums.KlineInterval)request.Interval;
if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval))
return new ExchangeResult<UpdateSubscription>(Exchange, new ArgumentError("Interval not supported"));

var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes);
if (validationError != null)
return new ExchangeResult<UpdateSubscription>(Exchange, validationError);

var symbol = request.Symbol.GetSymbol(FormatSymbol);
var result = await SubscribeToKlineUpdatesAsync(symbol, interval, update =>
{
if (update.UpdateType == SocketUpdateType.Snapshot)
return;

foreach (var item in update.Data)
handler(update.AsExchangeEvent(Exchange, new SharedKline(item.Timestamp, item.ClosePrice, item.HighPrice, item.LowPrice, item.OpenPrice, item.Volume)));
}, ct).ConfigureAwait(false);

return new ExchangeResult<UpdateSubscription>(Exchange, result);
}
#endregion

#region Book Ticker client

EndpointOptions<SubscribeBookTickerRequest> IBookTickerSocketClient.SubscribeBookTickerOptions { get; } = new EndpointOptions<SubscribeBookTickerRequest>(false);
Expand Down
3 changes: 2 additions & 1 deletion BingX.Net/Clients/SpotApi/BingXRestClientSpotApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ internal BingXRestClientSpotApi(ILogger logger, HttpClient? httpClient, BingXRes
#endregion

/// <inheritdoc />
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)
=> BingXExchange.FormatSymbol(baseAsset, quoteAsset, tradingMode, deliverTime);

/// <inheritdoc />
protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer();
Expand Down
5 changes: 4 additions & 1 deletion BingX.Net/Clients/SpotApi/BingXRestClientSpotApiShared.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,10 @@ async Task<ExchangeWebResult<IEnumerable<SharedTrade>>> IRecentTradeRestClient.G
if (!result)
return result.AsExchangeResult<IEnumerable<SharedTrade>>(Exchange, null, default);

return result.AsExchangeResult<IEnumerable<SharedTrade>>(Exchange, request.Symbol.TradingMode, result.Data.Select(x => new SharedTrade(x.Quantity, x.Price, x.Timestamp)).ToArray());
return result.AsExchangeResult<IEnumerable<SharedTrade>>(Exchange, request.Symbol.TradingMode, result.Data.Select(x => new SharedTrade(x.Quantity, x.Price, x.Timestamp)
{
Side = x.BuyerIsMaker ? SharedOrderSide.Buy : SharedOrderSide.Sell
}).ToArray());
}

#endregion
Expand Down
3 changes: 2 additions & 1 deletion BingX.Net/Clients/SpotApi/BingXSocketClientSpotApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden
=> new BingXAuthenticationProvider(credentials);

/// <inheritdoc />
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)
=> BingXExchange.FormatSymbol(baseAsset, quoteAsset, tradingMode, deliverTime);

public IBingXSocketClientSpotApiShared SharedClient => this;

Expand Down
24 changes: 23 additions & 1 deletion BingX.Net/Clients/SpotApi/BingXSocketClientSpotApiShared.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,35 @@ async Task<ExchangeResult<UpdateSubscription>> ITradeSocketClient.SubscribeToTra
return new ExchangeResult<UpdateSubscription>(Exchange, validationError);

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

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

#endregion

#region Kline client
SubscribeKlineOptions IKlineSocketClient.SubscribeKlineOptions { get; } = new SubscribeKlineOptions(false);
async Task<ExchangeResult<UpdateSubscription>> IKlineSocketClient.SubscribeToKlineUpdatesAsync(SubscribeKlineRequest request, Action<ExchangeEvent<SharedKline>> handler, CancellationToken ct)
{
var interval = (Enums.KlineInterval)request.Interval;
if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval))
return new ExchangeResult<UpdateSubscription>(Exchange, new ArgumentError("Interval not supported"));

var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes);
if (validationError != null)
return new ExchangeResult<UpdateSubscription>(Exchange, validationError);

var symbol = request.Symbol.GetSymbol(FormatSymbol);
var result = await SubscribeToKlineUpdatesAsync(symbol, interval, update => handler(update.AsExchangeEvent(Exchange, new SharedKline(update.Data.Kline.OpenTime, update.Data.Kline.ClosePrice, update.Data.Kline.HighPrice, update.Data.Kline.LowPrice, update.Data.Kline.OpenPrice, update.Data.Kline.Volume))), ct).ConfigureAwait(false);

return new ExchangeResult<UpdateSubscription>(Exchange, result);
}
#endregion

#region Book Ticker client

EndpointOptions<SubscribeBookTickerRequest> IBookTickerSocketClient.SubscribeBookTickerOptions { get; } = new EndpointOptions<SubscribeBookTickerRequest>(false);
Expand Down
Loading
Loading