From a1df7545bf3fbe9d229fd526100c316b7810547f Mon Sep 17 00:00:00 2001 From: JKorf Date: Fri, 9 Aug 2024 15:27:47 +0200 Subject: [PATCH 01/54] wip --- Binance.Net/Binance.Net.csproj | 6 +- Binance.Net/Binance.Net.xml | 14 +-- .../BinanceRestClientCoinFuturesApi.cs | 8 +- .../BinanceRestClientCoinFuturesApiShared.cs | 94 ++++++++++++++++++ .../BinanceSocketClientCoinFuturesApi.cs | 3 +- .../GeneralApi/BinanceRestClientGeneralApi.cs | 2 +- .../SpotApi/BinanceRestClientSpotApi.cs | 6 +- .../SpotApi/BinanceRestClientSpotApiShared.cs | 93 ++++++++++++++++++ .../SpotApi/BinanceSocketClientSpotApi.cs | 2 +- .../BinanceRestClientUsdFuturesApi.cs | 11 ++- .../BinanceRestClientUsdFuturesApiShared.cs | 97 +++++++++++++++++++ .../BinanceSocketClientUsdFuturesApi.cs | 2 +- .../IBinanceRestClientCoinFuturesApi.cs | 5 +- .../IBinanceRestClientCoinFuturesApiShared.cs | 15 +++ .../SpotApi/IBinanceRestClientSpotApi.cs | 2 + .../IBinanceRestClientSpotApiShared.cs | 15 +++ .../IBinanceRestClientUsdFuturesApi.cs | 2 + .../IBinanceRestClientUsdFuturesApiShared.cs | 15 +++ 18 files changed, 370 insertions(+), 22 deletions(-) create mode 100644 Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs create mode 100644 Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs create mode 100644 Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs create mode 100644 Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs create mode 100644 Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs create mode 100644 Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs diff --git a/Binance.Net/Binance.Net.csproj b/Binance.Net/Binance.Net.csproj index ab9e8bc22..4970c614a 100644 --- a/Binance.Net/Binance.Net.csproj +++ b/Binance.Net/Binance.Net.csproj @@ -1,4 +1,4 @@ - + netstandard2.0;netstandard2.1 10.0 @@ -48,10 +48,12 @@ 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 1575af699..1e7cbce79 100644 --- a/Binance.Net/Binance.Net.xml +++ b/Binance.Net/Binance.Net.xml @@ -265,7 +265,7 @@ - + @@ -466,7 +466,7 @@ - + @@ -619,7 +619,7 @@ - + @@ -1064,7 +1064,7 @@ - + @@ -1604,7 +1604,7 @@ - + @@ -1839,7 +1839,7 @@ Event triggered when an order is canceled via this client. Note that this does not trigger when using CancelAllOrdersAsync. Only available for Spot orders - + @@ -2137,7 +2137,7 @@ - + diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs index 1335faf7c..de9b355ca 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs @@ -13,7 +13,7 @@ namespace Binance.Net.Clients.CoinFuturesApi { /// - internal class BinanceRestClientCoinFuturesApi : RestApiClient, IBinanceRestClientCoinFuturesApi, IFuturesClient + internal partial class BinanceRestClientCoinFuturesApi : RestApiClient, IBinanceRestClientCoinFuturesApi, IFuturesClient { #region fields /// @@ -75,7 +75,10 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(); /// - public override string FormatSymbol(string baseAsset, string quoteAsset) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); + public override string FormatSymbol(string baseAsset, string quoteAsset, FuturesType? futuresType = null) + { + return (baseAsset + quoteAsset).ToUpper(CultureInfo.InvariantCulture) + "_PERP"; + } internal Uri GetUrl(string endpoint, string api, string? version = null) { @@ -256,6 +259,7 @@ protected override Task> GetServerTimestampAsync() /// public IFuturesClient CommonFuturesClient => this; + public IBinanceRestClientCoinFuturesApiShared SharedClient => this; /// public string GetSymbolName(string baseAsset, string quoteAsset) => diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs new file mode 100644 index 000000000..232e50f07 --- /dev/null +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -0,0 +1,94 @@ +using Binance.Net.Interfaces.Clients.CoinFuturesApi; +using CryptoExchange.Net.SharedApis.Interfaces; +using CryptoExchange.Net.SharedApis.RequestModels; +using CryptoExchange.Net.SharedApis.ResponseModels; + +namespace Binance.Net.Clients.CoinFuturesApi +{ + internal partial class BinanceRestClientCoinFuturesApi : IBinanceRestClientCoinFuturesApiShared + { + public string Exchange => BinanceExchange.ExchangeName; + + async Task>> IKlineClient.GetKlinesAsync(KlineRequest request, CancellationToken ct) + { + var interval = (Enums.KlineInterval)request.Interval.TotalSeconds; + if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) + return new WebCallResult>(new ArgumentError("Interval not supported")); + + var result = await ExchangeData.GetKlinesAsync( + FormatSymbol(request.BaseAsset, request.QuoteAsset, request.FuturesType), + interval, + request.StartTime, + request.EndTime, + request.Limit, + ct: ct + ).ConfigureAwait(false); + if (!result) + return result.As>(default); + + return result.As(result.Data.Select(x => new SharedKline + { + BaseVolume = x.Volume, + ClosePrice = x.ClosePrice, + HighPrice = x.HighPrice, + LowPrice = x.LowPrice, + OpenPrice = x.OpenPrice, + OpenTime = x.OpenTime + })); + } + + async Task>> IFuturesSymbolClient.GetSymbolsAsync(SharedRequest request, CancellationToken ct) + { + var result = await ExchangeData.GetExchangeInfoAsync(ct).ConfigureAwait(false); + if (!result) + return result.As>(default); + + return result.As(result.Data.Symbols.Select(s => new SharedFuturesSymbol + { + BaseAsset = s.BaseAsset, + QuoteAsset = s.QuoteAsset, + Name = s.Name, + MinTradeQuantity = s.LotSizeFilter?.MinQuantity, + MaxTradeQuantity = s.LotSizeFilter?.MaxQuantity, + QuantityStep = s.LotSizeFilter?.StepSize, + PriceStep = s.PriceFilter?.TickSize, + ContractSize = 1, + DeliveryTime = s.DeliveryDate + })); + } + + async Task> ITickerClient.GetTickerAsync(TickerRequest request, CancellationToken ct) + { + var result = await ExchangeData.GetTickersAsync(symbol: FormatSymbol(request.BaseAsset, request.QuoteAsset, request.FuturesType), ct: ct).ConfigureAwait(false); + if (!result) + return result.As(default); + + var ticker = result.Data.Single(); + return result.As(new SharedTicker + { + HighPrice = ticker.HighPrice, + LastPrice = ticker.LastPrice, + LowPrice = ticker.LowPrice, + }); + } + + async Task>> ITradeClient.GetTradesAsync(TradeRequest request, CancellationToken ct) + { + var result = await ExchangeData.GetAggregatedTradeHistoryAsync( + FormatSymbol(request.BaseAsset, request.QuoteAsset, request.FuturesType), + startTime: request.StartTime, + endTime: request.EndTime, + limit: request.Limit, + ct: ct).ConfigureAwait(false); + if (!result) + return result.As>(default); + + return result.As(result.Data.Select(x => new SharedTrade + { + Price = x.Price, + Quantity = x.Quantity, + Timestamp = x.TradeTime + })); + } + } +} diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs index 89de866a9..366bfd0f3 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs @@ -68,7 +68,8 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden protected override IByteMessageAccessor CreateAccessor() => new SystemTextJsonByteMessageAccessor(); /// - public override string FormatSymbol(string baseAsset, string quoteAsset) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); + public override string FormatSymbol(string baseAsset, string quoteAsset, FuturesType? futuresType = null) + => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + "_PERP"; #region methods diff --git a/Binance.Net/Clients/GeneralApi/BinanceRestClientGeneralApi.cs b/Binance.Net/Clients/GeneralApi/BinanceRestClientGeneralApi.cs index bb8fae1a9..f9eef7b07 100644 --- a/Binance.Net/Clients/GeneralApi/BinanceRestClientGeneralApi.cs +++ b/Binance.Net/Clients/GeneralApi/BinanceRestClientGeneralApi.cs @@ -68,7 +68,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(); /// - public override string FormatSymbol(string baseAsset, string quoteAsset) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); + public override string FormatSymbol(string baseAsset, string quoteAsset, FuturesType? futuresType = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); 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 26905afba..b23fc69cc 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApi.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApi.cs @@ -14,7 +14,7 @@ namespace Binance.Net.Clients.SpotApi { /// - internal class BinanceRestClientSpotApi : RestApiClient, IBinanceRestClientSpotApi, ISpotClient + internal partial class BinanceRestClientSpotApi : RestApiClient, IBinanceRestClientSpotApi, ISpotClient { #region fields /// @@ -76,7 +76,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(); /// - public override string FormatSymbol(string baseAsset, string quoteAsset) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); + public override string FormatSymbol(string baseAsset, string quoteAsset, FuturesType? futuresType = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); #region helpers @@ -231,6 +231,8 @@ protected override Task> GetServerTimestampAsync() /// public ISpotClient CommonSpotClient => this; + public IBinanceRestClientSpotApiShared SharedClient => this; + /// public string GetSymbolName(string baseAsset, string quoteAsset) => (baseAsset + quoteAsset).ToUpper(CultureInfo.InvariantCulture); diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs new file mode 100644 index 000000000..7828c4c8d --- /dev/null +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -0,0 +1,93 @@ +using Binance.Net.Interfaces.Clients.SpotApi; +using CryptoExchange.Net.SharedApis.Interfaces; +using CryptoExchange.Net.SharedApis.RequestModels; +using CryptoExchange.Net.SharedApis.ResponseModels; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Binance.Net.Clients.SpotApi +{ + internal partial class BinanceRestClientSpotApi : IBinanceRestClientSpotApiShared + { + public string Exchange => BinanceExchange.ExchangeName; + + async Task>> IKlineClient.GetKlinesAsync(KlineRequest request, CancellationToken ct) + { + var interval = (Enums.KlineInterval)request.Interval.TotalSeconds; + if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) + return new WebCallResult>(new ArgumentError("Interval not supported")); + + var result = await ExchangeData.GetKlinesAsync( + FormatSymbol(request.BaseAsset, request.QuoteAsset, request.FuturesType), + interval, + request.StartTime, + request.EndTime, + request.Limit, + ct: ct + ).ConfigureAwait(false); + if (!result) + return result.As>(default); + + return result.As(result.Data.Select(x => new SharedKline + { + BaseVolume = x.Volume, + ClosePrice = x.ClosePrice, + HighPrice = x.HighPrice, + LowPrice = x.LowPrice, + OpenPrice = x.OpenPrice, + OpenTime = x.OpenTime + })); + } + + async Task>> ISpotSymbolClient.GetSymbolsAsync(SharedRequest request, CancellationToken ct) + { + var result = await ExchangeData.GetExchangeInfoAsync(ct).ConfigureAwait(false); + if (!result) + return result.As>(default); + + return result.As(result.Data.Symbols.Select(s => new SharedSpotSymbol + { + BaseAsset = s.BaseAsset, + QuoteAsset = s.QuoteAsset, + Name = s.Name, + MinTradeQuantity = s.LotSizeFilter?.MinQuantity, + MaxTradeQuantity = s.LotSizeFilter?.MaxQuantity, + QuantityStep = s.LotSizeFilter?.StepSize, + PriceStep = s.PriceFilter?.TickSize + })); + } + + async Task> ITickerClient.GetTickerAsync(TickerRequest request, CancellationToken ct) + { + var result = await ExchangeData.GetTickerAsync(FormatSymbol(request.BaseAsset, request.QuoteAsset, request.FuturesType), ct).ConfigureAwait(false); + if (!result) + return result.As(default); + + return result.As(new SharedTicker + { + HighPrice = result.Data.HighPrice, + LastPrice = result.Data.LastPrice, + LowPrice = result.Data.LowPrice, + }); + } + async Task>> ITradeClient.GetTradesAsync(TradeRequest request, CancellationToken ct) + { + var result = await ExchangeData.GetAggregatedTradeHistoryAsync( + FormatSymbol(request.BaseAsset, request.QuoteAsset, request.FuturesType), + startTime: request.StartTime, + endTime: request.EndTime, + limit: request.Limit, + ct: ct).ConfigureAwait(false); + if (!result) + return result.As>(default); + + return result.As(result.Data.Select(x => new SharedTrade + { + Price = x.Price, + Quantity = x.Quantity, + Timestamp = x.TradeTime + })); + } + } +} diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs index 679c57681..eb63fce2c 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs @@ -60,7 +60,7 @@ internal BinanceSocketClientSpotApi(ILogger logger, BinanceSocketOptions options #endregion /// - public override string FormatSymbol(string baseAsset, string quoteAsset) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); + public override string FormatSymbol(string baseAsset, string quoteAsset, FuturesType? futuresType = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); /// protected override AuthenticationProvider CreateAuthenticationProvider(ApiCredentials credentials) diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs index 7ffe9acb7..aea631946 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs @@ -13,7 +13,7 @@ namespace Binance.Net.Clients.UsdFuturesApi { /// - internal class BinanceRestClientUsdFuturesApi : RestApiClient, IBinanceRestClientUsdFuturesApi, IFuturesClient + internal partial class BinanceRestClientUsdFuturesApi : RestApiClient, IBinanceRestClientUsdFuturesApi, IFuturesClient { #region fields /// @@ -49,7 +49,7 @@ internal class BinanceRestClientUsdFuturesApi : RestApiClient, IBinanceRestClien public event Action? OnOrderCanceled; /// - public override string FormatSymbol(string baseAsset, string quoteAsset) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); + public override string FormatSymbol(string baseAsset, string quoteAsset, FuturesType? futuresType = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + "_PERP"; #region constructor/destructor internal BinanceRestClientUsdFuturesApi(ILogger logger, HttpClient? httpClient, BinanceRestOptions options) @@ -279,6 +279,7 @@ protected override Task> GetServerTimestampAsync() /// public IFuturesClient CommonFuturesClient => this; + public IBinanceRestClientUsdFuturesApiShared SharedClient => this; internal void InvokeOrderPlaced(OrderId id) { @@ -291,8 +292,10 @@ internal void InvokeOrderCanceled(OrderId id) } /// - public string GetSymbolName(string baseAsset, string quoteAsset) => - (baseAsset + quoteAsset).ToUpper(CultureInfo.InvariantCulture); + public string GetSymbolName(string baseAsset, string quoteAsset) + { + return (baseAsset + quoteAsset).ToUpper(CultureInfo.InvariantCulture); + } async Task> IFuturesClient.PlaceOrderAsync(string symbol, CommonOrderSide side, CommonOrderType type, decimal quantity, decimal? price, int? leverage, string? accountId, string? clientOrderId, CancellationToken ct) { diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs new file mode 100644 index 000000000..1f48dd193 --- /dev/null +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -0,0 +1,97 @@ +using Binance.Net.Interfaces.Clients.SpotApi; +using Binance.Net.Interfaces.Clients.UsdFuturesApi; +using CryptoExchange.Net.SharedApis.Interfaces; +using CryptoExchange.Net.SharedApis.RequestModels; +using CryptoExchange.Net.SharedApis.ResponseModels; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Binance.Net.Clients.UsdFuturesApi +{ + internal partial class BinanceRestClientUsdFuturesApi : IBinanceRestClientUsdFuturesApiShared + { + public string Exchange => BinanceExchange.ExchangeName; + + async Task>> IKlineClient.GetKlinesAsync(KlineRequest request, CancellationToken ct) + { + var interval = (Enums.KlineInterval)request.Interval.TotalSeconds; + if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) + return new WebCallResult>(new ArgumentError("Interval not supported")); + + var result = await ExchangeData.GetKlinesAsync( + FormatSymbol(request.BaseAsset, request.QuoteAsset, request.FuturesType), + interval, + request.StartTime, + request.EndTime, + request.Limit, + ct: ct + ).ConfigureAwait(false); + if (!result) + return result.As>(default); + + return result.As(result.Data.Select(x => new SharedKline + { + BaseVolume = x.Volume, + ClosePrice = x.ClosePrice, + HighPrice = x.HighPrice, + LowPrice = x.LowPrice, + OpenPrice = x.OpenPrice, + OpenTime = x.OpenTime + })); + } + + async Task>> IFuturesSymbolClient.GetSymbolsAsync(SharedRequest request, CancellationToken ct) + { + var result = await ExchangeData.GetExchangeInfoAsync(ct).ConfigureAwait(false); + if (!result) + return result.As>(default); + + return result.As(result.Data.Symbols.Select(s => new SharedFuturesSymbol + { + BaseAsset = s.BaseAsset, + QuoteAsset = s.QuoteAsset, + Name = s.Name, + MinTradeQuantity = s.LotSizeFilter?.MinQuantity, + MaxTradeQuantity = s.LotSizeFilter?.MaxQuantity, + QuantityStep = s.LotSizeFilter?.StepSize, + PriceStep = s.PriceFilter?.TickSize, + ContractSize = 1, + DeliveryTime = s.DeliveryDate + })); + } + + async Task> ITickerClient.GetTickerAsync(TickerRequest request, CancellationToken ct) + { + var result = await ExchangeData.GetTickerAsync(FormatSymbol(request.BaseAsset, request.QuoteAsset, request.FuturesType), ct).ConfigureAwait(false); + if (!result) + return result.As(default); + + return result.As(new SharedTicker + { + HighPrice = result.Data.HighPrice, + LastPrice = result.Data.LastPrice, + LowPrice = result.Data.LowPrice, + }); + } + + async Task>> ITradeClient.GetTradesAsync(TradeRequest request, CancellationToken ct) + { + var result = await ExchangeData.GetAggregatedTradeHistoryAsync( + FormatSymbol(request.BaseAsset, request.QuoteAsset, request.FuturesType), + startTime: request.StartTime, + endTime: request.EndTime, + limit: request.Limit, + ct: ct).ConfigureAwait(false); + if (!result) + return result.As>(default); + + return result.As(result.Data.Select(x => new SharedTrade + { + Price = x.Price, + Quantity = x.Quantity, + Timestamp = x.TradeTime + })); + } + } +} diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs index 1527e013f..3d6a2f822 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs @@ -66,7 +66,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden => new BinanceAuthenticationProvider(credentials); /// - public override string FormatSymbol(string baseAsset, string quoteAsset) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); + public override string FormatSymbol(string baseAsset, string quoteAsset, FuturesType? futuresType = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + "_PERP"; protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(); diff --git a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApi.cs b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApi.cs index 6cd97fc8b..9caf69f05 100644 --- a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApi.cs +++ b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApi.cs @@ -1,4 +1,5 @@ -using CryptoExchange.Net.Interfaces.CommonClients; +using Binance.Net.Interfaces.Clients.UsdFuturesApi; +using CryptoExchange.Net.Interfaces.CommonClients; namespace Binance.Net.Interfaces.Clients.CoinFuturesApi { @@ -27,5 +28,7 @@ public interface IBinanceRestClientCoinFuturesApi : IRestApiClient, IDisposable /// /// public IFuturesClient CommonFuturesClient { get; } + public IBinanceRestClientCoinFuturesApiShared SharedClient { get; } + } } diff --git a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs new file mode 100644 index 000000000..2851dc614 --- /dev/null +++ b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs @@ -0,0 +1,15 @@ +using CryptoExchange.Net.SharedApis.Interfaces; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Binance.Net.Interfaces.Clients.CoinFuturesApi +{ + public interface IBinanceRestClientCoinFuturesApiShared : + ITickerClient, + IFuturesSymbolClient, + IKlineClient, + ITradeClient + { + } +} diff --git a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApi.cs b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApi.cs index dc271add3..ef10cbb30 100644 --- a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApi.cs +++ b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApi.cs @@ -27,5 +27,7 @@ public interface IBinanceRestClientSpotApi : IRestApiClient, IDisposable /// /// public ISpotClient CommonSpotClient { get; } + + public IBinanceRestClientSpotApiShared SharedClient { get; } } } diff --git a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs new file mode 100644 index 000000000..de58859ac --- /dev/null +++ b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs @@ -0,0 +1,15 @@ +using CryptoExchange.Net.SharedApis.Interfaces; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Binance.Net.Interfaces.Clients.SpotApi +{ + public interface IBinanceRestClientSpotApiShared: + ITickerClient, + ISpotSymbolClient, + IKlineClient, + ITradeClient + { + } +} diff --git a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApi.cs b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApi.cs index b32f9c7c9..9ead0abb9 100644 --- a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApi.cs +++ b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApi.cs @@ -27,5 +27,7 @@ public interface IBinanceRestClientUsdFuturesApi : IRestApiClient, IDisposable /// /// public IFuturesClient CommonFuturesClient { get; } + + public IBinanceRestClientUsdFuturesApiShared SharedClient { get; } } } diff --git a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs new file mode 100644 index 000000000..25fde3a33 --- /dev/null +++ b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs @@ -0,0 +1,15 @@ +using CryptoExchange.Net.SharedApis.Interfaces; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Binance.Net.Interfaces.Clients.UsdFuturesApi +{ + public interface IBinanceRestClientUsdFuturesApiShared : + ITickerClient, + IFuturesSymbolClient, + IKlineClient, + ITradeClient + { + } +} From e43b137a1e3974bc117bfbb92ad74683416f43c3 Mon Sep 17 00:00:00 2001 From: JKorf Date: Fri, 9 Aug 2024 16:34:05 +0200 Subject: [PATCH 02/54] wip --- Binance.Net/Binance.Net.xml | 14 +++++++------- .../BinanceRestClientCoinFuturesApi.cs | 2 +- .../BinanceRestClientCoinFuturesApiShared.cs | 6 +++--- .../BinanceSocketClientCoinFuturesApi.cs | 2 +- .../GeneralApi/BinanceRestClientGeneralApi.cs | 2 +- .../Clients/SpotApi/BinanceRestClientSpotApi.cs | 2 +- .../SpotApi/BinanceRestClientSpotApiShared.cs | 6 +++--- .../Clients/SpotApi/BinanceSocketClientSpotApi.cs | 2 +- .../BinanceRestClientUsdFuturesApi.cs | 6 +++++- .../BinanceRestClientUsdFuturesApiShared.cs | 6 +++--- .../BinanceSocketClientUsdFuturesApi.cs | 2 +- 11 files changed, 27 insertions(+), 23 deletions(-) diff --git a/Binance.Net/Binance.Net.xml b/Binance.Net/Binance.Net.xml index 1e7cbce79..f7a5558bb 100644 --- a/Binance.Net/Binance.Net.xml +++ b/Binance.Net/Binance.Net.xml @@ -265,7 +265,7 @@ - + @@ -466,7 +466,7 @@ - + @@ -619,7 +619,7 @@ - + @@ -1064,7 +1064,7 @@ - + @@ -1604,7 +1604,7 @@ - + @@ -1839,7 +1839,7 @@ Event triggered when an order is canceled via this client. Note that this does not trigger when using CancelAllOrdersAsync. Only available for Spot orders - + @@ -2137,7 +2137,7 @@ - + diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs index de9b355ca..080ddfdb9 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs @@ -75,7 +75,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(); /// - public override string FormatSymbol(string baseAsset, string quoteAsset, FuturesType? futuresType = null) + public override string FormatSymbol(string baseAsset, string quoteAsset, ApiType? futuresType = null) { return (baseAsset + quoteAsset).ToUpper(CultureInfo.InvariantCulture) + "_PERP"; } diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs index 232e50f07..839c4c11d 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -16,7 +16,7 @@ async Task>> IKlineClient.GetKlinesAsync( return new WebCallResult>(new ArgumentError("Interval not supported")); var result = await ExchangeData.GetKlinesAsync( - FormatSymbol(request.BaseAsset, request.QuoteAsset, request.FuturesType), + FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), interval, request.StartTime, request.EndTime, @@ -59,7 +59,7 @@ async Task>> IFuturesSymbolClient async Task> ITickerClient.GetTickerAsync(TickerRequest request, CancellationToken ct) { - var result = await ExchangeData.GetTickersAsync(symbol: FormatSymbol(request.BaseAsset, request.QuoteAsset, request.FuturesType), ct: ct).ConfigureAwait(false); + var result = await ExchangeData.GetTickersAsync(symbol: FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), ct: ct).ConfigureAwait(false); if (!result) return result.As(default); @@ -75,7 +75,7 @@ async Task> ITickerClient.GetTickerAsync(TickerReque async Task>> ITradeClient.GetTradesAsync(TradeRequest request, CancellationToken ct) { var result = await ExchangeData.GetAggregatedTradeHistoryAsync( - FormatSymbol(request.BaseAsset, request.QuoteAsset, request.FuturesType), + FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), startTime: request.StartTime, endTime: request.EndTime, limit: request.Limit, diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs index 366bfd0f3..aeb81f51a 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs @@ -68,7 +68,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden protected override IByteMessageAccessor CreateAccessor() => new SystemTextJsonByteMessageAccessor(); /// - public override string FormatSymbol(string baseAsset, string quoteAsset, FuturesType? futuresType = null) + public override string FormatSymbol(string baseAsset, string quoteAsset, ApiType? futuresType = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + "_PERP"; #region methods diff --git a/Binance.Net/Clients/GeneralApi/BinanceRestClientGeneralApi.cs b/Binance.Net/Clients/GeneralApi/BinanceRestClientGeneralApi.cs index f9eef7b07..a7b9a23d2 100644 --- a/Binance.Net/Clients/GeneralApi/BinanceRestClientGeneralApi.cs +++ b/Binance.Net/Clients/GeneralApi/BinanceRestClientGeneralApi.cs @@ -68,7 +68,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(); /// - public override string FormatSymbol(string baseAsset, string quoteAsset, FuturesType? futuresType = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); + public override string FormatSymbol(string baseAsset, string quoteAsset, ApiType? futuresType = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); 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 b23fc69cc..b5787c33b 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApi.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApi.cs @@ -76,7 +76,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(); /// - public override string FormatSymbol(string baseAsset, string quoteAsset, FuturesType? futuresType = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); + public override string FormatSymbol(string baseAsset, string quoteAsset, ApiType? futuresType = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); #region helpers diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index 7828c4c8d..4f3331116 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -19,7 +19,7 @@ async Task>> IKlineClient.GetKlinesAsync( return new WebCallResult>(new ArgumentError("Interval not supported")); var result = await ExchangeData.GetKlinesAsync( - FormatSymbol(request.BaseAsset, request.QuoteAsset, request.FuturesType), + FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), interval, request.StartTime, request.EndTime, @@ -60,7 +60,7 @@ async Task>> ISpotSymbolClient.GetSy async Task> ITickerClient.GetTickerAsync(TickerRequest request, CancellationToken ct) { - var result = await ExchangeData.GetTickerAsync(FormatSymbol(request.BaseAsset, request.QuoteAsset, request.FuturesType), ct).ConfigureAwait(false); + var result = await ExchangeData.GetTickerAsync(FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), ct).ConfigureAwait(false); if (!result) return result.As(default); @@ -74,7 +74,7 @@ async Task> ITickerClient.GetTickerAsync(TickerReque async Task>> ITradeClient.GetTradesAsync(TradeRequest request, CancellationToken ct) { var result = await ExchangeData.GetAggregatedTradeHistoryAsync( - FormatSymbol(request.BaseAsset, request.QuoteAsset, request.FuturesType), + FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), startTime: request.StartTime, endTime: request.EndTime, limit: request.Limit, diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs index eb63fce2c..b98a70b4b 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs @@ -60,7 +60,7 @@ internal BinanceSocketClientSpotApi(ILogger logger, BinanceSocketOptions options #endregion /// - public override string FormatSymbol(string baseAsset, string quoteAsset, FuturesType? futuresType = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); + public override string FormatSymbol(string baseAsset, string quoteAsset, ApiType? futuresType = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); /// protected override AuthenticationProvider CreateAuthenticationProvider(ApiCredentials credentials) diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs index aea631946..54f67e11d 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs @@ -49,7 +49,11 @@ internal partial class BinanceRestClientUsdFuturesApi : RestApiClient, IBinanceR public event Action? OnOrderCanceled; /// - public override string FormatSymbol(string baseAsset, string quoteAsset, FuturesType? futuresType = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + "_PERP"; + public override string FormatSymbol(string baseAsset, string quoteAsset, ApiType? futuresType = null) + { + var suffix = futuresType == null ? string.Empty : "_PERP"; + return baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + suffix; + } #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 1f48dd193..8d0a40877 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -20,7 +20,7 @@ async Task>> IKlineClient.GetKlinesAsync( return new WebCallResult>(new ArgumentError("Interval not supported")); var result = await ExchangeData.GetKlinesAsync( - FormatSymbol(request.BaseAsset, request.QuoteAsset, request.FuturesType), + FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), interval, request.StartTime, request.EndTime, @@ -63,7 +63,7 @@ async Task>> IFuturesSymbolClient async Task> ITickerClient.GetTickerAsync(TickerRequest request, CancellationToken ct) { - var result = await ExchangeData.GetTickerAsync(FormatSymbol(request.BaseAsset, request.QuoteAsset, request.FuturesType), ct).ConfigureAwait(false); + var result = await ExchangeData.GetTickerAsync(FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), ct).ConfigureAwait(false); if (!result) return result.As(default); @@ -78,7 +78,7 @@ async Task> ITickerClient.GetTickerAsync(TickerReque async Task>> ITradeClient.GetTradesAsync(TradeRequest request, CancellationToken ct) { var result = await ExchangeData.GetAggregatedTradeHistoryAsync( - FormatSymbol(request.BaseAsset, request.QuoteAsset, request.FuturesType), + FormatSymbol(request.BaseAsset, request.QuoteAsset), // Don't pass api type; need only the pair startTime: request.StartTime, endTime: request.EndTime, limit: request.Limit, diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs index 3d6a2f822..9f7cec765 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs @@ -66,7 +66,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden => new BinanceAuthenticationProvider(credentials); /// - public override string FormatSymbol(string baseAsset, string quoteAsset, FuturesType? futuresType = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + "_PERP"; + public override string FormatSymbol(string baseAsset, string quoteAsset, ApiType? futuresType = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + "_PERP"; protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(); From c6d73c5f668095b766be2e5d46033309756cf036 Mon Sep 17 00:00:00 2001 From: JKorf Date: Sun, 11 Aug 2024 21:34:37 +0200 Subject: [PATCH 03/54] wip --- .../BinanceRestClientCoinFuturesApiShared.cs | 24 ++++++++-- .../SpotApi/BinanceRestClientSpotApiShared.cs | 24 ++++++++-- .../SpotApi/BinanceSocketClientSpotApi.cs | 5 ++- .../BinanceSocketClientSpotApiShared.cs | 44 +++++++++++++++++++ .../BinanceRestClientUsdFuturesApiShared.cs | 23 ++++++++-- .../IBinanceRestClientCoinFuturesApiShared.cs | 8 ++-- .../IBinanceRestClientSpotApiShared.cs | 8 ++-- .../SpotApi/IBinanceSocketClientSpotApi.cs | 6 ++- .../IBinanceSocketClientSpotApiShared.cs | 13 ++++++ .../IBinanceRestClientUsdFuturesApiShared.cs | 8 ++-- 10 files changed, 137 insertions(+), 26 deletions(-) create mode 100644 Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs create mode 100644 Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApiShared.cs diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs index 839c4c11d..9c8172ebc 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -9,7 +9,7 @@ internal partial class BinanceRestClientCoinFuturesApi : IBinanceRestClientCoinF { public string Exchange => BinanceExchange.ExchangeName; - async Task>> IKlineClient.GetKlinesAsync(KlineRequest request, CancellationToken ct) + async Task>> IKlineRestClient.GetKlinesAsync(GetKlinesRequest request, CancellationToken ct) { var interval = (Enums.KlineInterval)request.Interval.TotalSeconds; if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) @@ -37,7 +37,7 @@ async Task>> IKlineClient.GetKlinesAsync( })); } - async Task>> IFuturesSymbolClient.GetSymbolsAsync(SharedRequest request, CancellationToken ct) + async Task>> IFuturesSymbolRestClient.GetSymbolsAsync(SharedRequest request, CancellationToken ct) { var result = await ExchangeData.GetExchangeInfoAsync(ct).ConfigureAwait(false); if (!result) @@ -57,7 +57,7 @@ async Task>> IFuturesSymbolClient })); } - async Task> ITickerClient.GetTickerAsync(TickerRequest request, CancellationToken ct) + async Task> ITickerRestClient.GetTickerAsync(GetTickerRequest request, CancellationToken ct) { var result = await ExchangeData.GetTickersAsync(symbol: FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), ct: ct).ConfigureAwait(false); if (!result) @@ -66,13 +66,29 @@ async Task> ITickerClient.GetTickerAsync(TickerReque var ticker = result.Data.Single(); return result.As(new SharedTicker { + Symbol = ticker.Symbol, HighPrice = ticker.HighPrice, LastPrice = ticker.LastPrice, LowPrice = ticker.LowPrice, }); } - async Task>> ITradeClient.GetTradesAsync(TradeRequest request, CancellationToken ct) + async Task>> ITickerRestClient.GetTickersAsync(SharedRequest request, CancellationToken ct) + { + var result = await ExchangeData.GetTickersAsync(ct: ct).ConfigureAwait(false); + if (!result) + return result.As>(default); + + return result.As>(result.Data.Select( x => new SharedTicker + { + Symbol = x.Symbol, + HighPrice = x.HighPrice, + LastPrice = x.LastPrice, + LowPrice = x.LowPrice, + })); + } + + async Task>> ITradeRestClient.GetTradesAsync(GetTradesRequest request, CancellationToken ct) { var result = await ExchangeData.GetAggregatedTradeHistoryAsync( FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index 4f3331116..6688aab2e 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -12,7 +12,7 @@ internal partial class BinanceRestClientSpotApi : IBinanceRestClientSpotApiShare { public string Exchange => BinanceExchange.ExchangeName; - async Task>> IKlineClient.GetKlinesAsync(KlineRequest request, CancellationToken ct) + async Task>> IKlineRestClient.GetKlinesAsync(GetKlinesRequest request, CancellationToken ct) { var interval = (Enums.KlineInterval)request.Interval.TotalSeconds; if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) @@ -40,7 +40,7 @@ async Task>> IKlineClient.GetKlinesAsync( })); } - async Task>> ISpotSymbolClient.GetSymbolsAsync(SharedRequest request, CancellationToken ct) + async Task>> ISpotSymbolRestClient.GetSymbolsAsync(SharedRequest request, CancellationToken ct) { var result = await ExchangeData.GetExchangeInfoAsync(ct).ConfigureAwait(false); if (!result) @@ -58,7 +58,7 @@ async Task>> ISpotSymbolClient.GetSy })); } - async Task> ITickerClient.GetTickerAsync(TickerRequest request, CancellationToken ct) + async Task> ITickerRestClient.GetTickerAsync(GetTickerRequest request, CancellationToken ct) { var result = await ExchangeData.GetTickerAsync(FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), ct).ConfigureAwait(false); if (!result) @@ -71,7 +71,23 @@ async Task> ITickerClient.GetTickerAsync(TickerReque LowPrice = result.Data.LowPrice, }); } - async Task>> ITradeClient.GetTradesAsync(TradeRequest request, CancellationToken ct) + + async Task>> ITickerRestClient.GetTickersAsync(SharedRequest request, CancellationToken ct) + { + var result = await ExchangeData.GetTickersAsync(ct: ct).ConfigureAwait(false); + if (!result) + return result.As>(default); + + return result.As>(result.Data.Select(x => new SharedTicker + { + Symbol = x.Symbol, + HighPrice = x.HighPrice, + LastPrice = x.LastPrice, + LowPrice = x.LowPrice, + })); + } + + async Task>> ITradeRestClient.GetTradesAsync(GetTradesRequest request, CancellationToken ct) { var result = await ExchangeData.GetAggregatedTradeHistoryAsync( FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs index b98a70b4b..e715956e8 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs @@ -9,12 +9,13 @@ using CryptoExchange.Net.Clients; using CryptoExchange.Net.Converters.MessageParsing; using CryptoExchange.Net.Objects.Sockets; +using CryptoExchange.Net.SharedApis.Interfaces; using CryptoExchange.Net.Sockets; namespace Binance.Net.Clients.SpotApi { /// - internal class BinanceSocketClientSpotApi : SocketApiClient, IBinanceSocketClientSpotApi + internal partial class BinanceSocketClientSpotApi : SocketApiClient, IBinanceSocketClientSpotApi { #region fields /// @@ -59,6 +60,8 @@ internal BinanceSocketClientSpotApi(ILogger logger, BinanceSocketOptions options } #endregion + public IBinanceSocketClientSpotApiShared SharedClient => this; + /// public override string FormatSymbol(string baseAsset, string quoteAsset, ApiType? futuresType = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs new file mode 100644 index 000000000..6971ba515 --- /dev/null +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs @@ -0,0 +1,44 @@ +using Binance.Net.Interfaces.Clients.SpotApi; +using CryptoExchange.Net.Objects.Sockets; +using CryptoExchange.Net.SharedApis.Interfaces; +using CryptoExchange.Net.SharedApis.RequestModels; +using CryptoExchange.Net.SharedApis.ResponseModels; +using CryptoExchange.Net.SharedApis.SubscribeModels; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Binance.Net.Clients.SpotApi +{ + internal partial class BinanceSocketClientSpotApi : IBinanceSocketClientSpotApiShared + { + public string Exchange => BinanceExchange.ExchangeName; + + async Task> ITickersSocketClient.SubscribeToAllTickerUpdatesAsync(SharedRequest request, Action>> handler, CancellationToken ct) + { + var result = await ExchangeData.SubscribeToAllMiniTickerUpdatesAsync(update => handler(update.As(update.Data.Select(x => new SharedTicker + { + Symbol = x.Symbol, + HighPrice = x.HighPrice, + LastPrice = x.LastPrice, + LowPrice = x.LowPrice + }))), ct).ConfigureAwait(false); + + return result; + } + + async Task> ITickerSocketClient.SubscribeToTickerUpdatesAsync(TickerSubscribeRequest request, Action> handler, CancellationToken ct) + { + var symbol = FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType); + var result = await ExchangeData.SubscribeToMiniTickerUpdatesAsync(symbol, update => handler(update.As(new SharedTicker + { + Symbol = update.Data.Symbol, + HighPrice = update.Data.HighPrice, + LastPrice = update.Data.LastPrice, + LowPrice = update.Data.LowPrice + })), ct).ConfigureAwait(false); + + return result; + } + } +} diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs index 8d0a40877..877ae47a9 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -13,7 +13,7 @@ internal partial class BinanceRestClientUsdFuturesApi : IBinanceRestClientUsdFut { public string Exchange => BinanceExchange.ExchangeName; - async Task>> IKlineClient.GetKlinesAsync(KlineRequest request, CancellationToken ct) + async Task>> IKlineRestClient.GetKlinesAsync(GetKlinesRequest request, CancellationToken ct) { var interval = (Enums.KlineInterval)request.Interval.TotalSeconds; if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) @@ -41,7 +41,7 @@ async Task>> IKlineClient.GetKlinesAsync( })); } - async Task>> IFuturesSymbolClient.GetSymbolsAsync(SharedRequest request, CancellationToken ct) + async Task>> IFuturesSymbolRestClient.GetSymbolsAsync(SharedRequest request, CancellationToken ct) { var result = await ExchangeData.GetExchangeInfoAsync(ct).ConfigureAwait(false); if (!result) @@ -61,7 +61,7 @@ async Task>> IFuturesSymbolClient })); } - async Task> ITickerClient.GetTickerAsync(TickerRequest request, CancellationToken ct) + async Task> ITickerRestClient.GetTickerAsync(GetTickerRequest request, CancellationToken ct) { var result = await ExchangeData.GetTickerAsync(FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), ct).ConfigureAwait(false); if (!result) @@ -75,7 +75,22 @@ async Task> ITickerClient.GetTickerAsync(TickerReque }); } - async Task>> ITradeClient.GetTradesAsync(TradeRequest request, CancellationToken ct) + async Task>> ITickerRestClient.GetTickersAsync(SharedRequest request, CancellationToken ct) + { + var result = await ExchangeData.GetTickersAsync(ct: ct).ConfigureAwait(false); + if (!result) + return result.As>(default); + + return result.As>(result.Data.Select(x => new SharedTicker + { + Symbol = x.Symbol, + HighPrice = x.HighPrice, + LastPrice = x.LastPrice, + LowPrice = x.LowPrice, + })); + } + + async Task>> ITradeRestClient.GetTradesAsync(GetTradesRequest request, CancellationToken ct) { var result = await ExchangeData.GetAggregatedTradeHistoryAsync( FormatSymbol(request.BaseAsset, request.QuoteAsset), // Don't pass api type; need only the pair diff --git a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs index 2851dc614..29c483496 100644 --- a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs @@ -6,10 +6,10 @@ namespace Binance.Net.Interfaces.Clients.CoinFuturesApi { public interface IBinanceRestClientCoinFuturesApiShared : - ITickerClient, - IFuturesSymbolClient, - IKlineClient, - ITradeClient + ITickerRestClient, + IFuturesSymbolRestClient, + IKlineRestClient, + ITradeRestClient { } } diff --git a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs index de58859ac..1a8bf9b69 100644 --- a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs @@ -6,10 +6,10 @@ namespace Binance.Net.Interfaces.Clients.SpotApi { public interface IBinanceRestClientSpotApiShared: - ITickerClient, - ISpotSymbolClient, - IKlineClient, - ITradeClient + ITickerRestClient, + ISpotSymbolRestClient, + IKlineRestClient, + ITradeRestClient { } } diff --git a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApi.cs b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApi.cs index 9dfddd4d0..431bf0982 100644 --- a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApi.cs +++ b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApi.cs @@ -1,4 +1,6 @@ -namespace Binance.Net.Interfaces.Clients.SpotApi +using CryptoExchange.Net.SharedApis.Interfaces; + +namespace Binance.Net.Interfaces.Clients.SpotApi { /// /// Spot API socket subscriptions and requests @@ -17,5 +19,7 @@ public interface IBinanceSocketClientSpotApi : ISocketApiClient /// Trading data and queries /// IBinanceSocketClientSpotApiTrading Trading { get; } + + IBinanceSocketClientSpotApiShared SharedClient { get; } } } \ No newline at end of file diff --git a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApiShared.cs b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApiShared.cs new file mode 100644 index 000000000..0e83df3fa --- /dev/null +++ b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApiShared.cs @@ -0,0 +1,13 @@ +using CryptoExchange.Net.SharedApis.Interfaces; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Binance.Net.Interfaces.Clients.SpotApi +{ + public interface IBinanceSocketClientSpotApiShared : + ITickerSocketClient, + ITickersSocketClient + { + } +} diff --git a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs index 25fde3a33..873c24da0 100644 --- a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs @@ -6,10 +6,10 @@ namespace Binance.Net.Interfaces.Clients.UsdFuturesApi { public interface IBinanceRestClientUsdFuturesApiShared : - ITickerClient, - IFuturesSymbolClient, - IKlineClient, - ITradeClient + ITickerRestClient, + IFuturesSymbolRestClient, + IKlineRestClient, + ITradeRestClient { } } From 7491adad849c0eb367f300abc07b05725b44f1da Mon Sep 17 00:00:00 2001 From: JKorf Date: Mon, 12 Aug 2024 16:59:01 +0200 Subject: [PATCH 04/54] wip --- .../BinanceRestClientCoinFuturesApiShared.cs | 39 ++------- .../SpotApi/BinanceRestClientSpotApiShared.cs | 32 ++------ .../BinanceSocketClientSpotApiAccount.cs | 1 + .../BinanceSocketClientSpotApiExchangeData.cs | 2 +- .../BinanceSocketClientSpotApiShared.cs | 79 +++++++++++++++---- .../BinanceRestClientUsdFuturesApiShared.cs | 38 ++------- .../IBinanceSocketClientSpotApiShared.cs | 8 +- 7 files changed, 90 insertions(+), 109 deletions(-) diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs index 9c8172ebc..ba4b1e11c 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -1,5 +1,6 @@ using Binance.Net.Interfaces.Clients.CoinFuturesApi; using CryptoExchange.Net.SharedApis.Interfaces; +using CryptoExchange.Net.SharedApis.Models.Rest; using CryptoExchange.Net.SharedApis.RequestModels; using CryptoExchange.Net.SharedApis.ResponseModels; @@ -26,15 +27,7 @@ async Task>> IKlineRestClient.GetKlinesAs if (!result) return result.As>(default); - return result.As(result.Data.Select(x => new SharedKline - { - BaseVolume = x.Volume, - ClosePrice = x.ClosePrice, - HighPrice = x.HighPrice, - LowPrice = x.LowPrice, - OpenPrice = x.OpenPrice, - OpenTime = x.OpenTime - })); + return result.As(result.Data.Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume))); } async Task>> IFuturesSymbolRestClient.GetSymbolsAsync(SharedRequest request, CancellationToken ct) @@ -43,11 +36,8 @@ async Task>> IFuturesSymbolRestCl if (!result) return result.As>(default); - return result.As(result.Data.Symbols.Select(s => new SharedFuturesSymbol + return result.As(result.Data.Symbols.Select(s => new SharedFuturesSymbol(s.BaseAsset, s.QuoteAsset, s.Name) { - BaseAsset = s.BaseAsset, - QuoteAsset = s.QuoteAsset, - Name = s.Name, MinTradeQuantity = s.LotSizeFilter?.MinQuantity, MaxTradeQuantity = s.LotSizeFilter?.MaxQuantity, QuantityStep = s.LotSizeFilter?.StepSize, @@ -64,13 +54,7 @@ async Task> ITickerRestClient.GetTickerAsync(GetTick return result.As(default); var ticker = result.Data.Single(); - return result.As(new SharedTicker - { - Symbol = ticker.Symbol, - HighPrice = ticker.HighPrice, - LastPrice = ticker.LastPrice, - LowPrice = ticker.LowPrice, - }); + return result.As(new SharedTicker(ticker.Symbol, ticker.LastPrice, ticker.HighPrice, ticker.LowPrice)); } async Task>> ITickerRestClient.GetTickersAsync(SharedRequest request, CancellationToken ct) @@ -79,13 +63,7 @@ async Task>> ITickerRestClient.GetTicker if (!result) return result.As>(default); - return result.As>(result.Data.Select( x => new SharedTicker - { - Symbol = x.Symbol, - HighPrice = x.HighPrice, - LastPrice = x.LastPrice, - LowPrice = x.LowPrice, - })); + return result.As>(result.Data.Select( x => new SharedTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice))); } async Task>> ITradeRestClient.GetTradesAsync(GetTradesRequest request, CancellationToken ct) @@ -99,12 +77,7 @@ async Task>> ITradeRestClient.GetTradesAs if (!result) return result.As>(default); - return result.As(result.Data.Select(x => new SharedTrade - { - Price = x.Price, - Quantity = x.Quantity, - Timestamp = x.TradeTime - })); + return result.As(result.Data.Select(x => new SharedTrade(x.Quantity, x.Price, x.TradeTime))); } } } diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index 6688aab2e..72f6a8500 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -1,5 +1,6 @@ using Binance.Net.Interfaces.Clients.SpotApi; using CryptoExchange.Net.SharedApis.Interfaces; +using CryptoExchange.Net.SharedApis.Models.Rest; using CryptoExchange.Net.SharedApis.RequestModels; using CryptoExchange.Net.SharedApis.ResponseModels; using System; @@ -29,15 +30,7 @@ async Task>> IKlineRestClient.GetKlinesAs if (!result) return result.As>(default); - return result.As(result.Data.Select(x => new SharedKline - { - BaseVolume = x.Volume, - ClosePrice = x.ClosePrice, - HighPrice = x.HighPrice, - LowPrice = x.LowPrice, - OpenPrice = x.OpenPrice, - OpenTime = x.OpenTime - })); + return result.As(result.Data.Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume))); } async Task>> ISpotSymbolRestClient.GetSymbolsAsync(SharedRequest request, CancellationToken ct) @@ -46,11 +39,8 @@ async Task>> ISpotSymbolRestClient.G if (!result) return result.As>(default); - return result.As(result.Data.Symbols.Select(s => new SharedSpotSymbol + return result.As(result.Data.Symbols.Select(s => new SharedSpotSymbol(s.BaseAsset, s.QuoteAsset, s.Name) { - BaseAsset = s.BaseAsset, - QuoteAsset = s.QuoteAsset, - Name = s.Name, MinTradeQuantity = s.LotSizeFilter?.MinQuantity, MaxTradeQuantity = s.LotSizeFilter?.MaxQuantity, QuantityStep = s.LotSizeFilter?.StepSize, @@ -64,12 +54,7 @@ async Task> ITickerRestClient.GetTickerAsync(GetTick if (!result) return result.As(default); - return result.As(new SharedTicker - { - HighPrice = result.Data.HighPrice, - LastPrice = result.Data.LastPrice, - LowPrice = result.Data.LowPrice, - }); + return result.As(new SharedTicker(result.Data.Symbol, result.Data.LastPrice, result.Data.HighPrice, result.Data.LowPrice)); } async Task>> ITickerRestClient.GetTickersAsync(SharedRequest request, CancellationToken ct) @@ -78,7 +63,7 @@ async Task>> ITickerRestClient.GetTicker if (!result) return result.As>(default); - return result.As>(result.Data.Select(x => new SharedTicker + return result.As>(result.Data.Select(x => new SharedTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice) { Symbol = x.Symbol, HighPrice = x.HighPrice, @@ -98,12 +83,7 @@ async Task>> ITradeRestClient.GetTradesAs if (!result) return result.As>(default); - return result.As(result.Data.Select(x => new SharedTrade - { - Price = x.Price, - Quantity = x.Quantity, - Timestamp = x.TradeTime - })); + return result.As(result.Data.Select(x => new SharedTrade(x.Quantity, x.Price, x.TradeTime))); } } } diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiAccount.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiAccount.cs index a3f7e078a..3920aca6f 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiAccount.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiAccount.cs @@ -118,3 +118,4 @@ public async Task> SubscribeToUserDataUpdatesAsyn #endregion } } + \ No newline at end of file diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiExchangeData.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiExchangeData.cs index c432c9d7d..f93a358ed 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiExchangeData.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiExchangeData.cs @@ -239,7 +239,7 @@ public async Task> SubscribeToTradeUpdatesAsync(I return await _client.SubscribeAsync(_client.BaseAddress, symbols, handler, ct).ConfigureAwait(false); } - #endregion + #endregion #region Aggregate Trade Streams diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs index 6971ba515..b445bae71 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs @@ -1,6 +1,7 @@ using Binance.Net.Interfaces.Clients.SpotApi; using CryptoExchange.Net.Objects.Sockets; -using CryptoExchange.Net.SharedApis.Interfaces; +using CryptoExchange.Net.SharedApis.Interfaces.Socket; +using CryptoExchange.Net.SharedApis.Models.Socket; using CryptoExchange.Net.SharedApis.RequestModels; using CryptoExchange.Net.SharedApis.ResponseModels; using CryptoExchange.Net.SharedApis.SubscribeModels; @@ -16,13 +17,7 @@ internal partial class BinanceSocketClientSpotApi : IBinanceSocketClientSpotApiS async Task> ITickersSocketClient.SubscribeToAllTickerUpdatesAsync(SharedRequest request, Action>> handler, CancellationToken ct) { - var result = await ExchangeData.SubscribeToAllMiniTickerUpdatesAsync(update => handler(update.As(update.Data.Select(x => new SharedTicker - { - Symbol = x.Symbol, - HighPrice = x.HighPrice, - LastPrice = x.LastPrice, - LowPrice = x.LowPrice - }))), ct).ConfigureAwait(false); + var result = await ExchangeData.SubscribeToAllMiniTickerUpdatesAsync(update => handler(update.As(update.Data.Select(x => new SharedTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice)))), ct).ConfigureAwait(false); return result; } @@ -30,13 +25,67 @@ async Task> ITickersSocketClient.SubscribeToAllTi async Task> ITickerSocketClient.SubscribeToTickerUpdatesAsync(TickerSubscribeRequest request, Action> handler, CancellationToken ct) { var symbol = FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType); - var result = await ExchangeData.SubscribeToMiniTickerUpdatesAsync(symbol, update => handler(update.As(new SharedTicker - { - Symbol = update.Data.Symbol, - HighPrice = update.Data.HighPrice, - LastPrice = update.Data.LastPrice, - LowPrice = update.Data.LowPrice - })), ct).ConfigureAwait(false); + var result = await ExchangeData.SubscribeToMiniTickerUpdatesAsync(symbol, update => handler(update.As(new SharedTicker(update.Data.Symbol, update.Data.LastPrice, update.Data.HighPrice, update.Data.LowPrice))), ct).ConfigureAwait(false); + + return result; + } + + async Task> ITradeSocketClient.SubscribeToTradeUpdatesAsync(TradeSubscribeRequest request, Action>> handler, CancellationToken ct) + { + var symbol = FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType); + var result = await ExchangeData.SubscribeToTradeUpdatesAsync(symbol, update => handler(update.As>(new[] { new SharedTrade(update.Data.Price, update.Data.Quantity, update.Data.TradeTime) })), ct).ConfigureAwait(false); + + return result; + } + + async Task> IBookTickerSocketClient.SubscribeToBookTickerUpdatesAsync(BookTickerSubscribeRequest request, Action> handler, CancellationToken ct) + { + var symbol = FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType); + var result = await ExchangeData.SubscribeToBookTickerUpdatesAsync(symbol, update => handler(update.As(new SharedBookTicker(update.Data.BestAskPrice, update.Data.BestAskQuantity, update.Data.BestBidPrice, update.Data.BestBidQuantity))), ct).ConfigureAwait(false); + + return result; + } + + async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(SharedRequest request, Action>> handler, CancellationToken ct) + { + var listenKey = await Account.StartUserStreamAsync().ConfigureAwait(false); + if (!listenKey) + return listenKey.As(default); + + var result = await Account.SubscribeToUserDataUpdatesAsync(listenKey.Data.Result, + onAccountPositionMessage: update => handler(update.As(update.Data.Balances.Select(x => new SharedBalance(x.Asset, x.Available, x.Total)))), + ct: ct).ConfigureAwait(false); + + return result; + } + + async Task> ISpotOrderSocketClient.SubscribeToOrderUpdatesAsync(SharedRequest request, Action>> handler, CancellationToken ct) + { + var listenKey = await Account.StartUserStreamAsync().ConfigureAwait(false); + if (!listenKey) + return listenKey.As(default); + + var result = await Account.SubscribeToUserDataUpdatesAsync(listenKey.Data.Result, + onOrderUpdateMessage: update => handler(update.As>(new[] { + new SharedSpotOrder( + update.Data.Symbol, + update.Data.Id.ToString(), + update.Data.Type == Enums.SpotOrderType.Limit ? CryptoExchange.Net.SharedApis.Enums.SharedOrderType.Limit : update.Data.Type == Enums.SpotOrderType.Market ? CryptoExchange.Net.SharedApis.Enums.SharedOrderType.Market : update.Data.Type == Enums.SpotOrderType.LimitMaker ? CryptoExchange.Net.SharedApis.Enums.SharedOrderType.LimitMaker : CryptoExchange.Net.SharedApis.Enums.SharedOrderType.Other, + update.Data.Side == Enums.OrderSide.Buy ? CryptoExchange.Net.SharedApis.Enums.SharedOrderSide.Buy : CryptoExchange.Net.SharedApis.Enums.SharedOrderSide.Sell, + update.Data.Status == Enums.OrderStatus.Canceled ? CryptoExchange.Net.SharedApis.Enums.SharedOrderStatus.Canceled : (update.Data.Status == Enums.OrderStatus.New || update.Data.Status == Enums.OrderStatus.PartiallyFilled) ? CryptoExchange.Net.SharedApis.Enums.SharedOrderStatus.PartiallyFilled : CryptoExchange.Net.SharedApis.Enums.SharedOrderStatus.Filled, + update.Data.CreateTime) + { + ClientOrderId = update.Data.ClientOrderId, + Price = update.Data.Price, + Quantity = update.Data.Quantity, + QuantityFilled = update.Data.QuantityFilled, + QuoteQuantity = update.Data.QuoteQuantity, + QuoteQuantityFilled = update.Data.QuoteQuantityFilled, + UpdateTime = update.Data.UpdateTime, + TimeInForce = update.Data.TimeInForce == Enums.TimeInForce.ImmediateOrCancel ? CryptoExchange.Net.SharedApis.Enums.SharedTimeInForce.ImmediateOrCancel : update.Data.TimeInForce == Enums.TimeInForce.FillOrKill ? CryptoExchange.Net.SharedApis.Enums.SharedTimeInForce.FillOrKill : update.Data.TimeInForce == Enums.TimeInForce.GoodTillDate ? CryptoExchange.Net.SharedApis.Enums.SharedTimeInForce.GoodTillDate : CryptoExchange.Net.SharedApis.Enums.SharedTimeInForce.GoodTillCanceled + } + })), + ct: ct).ConfigureAwait(false); return result; } diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs index 877ae47a9..ebc4dc9f6 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -1,6 +1,7 @@ using Binance.Net.Interfaces.Clients.SpotApi; using Binance.Net.Interfaces.Clients.UsdFuturesApi; using CryptoExchange.Net.SharedApis.Interfaces; +using CryptoExchange.Net.SharedApis.Models.Rest; using CryptoExchange.Net.SharedApis.RequestModels; using CryptoExchange.Net.SharedApis.ResponseModels; using System; @@ -30,15 +31,7 @@ async Task>> IKlineRestClient.GetKlinesAs if (!result) return result.As>(default); - return result.As(result.Data.Select(x => new SharedKline - { - BaseVolume = x.Volume, - ClosePrice = x.ClosePrice, - HighPrice = x.HighPrice, - LowPrice = x.LowPrice, - OpenPrice = x.OpenPrice, - OpenTime = x.OpenTime - })); + return result.As(result.Data.Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume))); } async Task>> IFuturesSymbolRestClient.GetSymbolsAsync(SharedRequest request, CancellationToken ct) @@ -47,11 +40,8 @@ async Task>> IFuturesSymbolRestCl if (!result) return result.As>(default); - return result.As(result.Data.Symbols.Select(s => new SharedFuturesSymbol + return result.As(result.Data.Symbols.Select(s => new SharedFuturesSymbol(s.BaseAsset, s.QuoteAsset, s.Name) { - BaseAsset = s.BaseAsset, - QuoteAsset = s.QuoteAsset, - Name = s.Name, MinTradeQuantity = s.LotSizeFilter?.MinQuantity, MaxTradeQuantity = s.LotSizeFilter?.MaxQuantity, QuantityStep = s.LotSizeFilter?.StepSize, @@ -67,12 +57,7 @@ async Task> ITickerRestClient.GetTickerAsync(GetTick if (!result) return result.As(default); - return result.As(new SharedTicker - { - HighPrice = result.Data.HighPrice, - LastPrice = result.Data.LastPrice, - LowPrice = result.Data.LowPrice, - }); + return result.As(new SharedTicker(result.Data.Symbol, result.Data.LastPrice, result.Data.HighPrice, result.Data.LowPrice)); } async Task>> ITickerRestClient.GetTickersAsync(SharedRequest request, CancellationToken ct) @@ -81,13 +66,7 @@ async Task>> ITickerRestClient.GetTicker if (!result) return result.As>(default); - return result.As>(result.Data.Select(x => new SharedTicker - { - Symbol = x.Symbol, - HighPrice = x.HighPrice, - LastPrice = x.LastPrice, - LowPrice = x.LowPrice, - })); + return result.As>(result.Data.Select(x => new SharedTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice))); } async Task>> ITradeRestClient.GetTradesAsync(GetTradesRequest request, CancellationToken ct) @@ -101,12 +80,7 @@ async Task>> ITradeRestClient.GetTradesAs if (!result) return result.As>(default); - return result.As(result.Data.Select(x => new SharedTrade - { - Price = x.Price, - Quantity = x.Quantity, - Timestamp = x.TradeTime - })); + return result.As(result.Data.Select(x => new SharedTrade(x.Quantity, x.Price, x.TradeTime))); } } } diff --git a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApiShared.cs b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApiShared.cs index 0e83df3fa..504e86616 100644 --- a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApiShared.cs +++ b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApiShared.cs @@ -1,4 +1,4 @@ -using CryptoExchange.Net.SharedApis.Interfaces; +using CryptoExchange.Net.SharedApis.Interfaces.Socket; using System; using System.Collections.Generic; using System.Text; @@ -7,7 +7,11 @@ namespace Binance.Net.Interfaces.Clients.SpotApi { public interface IBinanceSocketClientSpotApiShared : ITickerSocketClient, - ITickersSocketClient + ITickersSocketClient, + ITradeSocketClient, + IBookTickerSocketClient, + IBalanceSocketClient, + ISpotOrderSocketClient { } } From 2802ac52a9dfe555c26fd4da2fc9cfc8476dbe53 Mon Sep 17 00:00:00 2001 From: JKorf Date: Mon, 12 Aug 2024 21:30:51 +0200 Subject: [PATCH 05/54] wip --- Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs index b445bae71..d7b191481 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs @@ -82,6 +82,8 @@ async Task> ISpotOrderSocketClient.SubscribeToOrd QuoteQuantity = update.Data.QuoteQuantity, QuoteQuantityFilled = update.Data.QuoteQuantityFilled, UpdateTime = update.Data.UpdateTime, + Fee = update.Data.Fee, + FeeAsset = update.Data.FeeAsset, TimeInForce = update.Data.TimeInForce == Enums.TimeInForce.ImmediateOrCancel ? CryptoExchange.Net.SharedApis.Enums.SharedTimeInForce.ImmediateOrCancel : update.Data.TimeInForce == Enums.TimeInForce.FillOrKill ? CryptoExchange.Net.SharedApis.Enums.SharedTimeInForce.FillOrKill : update.Data.TimeInForce == Enums.TimeInForce.GoodTillDate ? CryptoExchange.Net.SharedApis.Enums.SharedTimeInForce.GoodTillDate : CryptoExchange.Net.SharedApis.Enums.SharedTimeInForce.GoodTillCanceled } })), From 6a232bf1ce6716cb7f42e52ce009ee7058dc4a63 Mon Sep 17 00:00:00 2001 From: JKorf Date: Tue, 13 Aug 2024 16:38:08 +0200 Subject: [PATCH 06/54] wip --- .../SpotApi/BinanceRestClientSpotApiShared.cs | 9 +++++++++ .../SpotApi/BinanceSocketClientSpotApiShared.cs | 13 +++++++++---- .../SpotApi/IBinanceRestClientSpotApiShared.cs | 3 ++- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index 72f6a8500..defb813c5 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -85,5 +85,14 @@ async Task>> ITradeRestClient.GetTradesAs return result.As(result.Data.Select(x => new SharedTrade(x.Quantity, x.Price, x.TradeTime))); } + + async Task>> IBalanceRestClient.GetBalancesAsync(SharedRequest request, CancellationToken ct) + { + var result = await Account.GetBalancesAsync(ct: ct).ConfigureAwait(false); + if (!result) + return result.As>(default); + + return result.As(result.Data.Select(x => new SharedBalance(x.Asset, x.Available, x.Total))); + } } } diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs index d7b191481..ea8e1962a 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs @@ -1,5 +1,6 @@ using Binance.Net.Interfaces.Clients.SpotApi; using CryptoExchange.Net.Objects.Sockets; +using CryptoExchange.Net.SharedApis.Enums; using CryptoExchange.Net.SharedApis.Interfaces.Socket; using CryptoExchange.Net.SharedApis.Models.Socket; using CryptoExchange.Net.SharedApis.RequestModels; @@ -70,9 +71,9 @@ async Task> ISpotOrderSocketClient.SubscribeToOrd new SharedSpotOrder( update.Data.Symbol, update.Data.Id.ToString(), - update.Data.Type == Enums.SpotOrderType.Limit ? CryptoExchange.Net.SharedApis.Enums.SharedOrderType.Limit : update.Data.Type == Enums.SpotOrderType.Market ? CryptoExchange.Net.SharedApis.Enums.SharedOrderType.Market : update.Data.Type == Enums.SpotOrderType.LimitMaker ? CryptoExchange.Net.SharedApis.Enums.SharedOrderType.LimitMaker : CryptoExchange.Net.SharedApis.Enums.SharedOrderType.Other, - update.Data.Side == Enums.OrderSide.Buy ? CryptoExchange.Net.SharedApis.Enums.SharedOrderSide.Buy : CryptoExchange.Net.SharedApis.Enums.SharedOrderSide.Sell, - update.Data.Status == Enums.OrderStatus.Canceled ? CryptoExchange.Net.SharedApis.Enums.SharedOrderStatus.Canceled : (update.Data.Status == Enums.OrderStatus.New || update.Data.Status == Enums.OrderStatus.PartiallyFilled) ? CryptoExchange.Net.SharedApis.Enums.SharedOrderStatus.PartiallyFilled : CryptoExchange.Net.SharedApis.Enums.SharedOrderStatus.Filled, + update.Data.Type == Enums.SpotOrderType.Limit ? SharedOrderType.Limit : update.Data.Type == Enums.SpotOrderType.Market ? SharedOrderType.Market : update.Data.Type == Enums.SpotOrderType.LimitMaker ? SharedOrderType.LimitMaker : SharedOrderType.Other, + update.Data.Side == Enums.OrderSide.Buy ? SharedOrderSide.Buy : SharedOrderSide.Sell, + update.Data.Status == Enums.OrderStatus.Canceled ? SharedOrderStatus.Canceled : (update.Data.Status == Enums.OrderStatus.New || update.Data.Status == Enums.OrderStatus.PartiallyFilled) ? SharedOrderStatus.Open : SharedOrderStatus.Filled, update.Data.CreateTime) { ClientOrderId = update.Data.ClientOrderId, @@ -84,7 +85,11 @@ async Task> ISpotOrderSocketClient.SubscribeToOrd UpdateTime = update.Data.UpdateTime, Fee = update.Data.Fee, FeeAsset = update.Data.FeeAsset, - TimeInForce = update.Data.TimeInForce == Enums.TimeInForce.ImmediateOrCancel ? CryptoExchange.Net.SharedApis.Enums.SharedTimeInForce.ImmediateOrCancel : update.Data.TimeInForce == Enums.TimeInForce.FillOrKill ? CryptoExchange.Net.SharedApis.Enums.SharedTimeInForce.FillOrKill : update.Data.TimeInForce == Enums.TimeInForce.GoodTillDate ? CryptoExchange.Net.SharedApis.Enums.SharedTimeInForce.GoodTillDate : CryptoExchange.Net.SharedApis.Enums.SharedTimeInForce.GoodTillCanceled + TimeInForce = update.Data.TimeInForce == Enums.TimeInForce.ImmediateOrCancel ? SharedTimeInForce.ImmediateOrCancel : update.Data.TimeInForce == Enums.TimeInForce.FillOrKill ? SharedTimeInForce.FillOrKill : update.Data.TimeInForce == Enums.TimeInForce.GoodTillDate ? SharedTimeInForce.GoodTillDate : SharedTimeInForce.GoodTillCanceled, + LastTrade = update.Data.LastQuantityFilled == 0 ? null : new SharedUserTrade(update.Data.Id.ToString(), update.Data.TradeId.ToString(), update.Data.LastQuantityFilled, update.Data.LastPriceFilled, update.Data.UpdateTime) + { + Role = update.Data.BuyerIsMaker ? SharedRole.Maker : SharedRole.Taker + } } })), ct: ct).ConfigureAwait(false); diff --git a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs index 1a8bf9b69..2bdb211b9 100644 --- a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs @@ -9,7 +9,8 @@ public interface IBinanceRestClientSpotApiShared: ITickerRestClient, ISpotSymbolRestClient, IKlineRestClient, - ITradeRestClient + ITradeRestClient, + IBalanceRestClient { } } From e618f35e31f5da940a3d8314b96f44cf040f4d86 Mon Sep 17 00:00:00 2001 From: JKorf Date: Wed, 14 Aug 2024 16:59:31 +0200 Subject: [PATCH 07/54] wip --- .../SpotApi/BinanceRestClientSpotApiShared.cs | 223 +++++++++++++++++- .../IBinanceRestClientSpotApiShared.cs | 3 +- 2 files changed, 222 insertions(+), 4 deletions(-) diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index defb813c5..0e7d1404b 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -1,11 +1,10 @@ using Binance.Net.Interfaces.Clients.SpotApi; +using CryptoExchange.Net.SharedApis.Enums; using CryptoExchange.Net.SharedApis.Interfaces; using CryptoExchange.Net.SharedApis.Models.Rest; using CryptoExchange.Net.SharedApis.RequestModels; using CryptoExchange.Net.SharedApis.ResponseModels; -using System; -using System.Collections.Generic; -using System.Text; +using Binance.Net.Enums; namespace Binance.Net.Clients.SpotApi { @@ -13,6 +12,27 @@ internal partial class BinanceRestClientSpotApi : IBinanceRestClientSpotApiShare { public string Exchange => BinanceExchange.ExchangeName; + public IEnumerable SupportedOrderType { get; } = new[] + { + SharedOrderType.Limit, + SharedOrderType.Market, + SharedOrderType.LimitMaker + }; + + public IEnumerable SupportedTimeInForce { get; } = new[] + { + SharedTimeInForce.GoodTillCanceled, + SharedTimeInForce.ImmediateOrCancel, + SharedTimeInForce.FillOrKill + }; + + public SharedQuantitySupport OrderQuantitySupport { get; } = + new SharedQuantitySupport( + SharedQuantityType.BaseAssetQuantity, + SharedQuantityType.BaseAssetQuantity, + SharedQuantityType.Both, + SharedQuantityType.Both); + async Task>> IKlineRestClient.GetKlinesAsync(GetKlinesRequest request, CancellationToken ct) { var interval = (Enums.KlineInterval)request.Interval.TotalSeconds; @@ -94,5 +114,202 @@ async Task>> IBalanceRestClient.GetBala return result.As(result.Data.Select(x => new SharedBalance(x.Asset, x.Available, x.Total))); } + + async Task> ISpotOrderRestClient.PlaceOrderAsync(PlaceSpotPlaceOrderRequest request, CancellationToken ct = default) + { + if (request.OrderType == SharedOrderType.Other) + throw new ArgumentException("OrderType can't be `Other`", nameof(request.OrderType)); + + var result = await Trading.PlaceOrderAsync( + FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), + request.Side == SharedOrderSide.Buy ? Enums.OrderSide.Buy : Enums.OrderSide.Sell, + request.OrderType == SharedOrderType.Limit ? Enums.SpotOrderType.Limit : request.OrderType == SharedOrderType.Market ? Enums.SpotOrderType.Market: Enums.SpotOrderType.LimitMaker, + quantity: request.Quantity, + quoteQuantity: request.QuoteQuantity, + price: request.Price, + newClientOrderId: request.ClientOrderId).ConfigureAwait(false); + + if (!result) + return result.As(default); + + return result.As(new SharedOrderId(result.Data.Id.ToString())); + } + + async Task> ISpotOrderRestClient.GetOrderAsync(GetOrderRequest request, CancellationToken ct = default) + { + if (!long.TryParse(request.OrderId, out var orderId)) + return new WebCallResult(new ArgumentError("Invalid order id")); + + var order = await Trading.GetOrderAsync(FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), orderId).ConfigureAwait(false); + if (!order) + return order.As(default); + + return order.As(new SharedSpotOrder( + order.Data.Symbol, + order.Data.Id.ToString(), + ParseOrderType(order.Data.Type), + order.Data.Side == OrderSide.Buy ? SharedOrderSide.Buy : SharedOrderSide.Sell, + ParseOrderStatus(order.Data.Status), + order.Data.CreateTime) + { + ClientOrderId = order.Data.ClientOrderId, + AveragePrice = order.Data.AverageFillPrice, + Price = order.Data.Price, + Quantity = order.Data.Quantity, + QuantityFilled = order.Data.QuantityFilled, + QuoteQuantity = order.Data.QuoteQuantity, + QuoteQuantityFilled = order.Data.QuoteQuantityFilled, + TimeInForce = ParseTimeInForce(order.Data.TimeInForce), + UpdateTime = order.Data.UpdateTime + }); + } + + async Task>> ISpotOrderRestClient.GetOpenOrdersAsync(GetOpenOrdersRequest request, CancellationToken ct = default) + { + string? symbol = null; + if (request.BaseAsset != null && request.QuoteAsset != null) + symbol = FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType); + + var orders = await Trading.GetOpenOrdersAsync(symbol).ConfigureAwait(false); + if (!orders) + return orders.As>(default); + + return orders.As(orders.Data.Select(x => new SharedSpotOrder( + x.Symbol, + x.Id.ToString(), + ParseOrderType(x.Type), + x.Side == OrderSide.Buy ? SharedOrderSide.Buy : SharedOrderSide.Sell, + ParseOrderStatus(x.Status), + x.CreateTime) + { + ClientOrderId = x.ClientOrderId, + AveragePrice = x.AverageFillPrice, + Price = x.Price, + Quantity = x.Quantity, + QuantityFilled = x.QuantityFilled, + QuoteQuantity = x.QuoteQuantity, + QuoteQuantityFilled = x.QuoteQuantityFilled, + TimeInForce = ParseTimeInForce(x.TimeInForce), + UpdateTime = x.UpdateTime + })); + } + + async Task>> ISpotOrderRestClient.GetClosedOrdersAsync(GetClosedOrdersRequest request, CancellationToken ct = default) + { + var orders = await Trading.GetOrdersAsync(FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), + startTime: request.StartTime, + endTime: request.EndTime, + limit: request.Limit).ConfigureAwait(false); + if (!orders) + return orders.As>(default); + + return orders.As(orders.Data.Where(x => x.Status == OrderStatus.Filled || x.Status == OrderStatus.Canceled || x.Status == OrderStatus.Expired).Select(x => new SharedSpotOrder( + x.Symbol, + x.Id.ToString(), + ParseOrderType(x.Type), + x.Side == OrderSide.Buy ? SharedOrderSide.Buy : SharedOrderSide.Sell, + ParseOrderStatus(x.Status), + x.CreateTime) + { + ClientOrderId = x.ClientOrderId, + AveragePrice = x.AverageFillPrice, + Price = x.Price, + Quantity = x.Quantity, + QuantityFilled = x.QuantityFilled, + QuoteQuantity = x.QuoteQuantity, + QuoteQuantityFilled = x.QuoteQuantityFilled, + TimeInForce = ParseTimeInForce(x.TimeInForce), + UpdateTime = x.UpdateTime + })); + } + + async Task>> ISpotOrderRestClient.GetOrderTradesAsync(GetOrderTradesRequest request, CancellationToken ct = default) + { + if (!long.TryParse(request.OrderId, out var orderId)) + return new WebCallResult>(new ArgumentError("Invalid order id")); + + var orders = await Trading.GetUserTradesAsync(FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), orderId: orderId).ConfigureAwait(false); + if (!orders) + return orders.As>(default); + + return orders.As(orders.Data.Select(x => new SharedUserTrade( + x.Symbol, + x.OrderId.ToString(), + x.Id.ToString(), + x.Quantity, + x.Price, + x.Timestamp) + { + Price = x.Price, + Quantity = x.Quantity, + Fee = x.Fee, + FeeAsset = x.FeeAsset, + Role = x.IsMaker ? SharedRole.Maker : SharedRole.Taker + })); + } + + async Task>> ISpotOrderRestClient.GetUserTradesAsync(GetUserTradesRequest request, CancellationToken ct = default) + { + var orders = await Trading.GetUserTradesAsync(FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), + startTime: request.StartTime, + endTime: request.EndTime, + limit: request.Limit + ).ConfigureAwait(false); + if (!orders) + return orders.As>(default); + + return orders.As(orders.Data.Select(x => new SharedUserTrade( + x.Symbol, + x.OrderId.ToString(), + x.Id.ToString(), + x.Quantity, + x.Price, + x.Timestamp) + { + Price = x.Price, + Quantity = x.Quantity, + Fee = x.Fee, + FeeAsset = x.FeeAsset, + Role = x.IsMaker ? SharedRole.Maker : SharedRole.Taker + })); + } + + async Task> ISpotOrderRestClient.CancelOrderAsync(CancelOrderRequest request, CancellationToken ct = default) + { + if (!long.TryParse(request.OrderId, out var orderId)) + return new WebCallResult(new ArgumentError("Invalid order id")); + + var order = await Trading.CancelOrderAsync(FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), orderId).ConfigureAwait(false); + if (!order) + return order.As(default); + + return order.As(new SharedOrderId(order.Data.Id.ToString())); + } + + private SharedOrderStatus ParseOrderStatus(OrderStatus status) + { + if (status == OrderStatus.PendingNew || status == OrderStatus.New || status == OrderStatus.PartiallyFilled || status == OrderStatus.PendingCancel) return SharedOrderStatus.Open; + if (status == OrderStatus.Canceled || status == OrderStatus.Rejected || status == OrderStatus.Expired) return SharedOrderStatus.Canceled; + return SharedOrderStatus.Filled; + } + + private SharedOrderType ParseOrderType(SpotOrderType type) + { + if (type == SpotOrderType.Market) return SharedOrderType.Market; + if (type == SpotOrderType.LimitMaker) return SharedOrderType.LimitMaker; + if (type == SpotOrderType.Limit) return SharedOrderType.Limit; + + return SharedOrderType.Other; + } + + private SharedTimeInForce? ParseTimeInForce(TimeInForce tif) + { + if (tif == TimeInForce.GoodTillCanceled) return SharedTimeInForce.GoodTillCanceled; + if (tif == TimeInForce.ImmediateOrCancel) return SharedTimeInForce.ImmediateOrCancel; + if (tif == TimeInForce.FillOrKill) return SharedTimeInForce.FillOrKill; + if (tif == TimeInForce.GoodTillDate) return SharedTimeInForce.GoodTillDate; + + return null; + } } } diff --git a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs index 2bdb211b9..1eebf2e23 100644 --- a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs @@ -10,7 +10,8 @@ public interface IBinanceRestClientSpotApiShared: ISpotSymbolRestClient, IKlineRestClient, ITradeRestClient, - IBalanceRestClient + IBalanceRestClient, + ISpotOrderRestClient { } } From 9736be952d31bd0698f65da3ec66c9a13590ec77 Mon Sep 17 00:00:00 2001 From: JKorf Date: Wed, 14 Aug 2024 22:06:04 +0200 Subject: [PATCH 08/54] wip --- .../Clients/SpotApi/BinanceRestClientSpotApiShared.cs | 6 +++--- .../Clients/SpotApi/BinanceSocketClientSpotApiShared.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index 0e7d1404b..0aad36c64 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -115,7 +115,7 @@ async Task>> IBalanceRestClient.GetBala return result.As(result.Data.Select(x => new SharedBalance(x.Asset, x.Available, x.Total))); } - async Task> ISpotOrderRestClient.PlaceOrderAsync(PlaceSpotPlaceOrderRequest request, CancellationToken ct = default) + async Task> ISpotOrderRestClient.PlaceOrderAsync(PlaceSpotOrderRequest request, CancellationToken ct = default) { if (request.OrderType == SharedOrderType.Other) throw new ArgumentException("OrderType can't be `Other`", nameof(request.OrderType)); @@ -164,7 +164,7 @@ async Task> ISpotOrderRestClient.GetOrderAsync(Ge }); } - async Task>> ISpotOrderRestClient.GetOpenOrdersAsync(GetOpenOrdersRequest request, CancellationToken ct = default) + async Task>> ISpotOrderRestClient.GetOpenOrdersAsync(GetSpotOpenOrdersRequest request, CancellationToken ct = default) { string? symbol = null; if (request.BaseAsset != null && request.QuoteAsset != null) @@ -194,7 +194,7 @@ async Task>> ISpotOrderRestClient.Get })); } - async Task>> ISpotOrderRestClient.GetClosedOrdersAsync(GetClosedOrdersRequest request, CancellationToken ct = default) + async Task>> ISpotOrderRestClient.GetClosedOrdersAsync(GetSpotClosedOrdersRequest request, CancellationToken ct = default) { var orders = await Trading.GetOrdersAsync(FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), startTime: request.StartTime, diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs index ea8e1962a..63d49722b 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs @@ -86,7 +86,7 @@ async Task> ISpotOrderSocketClient.SubscribeToOrd Fee = update.Data.Fee, FeeAsset = update.Data.FeeAsset, TimeInForce = update.Data.TimeInForce == Enums.TimeInForce.ImmediateOrCancel ? SharedTimeInForce.ImmediateOrCancel : update.Data.TimeInForce == Enums.TimeInForce.FillOrKill ? SharedTimeInForce.FillOrKill : update.Data.TimeInForce == Enums.TimeInForce.GoodTillDate ? SharedTimeInForce.GoodTillDate : SharedTimeInForce.GoodTillCanceled, - LastTrade = update.Data.LastQuantityFilled == 0 ? null : new SharedUserTrade(update.Data.Id.ToString(), update.Data.TradeId.ToString(), update.Data.LastQuantityFilled, update.Data.LastPriceFilled, update.Data.UpdateTime) + LastTrade = update.Data.LastQuantityFilled == 0 ? null : new SharedUserTrade(update.Data.Symbol, update.Data.Id.ToString(), update.Data.TradeId.ToString(), update.Data.LastQuantityFilled, update.Data.LastPriceFilled, update.Data.UpdateTime) { Role = update.Data.BuyerIsMaker ? SharedRole.Maker : SharedRole.Taker } From a457a491afdd989ea4cd97848c8eca430d4f2b28 Mon Sep 17 00:00:00 2001 From: JKorf Date: Thu, 15 Aug 2024 11:48:25 +0200 Subject: [PATCH 09/54] wip --- .../BinanceRestClientCoinFuturesApiShared.cs | 49 +++++--- .../SpotApi/BinanceRestClientSpotApiShared.cs | 108 ++++++++++-------- .../BinanceSocketClientSpotApiShared.cs | 29 ++--- .../BinanceRestClientUsdFuturesApiShared.cs | 49 +++++--- 4 files changed, 140 insertions(+), 95 deletions(-) diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs index ba4b1e11c..6221d2d50 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -1,5 +1,8 @@ using Binance.Net.Interfaces.Clients.CoinFuturesApi; +using CryptoExchange.Net.SharedApis.Enums; using CryptoExchange.Net.SharedApis.Interfaces; +using CryptoExchange.Net.SharedApis.Models; +using CryptoExchange.Net.SharedApis.Models.FilterOptions; using CryptoExchange.Net.SharedApis.Models.Rest; using CryptoExchange.Net.SharedApis.RequestModels; using CryptoExchange.Net.SharedApis.ResponseModels; @@ -10,11 +13,23 @@ internal partial class BinanceRestClientCoinFuturesApi : IBinanceRestClientCoinF { public string Exchange => BinanceExchange.ExchangeName; - async Task>> IKlineRestClient.GetKlinesAsync(GetKlinesRequest request, CancellationToken ct) + //GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } + // = new GetKlinesOptions( + // true, + // false, + // SharedKlineInterval.FiveMinutes, + // SharedKlineInterval.FifteenMinutes, + // SharedKlineInterval.OneHour, + // SharedKlineInterval.FifteenMinutes, + // SharedKlineInterval.OneDay, + // SharedKlineInterval.OneWeek, + // SharedKlineInterval.OneMonth); + + async Task>> IKlineRestClient.GetKlinesAsync(GetKlinesRequest request, CancellationToken ct) { - var interval = (Enums.KlineInterval)request.Interval.TotalSeconds; + var interval = (Enums.KlineInterval)request.Interval; if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) - return new WebCallResult>(new ArgumentError("Interval not supported")); + return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); var result = await ExchangeData.GetKlinesAsync( FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), @@ -25,18 +40,18 @@ async Task>> IKlineRestClient.GetKlinesAs ct: ct ).ConfigureAwait(false); if (!result) - return result.As>(default); + return result.AsExchangeResult>(Exchange, default); - return result.As(result.Data.Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume))); + return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume))); } - async Task>> IFuturesSymbolRestClient.GetSymbolsAsync(SharedRequest request, CancellationToken ct) + async Task>> IFuturesSymbolRestClient.GetSymbolsAsync(SharedRequest request, CancellationToken ct) { var result = await ExchangeData.GetExchangeInfoAsync(ct).ConfigureAwait(false); if (!result) - return result.As>(default); + return result.AsExchangeResult>(Exchange, default); - return result.As(result.Data.Symbols.Select(s => new SharedFuturesSymbol(s.BaseAsset, s.QuoteAsset, s.Name) + return result.AsExchangeResult(Exchange, result.Data.Symbols.Select(s => new SharedFuturesSymbol(s.BaseAsset, s.QuoteAsset, s.Name) { MinTradeQuantity = s.LotSizeFilter?.MinQuantity, MaxTradeQuantity = s.LotSizeFilter?.MaxQuantity, @@ -47,26 +62,26 @@ async Task>> IFuturesSymbolRestCl })); } - async Task> ITickerRestClient.GetTickerAsync(GetTickerRequest request, CancellationToken ct) + async Task> ITickerRestClient.GetTickerAsync(GetTickerRequest request, CancellationToken ct) { var result = await ExchangeData.GetTickersAsync(symbol: FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), ct: ct).ConfigureAwait(false); if (!result) - return result.As(default); + return result.AsExchangeResult(Exchange, default); var ticker = result.Data.Single(); - return result.As(new SharedTicker(ticker.Symbol, ticker.LastPrice, ticker.HighPrice, ticker.LowPrice)); + return result.AsExchangeResult(Exchange, new SharedTicker(ticker.Symbol, ticker.LastPrice, ticker.HighPrice, ticker.LowPrice)); } - async Task>> ITickerRestClient.GetTickersAsync(SharedRequest request, CancellationToken ct) + async Task>> ITickerRestClient.GetTickersAsync(SharedRequest request, CancellationToken ct) { var result = await ExchangeData.GetTickersAsync(ct: ct).ConfigureAwait(false); if (!result) - return result.As>(default); + return result.AsExchangeResult>(Exchange, default); - return result.As>(result.Data.Select( x => new SharedTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice))); + return result.AsExchangeResult(Exchange, result.Data.Select( x => new SharedTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice))); } - async Task>> ITradeRestClient.GetTradesAsync(GetTradesRequest request, CancellationToken ct) + async Task>> ITradeRestClient.GetTradesAsync(GetTradesRequest request, CancellationToken ct) { var result = await ExchangeData.GetAggregatedTradeHistoryAsync( FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), @@ -75,9 +90,9 @@ async Task>> ITradeRestClient.GetTradesAs limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) - return result.As>(default); + return result.AsExchangeResult>(Exchange, default); - return result.As(result.Data.Select(x => new SharedTrade(x.Quantity, x.Price, x.TradeTime))); + return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedTrade(x.Quantity, x.Price, x.TradeTime))); } } } diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index 0aad36c64..7e00ae0ee 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -5,6 +5,8 @@ using CryptoExchange.Net.SharedApis.RequestModels; using CryptoExchange.Net.SharedApis.ResponseModels; using Binance.Net.Enums; +using CryptoExchange.Net.SharedApis.Models.FilterOptions; +using CryptoExchange.Net.SharedApis.Models; namespace Binance.Net.Clients.SpotApi { @@ -26,21 +28,33 @@ internal partial class BinanceRestClientSpotApi : IBinanceRestClientSpotApiShare SharedTimeInForce.FillOrKill }; - public SharedQuantitySupport OrderQuantitySupport { get; } = + public SharedQuantitySupport OrderQuantitySupport { get; } = new SharedQuantitySupport( SharedQuantityType.BaseAssetQuantity, SharedQuantityType.BaseAssetQuantity, SharedQuantityType.Both, SharedQuantityType.Both); - async Task>> IKlineRestClient.GetKlinesAsync(GetKlinesRequest request, CancellationToken ct) + //GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } + // = new GetKlinesOptions( + // true, + // false, + // SharedKlineInterval.FiveMinutes, + // SharedKlineInterval.FifteenMinutes, + // SharedKlineInterval.OneHour, + // SharedKlineInterval.FifteenMinutes, + // SharedKlineInterval.OneDay, + // SharedKlineInterval.OneWeek, + // SharedKlineInterval.OneMonth); + + async Task>> IKlineRestClient.GetKlinesAsync(GetKlinesRequest request, CancellationToken ct) { - var interval = (Enums.KlineInterval)request.Interval.TotalSeconds; + var interval = (Enums.KlineInterval)request.Interval; if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) - return new WebCallResult>(new ArgumentError("Interval not supported")); - + return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); + var result = await ExchangeData.GetKlinesAsync( - FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), + request.GetSymbol(FormatSymbol), interval, request.StartTime, request.EndTime, @@ -48,18 +62,18 @@ async Task>> IKlineRestClient.GetKlinesAs ct: ct ).ConfigureAwait(false); if (!result) - return result.As>(default); + return new ExchangeWebResult>(Exchange, result.As>(default)); - return result.As(result.Data.Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume))); + return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume))); } - async Task>> ISpotSymbolRestClient.GetSymbolsAsync(SharedRequest request, CancellationToken ct) + async Task>> ISpotSymbolRestClient.GetSymbolsAsync(SharedRequest request, CancellationToken ct) { var result = await ExchangeData.GetExchangeInfoAsync(ct).ConfigureAwait(false); if (!result) - return result.As>(default); + return result.AsExchangeResult>(Exchange, default); - return result.As(result.Data.Symbols.Select(s => new SharedSpotSymbol(s.BaseAsset, s.QuoteAsset, s.Name) + return result.AsExchangeResult(Exchange, result.Data.Symbols.Select(s => new SharedSpotSymbol(s.BaseAsset, s.QuoteAsset, s.Name) { MinTradeQuantity = s.LotSizeFilter?.MinQuantity, MaxTradeQuantity = s.LotSizeFilter?.MaxQuantity, @@ -68,22 +82,22 @@ async Task>> ISpotSymbolRestClient.G })); } - async Task> ITickerRestClient.GetTickerAsync(GetTickerRequest request, CancellationToken ct) + async Task> ITickerRestClient.GetTickerAsync(GetTickerRequest request, CancellationToken ct) { var result = await ExchangeData.GetTickerAsync(FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), ct).ConfigureAwait(false); if (!result) - return result.As(default); + return result.AsExchangeResult(Exchange, default); - return result.As(new SharedTicker(result.Data.Symbol, result.Data.LastPrice, result.Data.HighPrice, result.Data.LowPrice)); + return result.AsExchangeResult(Exchange, new SharedTicker(result.Data.Symbol, result.Data.LastPrice, result.Data.HighPrice, result.Data.LowPrice)); } - async Task>> ITickerRestClient.GetTickersAsync(SharedRequest request, CancellationToken ct) + async Task>> ITickerRestClient.GetTickersAsync(SharedRequest request, CancellationToken ct) { var result = await ExchangeData.GetTickersAsync(ct: ct).ConfigureAwait(false); if (!result) - return result.As>(default); + return result.AsExchangeResult>(Exchange, default); - return result.As>(result.Data.Select(x => new SharedTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice) + return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice) { Symbol = x.Symbol, HighPrice = x.HighPrice, @@ -92,7 +106,7 @@ async Task>> ITickerRestClient.GetTicker })); } - async Task>> ITradeRestClient.GetTradesAsync(GetTradesRequest request, CancellationToken ct) + async Task>> ITradeRestClient.GetTradesAsync(GetTradesRequest request, CancellationToken ct) { var result = await ExchangeData.GetAggregatedTradeHistoryAsync( FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), @@ -101,21 +115,21 @@ async Task>> ITradeRestClient.GetTradesAs limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) - return result.As>(default); + return result.AsExchangeResult>(Exchange, default); - return result.As(result.Data.Select(x => new SharedTrade(x.Quantity, x.Price, x.TradeTime))); + return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedTrade(x.Quantity, x.Price, x.TradeTime))); } - async Task>> IBalanceRestClient.GetBalancesAsync(SharedRequest request, CancellationToken ct) + async Task>> IBalanceRestClient.GetBalancesAsync(SharedRequest request, CancellationToken ct) { var result = await Account.GetBalancesAsync(ct: ct).ConfigureAwait(false); if (!result) - return result.As>(default); + return result.AsExchangeResult>(Exchange, default); - return result.As(result.Data.Select(x => new SharedBalance(x.Asset, x.Available, x.Total))); + return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedBalance(x.Asset, x.Available, x.Total))); } - async Task> ISpotOrderRestClient.PlaceOrderAsync(PlaceSpotOrderRequest request, CancellationToken ct = default) + async Task> ISpotOrderRestClient.PlaceOrderAsync(PlaceSpotOrderRequest request, CancellationToken ct = default) { if (request.OrderType == SharedOrderType.Other) throw new ArgumentException("OrderType can't be `Other`", nameof(request.OrderType)); @@ -130,21 +144,21 @@ async Task> ISpotOrderRestClient.PlaceOrderAsync(Pl newClientOrderId: request.ClientOrderId).ConfigureAwait(false); if (!result) - return result.As(default); + return result.AsExchangeResult(Exchange, default); - return result.As(new SharedOrderId(result.Data.Id.ToString())); + return result.AsExchangeResult(Exchange, new SharedOrderId(result.Data.Id.ToString())); } - async Task> ISpotOrderRestClient.GetOrderAsync(GetOrderRequest request, CancellationToken ct = default) + async Task> ISpotOrderRestClient.GetOrderAsync(GetOrderRequest request, CancellationToken ct = default) { if (!long.TryParse(request.OrderId, out var orderId)) - return new WebCallResult(new ArgumentError("Invalid order id")); + return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); var order = await Trading.GetOrderAsync(FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), orderId).ConfigureAwait(false); if (!order) - return order.As(default); + return order.AsExchangeResult(Exchange, default); - return order.As(new SharedSpotOrder( + return order.AsExchangeResult(Exchange, new SharedSpotOrder( order.Data.Symbol, order.Data.Id.ToString(), ParseOrderType(order.Data.Type), @@ -164,7 +178,7 @@ async Task> ISpotOrderRestClient.GetOrderAsync(Ge }); } - async Task>> ISpotOrderRestClient.GetOpenOrdersAsync(GetSpotOpenOrdersRequest request, CancellationToken ct = default) + async Task>> ISpotOrderRestClient.GetOpenOrdersAsync(GetSpotOpenOrdersRequest request, CancellationToken ct = default) { string? symbol = null; if (request.BaseAsset != null && request.QuoteAsset != null) @@ -172,9 +186,9 @@ async Task>> ISpotOrderRestClient.Get var orders = await Trading.GetOpenOrdersAsync(symbol).ConfigureAwait(false); if (!orders) - return orders.As>(default); + return orders.AsExchangeResult>(Exchange, default); - return orders.As(orders.Data.Select(x => new SharedSpotOrder( + return orders.AsExchangeResult(Exchange, orders.Data.Select(x => new SharedSpotOrder( x.Symbol, x.Id.ToString(), ParseOrderType(x.Type), @@ -194,16 +208,16 @@ async Task>> ISpotOrderRestClient.Get })); } - async Task>> ISpotOrderRestClient.GetClosedOrdersAsync(GetSpotClosedOrdersRequest request, CancellationToken ct = default) + async Task>> ISpotOrderRestClient.GetClosedOrdersAsync(GetSpotClosedOrdersRequest request, CancellationToken ct = default) { var orders = await Trading.GetOrdersAsync(FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), startTime: request.StartTime, endTime: request.EndTime, limit: request.Limit).ConfigureAwait(false); if (!orders) - return orders.As>(default); + return orders.AsExchangeResult>(Exchange, default); - return orders.As(orders.Data.Where(x => x.Status == OrderStatus.Filled || x.Status == OrderStatus.Canceled || x.Status == OrderStatus.Expired).Select(x => new SharedSpotOrder( + return orders.AsExchangeResult(Exchange, orders.Data.Where(x => x.Status == OrderStatus.Filled || x.Status == OrderStatus.Canceled || x.Status == OrderStatus.Expired).Select(x => new SharedSpotOrder( x.Symbol, x.Id.ToString(), ParseOrderType(x.Type), @@ -223,16 +237,16 @@ async Task>> ISpotOrderRestClient.Get })); } - async Task>> ISpotOrderRestClient.GetOrderTradesAsync(GetOrderTradesRequest request, CancellationToken ct = default) + async Task>> ISpotOrderRestClient.GetOrderTradesAsync(GetOrderTradesRequest request, CancellationToken ct = default) { if (!long.TryParse(request.OrderId, out var orderId)) - return new WebCallResult>(new ArgumentError("Invalid order id")); + return new ExchangeWebResult>(Exchange, new ArgumentError("Invalid order id")); var orders = await Trading.GetUserTradesAsync(FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), orderId: orderId).ConfigureAwait(false); if (!orders) - return orders.As>(default); + return orders.AsExchangeResult>(Exchange, default); - return orders.As(orders.Data.Select(x => new SharedUserTrade( + return orders.AsExchangeResult(Exchange, orders.Data.Select(x => new SharedUserTrade( x.Symbol, x.OrderId.ToString(), x.Id.ToString(), @@ -248,7 +262,7 @@ async Task>> ISpotOrderRestClient.Get })); } - async Task>> ISpotOrderRestClient.GetUserTradesAsync(GetUserTradesRequest request, CancellationToken ct = default) + async Task>> ISpotOrderRestClient.GetUserTradesAsync(GetUserTradesRequest request, CancellationToken ct = default) { var orders = await Trading.GetUserTradesAsync(FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), startTime: request.StartTime, @@ -256,9 +270,9 @@ async Task>> ISpotOrderRestClient.Get limit: request.Limit ).ConfigureAwait(false); if (!orders) - return orders.As>(default); + return orders.AsExchangeResult>(Exchange, default); - return orders.As(orders.Data.Select(x => new SharedUserTrade( + return orders.AsExchangeResult(Exchange, orders.Data.Select(x => new SharedUserTrade( x.Symbol, x.OrderId.ToString(), x.Id.ToString(), @@ -274,16 +288,16 @@ async Task>> ISpotOrderRestClient.Get })); } - async Task> ISpotOrderRestClient.CancelOrderAsync(CancelOrderRequest request, CancellationToken ct = default) + async Task> ISpotOrderRestClient.CancelOrderAsync(CancelOrderRequest request, CancellationToken ct = default) { if (!long.TryParse(request.OrderId, out var orderId)) - return new WebCallResult(new ArgumentError("Invalid order id")); + return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); var order = await Trading.CancelOrderAsync(FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), orderId).ConfigureAwait(false); if (!order) - return order.As(default); + return order.AsExchangeResult(Exchange, default); - return order.As(new SharedOrderId(order.Data.Id.ToString())); + return order.AsExchangeResult(Exchange, new SharedOrderId(order.Data.Id.ToString())); } private SharedOrderStatus ParseOrderStatus(OrderStatus status) diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs index 63d49722b..53735da8d 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs @@ -2,6 +2,7 @@ using CryptoExchange.Net.Objects.Sockets; using CryptoExchange.Net.SharedApis.Enums; using CryptoExchange.Net.SharedApis.Interfaces.Socket; +using CryptoExchange.Net.SharedApis.Models; using CryptoExchange.Net.SharedApis.Models.Socket; using CryptoExchange.Net.SharedApis.RequestModels; using CryptoExchange.Net.SharedApis.ResponseModels; @@ -16,55 +17,55 @@ internal partial class BinanceSocketClientSpotApi : IBinanceSocketClientSpotApiS { public string Exchange => BinanceExchange.ExchangeName; - async Task> ITickersSocketClient.SubscribeToAllTickerUpdatesAsync(SharedRequest request, Action>> handler, CancellationToken ct) + async Task> ITickersSocketClient.SubscribeToAllTickerUpdatesAsync(SharedRequest request, Action>> handler, CancellationToken ct) { var result = await ExchangeData.SubscribeToAllMiniTickerUpdatesAsync(update => handler(update.As(update.Data.Select(x => new SharedTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice)))), ct).ConfigureAwait(false); - return result; + return new ExchangeResult(Exchange, result); } - async Task> ITickerSocketClient.SubscribeToTickerUpdatesAsync(TickerSubscribeRequest request, Action> handler, CancellationToken ct) + async Task> ITickerSocketClient.SubscribeToTickerUpdatesAsync(TickerSubscribeRequest request, Action> handler, CancellationToken ct) { var symbol = FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType); var result = await ExchangeData.SubscribeToMiniTickerUpdatesAsync(symbol, update => handler(update.As(new SharedTicker(update.Data.Symbol, update.Data.LastPrice, update.Data.HighPrice, update.Data.LowPrice))), ct).ConfigureAwait(false); - return result; + return new ExchangeResult(Exchange, result); } - async Task> ITradeSocketClient.SubscribeToTradeUpdatesAsync(TradeSubscribeRequest request, Action>> handler, CancellationToken ct) + async Task> ITradeSocketClient.SubscribeToTradeUpdatesAsync(TradeSubscribeRequest request, Action>> handler, CancellationToken ct) { var symbol = FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType); var result = await ExchangeData.SubscribeToTradeUpdatesAsync(symbol, update => handler(update.As>(new[] { new SharedTrade(update.Data.Price, update.Data.Quantity, update.Data.TradeTime) })), ct).ConfigureAwait(false); - return result; + return new ExchangeResult(Exchange, result); } - async Task> IBookTickerSocketClient.SubscribeToBookTickerUpdatesAsync(BookTickerSubscribeRequest request, Action> handler, CancellationToken ct) + async Task> IBookTickerSocketClient.SubscribeToBookTickerUpdatesAsync(BookTickerSubscribeRequest request, Action> handler, CancellationToken ct) { var symbol = FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType); var result = await ExchangeData.SubscribeToBookTickerUpdatesAsync(symbol, update => handler(update.As(new SharedBookTicker(update.Data.BestAskPrice, update.Data.BestAskQuantity, update.Data.BestBidPrice, update.Data.BestBidQuantity))), ct).ConfigureAwait(false); - return result; + return new ExchangeResult(Exchange, result); } - async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(SharedRequest request, Action>> handler, CancellationToken ct) + async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(SharedRequest request, Action>> handler, CancellationToken ct) { var listenKey = await Account.StartUserStreamAsync().ConfigureAwait(false); if (!listenKey) - return listenKey.As(default); + return new ExchangeResult(Exchange, listenKey.As(default)); var result = await Account.SubscribeToUserDataUpdatesAsync(listenKey.Data.Result, onAccountPositionMessage: update => handler(update.As(update.Data.Balances.Select(x => new SharedBalance(x.Asset, x.Available, x.Total)))), ct: ct).ConfigureAwait(false); - return result; + return new ExchangeResult(Exchange, result); } - async Task> ISpotOrderSocketClient.SubscribeToOrderUpdatesAsync(SharedRequest request, Action>> handler, CancellationToken ct) + async Task> ISpotOrderSocketClient.SubscribeToOrderUpdatesAsync(SharedRequest request, Action>> handler, CancellationToken ct) { var listenKey = await Account.StartUserStreamAsync().ConfigureAwait(false); if (!listenKey) - return listenKey.As(default); + return new ExchangeResult(Exchange, listenKey.As(default)); var result = await Account.SubscribeToUserDataUpdatesAsync(listenKey.Data.Result, onOrderUpdateMessage: update => handler(update.As>(new[] { @@ -94,7 +95,7 @@ async Task> ISpotOrderSocketClient.SubscribeToOrd })), ct: ct).ConfigureAwait(false); - return result; + return new ExchangeResult(Exchange, result); } } } diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs index ebc4dc9f6..d54759078 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -1,6 +1,9 @@ using Binance.Net.Interfaces.Clients.SpotApi; using Binance.Net.Interfaces.Clients.UsdFuturesApi; +using CryptoExchange.Net.SharedApis.Enums; using CryptoExchange.Net.SharedApis.Interfaces; +using CryptoExchange.Net.SharedApis.Models; +using CryptoExchange.Net.SharedApis.Models.FilterOptions; using CryptoExchange.Net.SharedApis.Models.Rest; using CryptoExchange.Net.SharedApis.RequestModels; using CryptoExchange.Net.SharedApis.ResponseModels; @@ -14,11 +17,23 @@ internal partial class BinanceRestClientUsdFuturesApi : IBinanceRestClientUsdFut { public string Exchange => BinanceExchange.ExchangeName; - async Task>> IKlineRestClient.GetKlinesAsync(GetKlinesRequest request, CancellationToken ct) + //GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } + // = new GetKlinesOptions( + // true, + // false, + // SharedKlineInterval.FiveMinutes, + // SharedKlineInterval.FifteenMinutes, + // SharedKlineInterval.OneHour, + // SharedKlineInterval.FifteenMinutes, + // SharedKlineInterval.OneDay, + // SharedKlineInterval.OneWeek, + // SharedKlineInterval.OneMonth); + + async Task>> IKlineRestClient.GetKlinesAsync(GetKlinesRequest request, CancellationToken ct) { - var interval = (Enums.KlineInterval)request.Interval.TotalSeconds; + var interval = (Enums.KlineInterval)request.Interval; if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) - return new WebCallResult>(new ArgumentError("Interval not supported")); + return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); var result = await ExchangeData.GetKlinesAsync( FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), @@ -29,18 +44,18 @@ async Task>> IKlineRestClient.GetKlinesAs ct: ct ).ConfigureAwait(false); if (!result) - return result.As>(default); + return result.AsExchangeResult< IEnumerable>(Exchange, default); - return result.As(result.Data.Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume))); + return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume))); } - async Task>> IFuturesSymbolRestClient.GetSymbolsAsync(SharedRequest request, CancellationToken ct) + async Task>> IFuturesSymbolRestClient.GetSymbolsAsync(SharedRequest request, CancellationToken ct) { var result = await ExchangeData.GetExchangeInfoAsync(ct).ConfigureAwait(false); if (!result) - return result.As>(default); + return result.AsExchangeResult< IEnumerable>(Exchange, default); - return result.As(result.Data.Symbols.Select(s => new SharedFuturesSymbol(s.BaseAsset, s.QuoteAsset, s.Name) + return result.AsExchangeResult(Exchange, result.Data.Symbols.Select(s => new SharedFuturesSymbol(s.BaseAsset, s.QuoteAsset, s.Name) { MinTradeQuantity = s.LotSizeFilter?.MinQuantity, MaxTradeQuantity = s.LotSizeFilter?.MaxQuantity, @@ -51,25 +66,25 @@ async Task>> IFuturesSymbolRestCl })); } - async Task> ITickerRestClient.GetTickerAsync(GetTickerRequest request, CancellationToken ct) + async Task> ITickerRestClient.GetTickerAsync(GetTickerRequest request, CancellationToken ct) { var result = await ExchangeData.GetTickerAsync(FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), ct).ConfigureAwait(false); if (!result) - return result.As(default); + return result.AsExchangeResult(Exchange, default); - return result.As(new SharedTicker(result.Data.Symbol, result.Data.LastPrice, result.Data.HighPrice, result.Data.LowPrice)); + return result.AsExchangeResult(Exchange, new SharedTicker(result.Data.Symbol, result.Data.LastPrice, result.Data.HighPrice, result.Data.LowPrice)); } - async Task>> ITickerRestClient.GetTickersAsync(SharedRequest request, CancellationToken ct) + async Task>> ITickerRestClient.GetTickersAsync(SharedRequest request, CancellationToken ct) { var result = await ExchangeData.GetTickersAsync(ct: ct).ConfigureAwait(false); if (!result) - return result.As>(default); + return result.AsExchangeResult>(Exchange, default); - return result.As>(result.Data.Select(x => new SharedTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice))); + return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice))); } - async Task>> ITradeRestClient.GetTradesAsync(GetTradesRequest request, CancellationToken ct) + async Task>> ITradeRestClient.GetTradesAsync(GetTradesRequest request, CancellationToken ct) { var result = await ExchangeData.GetAggregatedTradeHistoryAsync( FormatSymbol(request.BaseAsset, request.QuoteAsset), // Don't pass api type; need only the pair @@ -78,9 +93,9 @@ async Task>> ITradeRestClient.GetTradesAs limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) - return result.As>(default); + return result.AsExchangeResult< IEnumerable>(Exchange, default); - return result.As(result.Data.Select(x => new SharedTrade(x.Quantity, x.Price, x.TradeTime))); + return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedTrade(x.Quantity, x.Price, x.TradeTime))); } } } From 4fa5c20d8c17fd2ce06107cc96b27f5535b4b5a0 Mon Sep 17 00:00:00 2001 From: JKorf Date: Thu, 15 Aug 2024 16:55:12 +0200 Subject: [PATCH 10/54] wip --- .../BinanceRestClientCoinFuturesApiShared.cs | 30 ++++--- .../SpotApi/BinanceRestClientSpotApiShared.cs | 80 ++++++++++++++----- .../BinanceRestClientUsdFuturesApiShared.cs | 30 ++++--- .../IBinanceRestClientCoinFuturesApiShared.cs | 2 +- .../IBinanceRestClientSpotApiShared.cs | 2 +- .../IBinanceRestClientUsdFuturesApiShared.cs | 2 +- 6 files changed, 101 insertions(+), 45 deletions(-) diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs index 6221d2d50..ee2d9e2b0 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -25,24 +25,36 @@ internal partial class BinanceRestClientCoinFuturesApi : IBinanceRestClientCoinF // SharedKlineInterval.OneWeek, // SharedKlineInterval.OneMonth); - async Task>> IKlineRestClient.GetKlinesAsync(GetKlinesRequest request, CancellationToken ct) + async Task>> IKlineRestClient.GetKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, CancellationToken ct) { var interval = (Enums.KlineInterval)request.Interval; if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); + // Determine page token + DateTime? fromTimestamp = null; + if (pageToken is DateTimeToken dateTimeToken) + fromTimestamp = dateTimeToken.LastTime; + var result = await ExchangeData.GetKlinesAsync( - FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), + request.GetSymbol(FormatSymbol), interval, - request.StartTime, + fromTimestamp ?? request.StartTime, request.EndTime, - request.Limit, + request.Limit ?? 1000, ct: ct ).ConfigureAwait(false); if (!result) return result.AsExchangeResult>(Exchange, default); - return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume))); + // Get next token + DateTimeToken? nextToken = null; + if (result.Data.Count() == (request.Limit ?? 1000)) + nextToken = new DateTimeToken(result.Data.Max(o => o.OpenTime).AddSeconds((int)interval)); + if (nextToken?.LastTime >= request.EndTime) + nextToken = null; + + return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)), nextToken); } async Task>> IFuturesSymbolRestClient.GetSymbolsAsync(SharedRequest request, CancellationToken ct) @@ -64,7 +76,7 @@ async Task>> IFuturesSymbolRe async Task> ITickerRestClient.GetTickerAsync(GetTickerRequest request, CancellationToken ct) { - var result = await ExchangeData.GetTickersAsync(symbol: FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), ct: ct).ConfigureAwait(false); + var result = await ExchangeData.GetTickersAsync(symbol: request.GetSymbol(FormatSymbol), ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -81,12 +93,10 @@ async Task>> ITickerRestClient.GetTi return result.AsExchangeResult(Exchange, result.Data.Select( x => new SharedTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice))); } - async Task>> ITradeRestClient.GetTradesAsync(GetTradesRequest request, CancellationToken ct) + async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, CancellationToken ct) { var result = await ExchangeData.GetAggregatedTradeHistoryAsync( - FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), - startTime: request.StartTime, - endTime: request.EndTime, + request.GetSymbol(FormatSymbol), limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index 7e00ae0ee..f056369b3 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -47,24 +47,37 @@ internal partial class BinanceRestClientSpotApi : IBinanceRestClientSpotApiShare // SharedKlineInterval.OneWeek, // SharedKlineInterval.OneMonth); - async Task>> IKlineRestClient.GetKlinesAsync(GetKlinesRequest request, CancellationToken ct) + async Task>> IKlineRestClient.GetKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, CancellationToken ct) { var interval = (Enums.KlineInterval)request.Interval; if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - + + // Determine page token + DateTime? fromTimestamp = null; + if (pageToken is DateTimeToken dateTimeToken) + fromTimestamp = dateTimeToken.LastTime; + + // Get data var result = await ExchangeData.GetKlinesAsync( request.GetSymbol(FormatSymbol), interval, - request.StartTime, + fromTimestamp ?? request.StartTime, request.EndTime, - request.Limit, + request.Limit ?? 1000, ct: ct ).ConfigureAwait(false); if (!result) return new ExchangeWebResult>(Exchange, result.As>(default)); - return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume))); + // Get next token + DateTimeToken? nextToken = null; + if (result.Data.Count() == (request.Limit ?? 1000)) + nextToken = new DateTimeToken(result.Data.Max(o => o.OpenTime).AddSeconds((int)interval)); + if (nextToken?.LastTime >= request.EndTime) + nextToken = null; + + return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)), nextToken); } async Task>> ISpotSymbolRestClient.GetSymbolsAsync(SharedRequest request, CancellationToken ct) @@ -84,7 +97,7 @@ async Task>> ISpotSymbolRestClie async Task> ITickerRestClient.GetTickerAsync(GetTickerRequest request, CancellationToken ct) { - var result = await ExchangeData.GetTickerAsync(FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), ct).ConfigureAwait(false); + var result = await ExchangeData.GetTickerAsync(request.GetSymbol(FormatSymbol), ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -106,17 +119,17 @@ async Task>> ITickerRestClient.GetTi })); } - async Task>> ITradeRestClient.GetTradesAsync(GetTradesRequest request, CancellationToken ct) + async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, CancellationToken ct) { + // Get data var result = await ExchangeData.GetAggregatedTradeHistoryAsync( - FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), - startTime: request.StartTime, - endTime: request.EndTime, + request.GetSymbol(FormatSymbol), limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult>(Exchange, default); + // Return return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedTrade(x.Quantity, x.Price, x.TradeTime))); } @@ -135,7 +148,7 @@ async Task> ISpotOrderRestClient.PlaceOrderAsyn throw new ArgumentException("OrderType can't be `Other`", nameof(request.OrderType)); var result = await Trading.PlaceOrderAsync( - FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), + request.GetSymbol(FormatSymbol), request.Side == SharedOrderSide.Buy ? Enums.OrderSide.Buy : Enums.OrderSide.Sell, request.OrderType == SharedOrderType.Limit ? Enums.SpotOrderType.Limit : request.OrderType == SharedOrderType.Market ? Enums.SpotOrderType.Market: Enums.SpotOrderType.LimitMaker, quantity: request.Quantity, @@ -154,7 +167,7 @@ async Task> ISpotOrderRestClient.GetOrderAsyn if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); - var order = await Trading.GetOrderAsync(FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), orderId).ConfigureAwait(false); + var order = await Trading.GetOrderAsync(request.GetSymbol(FormatSymbol), orderId).ConfigureAwait(false); if (!order) return order.AsExchangeResult(Exchange, default); @@ -208,15 +221,26 @@ async Task>> ISpotOrderRestClient })); } - async Task>> ISpotOrderRestClient.GetClosedOrdersAsync(GetSpotClosedOrdersRequest request, CancellationToken ct = default) + async Task>> ISpotOrderRestClient.GetClosedOrdersAsync(GetSpotClosedOrdersRequest request, INextPageToken? pageToken, CancellationToken ct) { - var orders = await Trading.GetOrdersAsync(FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), - startTime: request.StartTime, + // Determine page token + DateTime? fromTimestamp = null; + if (pageToken is DateTimeToken dateTimeToken) + fromTimestamp = dateTimeToken.LastTime; + + // Get data + var orders = await Trading.GetOrdersAsync(request.GetSymbol(FormatSymbol), + startTime: fromTimestamp ?? request.StartTime, endTime: request.EndTime, - limit: request.Limit).ConfigureAwait(false); + limit: request.Limit ?? 1000).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); + // Get next token + DateTimeToken? nextToken = null; + if (orders.Data.Count() == (request.Limit ?? 1000)) + nextToken = new DateTimeToken(orders.Data.Max(o => o.CreateTime)); + return orders.AsExchangeResult(Exchange, orders.Data.Where(x => x.Status == OrderStatus.Filled || x.Status == OrderStatus.Canceled || x.Status == OrderStatus.Expired).Select(x => new SharedSpotOrder( x.Symbol, x.Id.ToString(), @@ -242,7 +266,7 @@ async Task>> ISpotOrderRestClient if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult>(Exchange, new ArgumentError("Invalid order id")); - var orders = await Trading.GetUserTradesAsync(FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), orderId: orderId).ConfigureAwait(false); + var orders = await Trading.GetUserTradesAsync(request.GetSymbol(FormatSymbol), orderId: orderId).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); @@ -262,16 +286,28 @@ async Task>> ISpotOrderRestClient })); } - async Task>> ISpotOrderRestClient.GetUserTradesAsync(GetUserTradesRequest request, CancellationToken ct = default) + async Task>> ISpotOrderRestClient.GetUserTradesAsync(GetUserTradesRequest request, INextPageToken? pageToken, CancellationToken ct) { - var orders = await Trading.GetUserTradesAsync(FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), + // Determine page token + long? fromId = null; + if (pageToken is FromIdToken fromIdToken) + fromId = long.Parse(fromIdToken.FromToken); + + // Get data + var orders = await Trading.GetUserTradesAsync(request.GetSymbol(FormatSymbol), startTime: request.StartTime, endTime: request.EndTime, - limit: request.Limit + limit: request.Limit ?? 500, + fromId: fromId ).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); + // Get next token + FromIdToken? nextToken = null; + if (orders.Data.Count() == (request.Limit ?? 500)) + nextToken = new FromIdToken(orders.Data.Max(o => o.Id).ToString()); + return orders.AsExchangeResult(Exchange, orders.Data.Select(x => new SharedUserTrade( x.Symbol, x.OrderId.ToString(), @@ -285,7 +321,7 @@ async Task>> ISpotOrderRestClient Fee = x.Fee, FeeAsset = x.FeeAsset, Role = x.IsMaker ? SharedRole.Maker : SharedRole.Taker - })); + }), nextToken); } async Task> ISpotOrderRestClient.CancelOrderAsync(CancelOrderRequest request, CancellationToken ct = default) @@ -293,7 +329,7 @@ async Task> ISpotOrderRestClient.CancelOrderAsy if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); - var order = await Trading.CancelOrderAsync(FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), orderId).ConfigureAwait(false); + var order = await Trading.CancelOrderAsync(request.GetSymbol(FormatSymbol), orderId).ConfigureAwait(false); if (!order) return order.AsExchangeResult(Exchange, default); diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs index d54759078..434a6add9 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -29,24 +29,36 @@ internal partial class BinanceRestClientUsdFuturesApi : IBinanceRestClientUsdFut // SharedKlineInterval.OneWeek, // SharedKlineInterval.OneMonth); - async Task>> IKlineRestClient.GetKlinesAsync(GetKlinesRequest request, CancellationToken ct) + async Task>> IKlineRestClient.GetKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, CancellationToken ct) { var interval = (Enums.KlineInterval)request.Interval; if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); + // Determine page token + DateTime? fromTimestamp = null; + if (pageToken is DateTimeToken dateTimeToken) + fromTimestamp = dateTimeToken.LastTime; + var result = await ExchangeData.GetKlinesAsync( - FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), + request.GetSymbol(FormatSymbol), interval, - request.StartTime, + fromTimestamp ?? request.StartTime, request.EndTime, - request.Limit, + request.Limit ?? 1000, ct: ct ).ConfigureAwait(false); if (!result) return result.AsExchangeResult< IEnumerable>(Exchange, default); - return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume))); + // Get next token + DateTimeToken? nextToken = null; + if (result.Data.Count() == (request.Limit ?? 1000)) + nextToken = new DateTimeToken(result.Data.Max(o => o.OpenTime).AddSeconds((int)interval)); + if (nextToken?.LastTime >= request.EndTime) + nextToken = null; + + return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)), nextToken); } async Task>> IFuturesSymbolRestClient.GetSymbolsAsync(SharedRequest request, CancellationToken ct) @@ -68,7 +80,7 @@ async Task>> IFuturesSymbolRe async Task> ITickerRestClient.GetTickerAsync(GetTickerRequest request, CancellationToken ct) { - var result = await ExchangeData.GetTickerAsync(FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType), ct).ConfigureAwait(false); + var result = await ExchangeData.GetTickerAsync(request.GetSymbol(FormatSymbol), ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -84,12 +96,10 @@ async Task>> ITickerRestClient.GetTi return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice))); } - async Task>> ITradeRestClient.GetTradesAsync(GetTradesRequest request, CancellationToken ct) + async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, CancellationToken ct) { var result = await ExchangeData.GetAggregatedTradeHistoryAsync( - FormatSymbol(request.BaseAsset, request.QuoteAsset), // Don't pass api type; need only the pair - startTime: request.StartTime, - endTime: request.EndTime, + request.GetSymbol((baseAsset, quoteAsset, apiType) => FormatSymbol(baseAsset, quoteAsset)), // Don't pass api type; need only the pair limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) diff --git a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs index 29c483496..a87d4b6fc 100644 --- a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs @@ -9,7 +9,7 @@ public interface IBinanceRestClientCoinFuturesApiShared : ITickerRestClient, IFuturesSymbolRestClient, IKlineRestClient, - ITradeRestClient + IRecentTradeRestClient { } } diff --git a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs index 1eebf2e23..1365109d3 100644 --- a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs @@ -9,7 +9,7 @@ public interface IBinanceRestClientSpotApiShared: ITickerRestClient, ISpotSymbolRestClient, IKlineRestClient, - ITradeRestClient, + IRecentTradeRestClient, IBalanceRestClient, ISpotOrderRestClient { diff --git a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs index 873c24da0..784d11938 100644 --- a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs @@ -9,7 +9,7 @@ public interface IBinanceRestClientUsdFuturesApiShared : ITickerRestClient, IFuturesSymbolRestClient, IKlineRestClient, - ITradeRestClient + IRecentTradeRestClient { } } From 63cef471d449dc55d4a20a63764357b3e4d9b5a8 Mon Sep 17 00:00:00 2001 From: JKorf Date: Fri, 16 Aug 2024 16:28:32 +0200 Subject: [PATCH 11/54] wip --- .../BinanceRestClientCoinFuturesApiShared.cs | 16 ++++++---- .../SpotApi/BinanceRestClientSpotApiShared.cs | 32 ++++++++++--------- .../BinanceRestClientUsdFuturesApiShared.cs | 16 ++++++---- 3 files changed, 35 insertions(+), 29 deletions(-) diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs index ee2d9e2b0..e43608a43 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -39,9 +39,9 @@ async Task>> IKlineRestClient.GetKlin var result = await ExchangeData.GetKlinesAsync( request.GetSymbol(FormatSymbol), interval, - fromTimestamp ?? request.StartTime, - request.EndTime, - request.Limit ?? 1000, + fromTimestamp ?? request.Filter?.StartTime, + request.Filter?.EndTime, + request.Filter?.Limit ?? 1000, ct: ct ).ConfigureAwait(false); if (!result) @@ -49,10 +49,12 @@ async Task>> IKlineRestClient.GetKlin // Get next token DateTimeToken? nextToken = null; - if (result.Data.Count() == (request.Limit ?? 1000)) - nextToken = new DateTimeToken(result.Data.Max(o => o.OpenTime).AddSeconds((int)interval)); - if (nextToken?.LastTime >= request.EndTime) - nextToken = null; + if (request.Filter?.StartTime != null && result.Data.Any()) + { + var maxOpenTime = result.Data.Max(x => x.OpenTime); + if (maxOpenTime < request.Filter.EndTime!.Value.AddSeconds(-(int)request.Interval)) + nextToken = new DateTimeToken(maxOpenTime.AddSeconds((int)interval)); + } return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)), nextToken); } diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index f056369b3..2a15154ae 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -62,9 +62,9 @@ async Task>> IKlineRestClient.GetKlin var result = await ExchangeData.GetKlinesAsync( request.GetSymbol(FormatSymbol), interval, - fromTimestamp ?? request.StartTime, - request.EndTime, - request.Limit ?? 1000, + fromTimestamp ?? request.Filter?.StartTime, + request.Filter?.EndTime?.AddSeconds(-1), + request.Filter?.Limit ?? 1000, ct: ct ).ConfigureAwait(false); if (!result) @@ -72,10 +72,12 @@ async Task>> IKlineRestClient.GetKlin // Get next token DateTimeToken? nextToken = null; - if (result.Data.Count() == (request.Limit ?? 1000)) - nextToken = new DateTimeToken(result.Data.Max(o => o.OpenTime).AddSeconds((int)interval)); - if (nextToken?.LastTime >= request.EndTime) - nextToken = null; + if (request.Filter?.StartTime != null && result.Data.Any()) + { + var maxOpenTime = result.Data.Max(x => x.OpenTime); + if (maxOpenTime < request.Filter.EndTime!.Value.AddSeconds(-(int)request.Interval)) + nextToken = new DateTimeToken(maxOpenTime.AddSeconds((int)interval)); + } return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)), nextToken); } @@ -230,15 +232,15 @@ async Task>> ISpotOrderRestClient // Get data var orders = await Trading.GetOrdersAsync(request.GetSymbol(FormatSymbol), - startTime: fromTimestamp ?? request.StartTime, - endTime: request.EndTime, - limit: request.Limit ?? 1000).ConfigureAwait(false); + startTime: fromTimestamp ?? request.Filter?.StartTime, + endTime: request.Filter?.EndTime, + limit: request.Filter?.Limit ?? 1000).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); // Get next token DateTimeToken? nextToken = null; - if (orders.Data.Count() == (request.Limit ?? 1000)) + if (orders.Data.Count() == (request.Filter?.Limit ?? 1000)) nextToken = new DateTimeToken(orders.Data.Max(o => o.CreateTime)); return orders.AsExchangeResult(Exchange, orders.Data.Where(x => x.Status == OrderStatus.Filled || x.Status == OrderStatus.Canceled || x.Status == OrderStatus.Expired).Select(x => new SharedSpotOrder( @@ -295,9 +297,9 @@ async Task>> ISpotOrderRestClient // Get data var orders = await Trading.GetUserTradesAsync(request.GetSymbol(FormatSymbol), - startTime: request.StartTime, - endTime: request.EndTime, - limit: request.Limit ?? 500, + startTime: request.Filter?.StartTime, + endTime: request.Filter?.EndTime, + limit: request.Filter?.Limit ?? 500, fromId: fromId ).ConfigureAwait(false); if (!orders) @@ -305,7 +307,7 @@ async Task>> ISpotOrderRestClient // Get next token FromIdToken? nextToken = null; - if (orders.Data.Count() == (request.Limit ?? 500)) + if (orders.Data.Count() == (request.Filter?.Limit ?? 500)) nextToken = new FromIdToken(orders.Data.Max(o => o.Id).ToString()); return orders.AsExchangeResult(Exchange, orders.Data.Select(x => new SharedUserTrade( diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs index 434a6add9..d1d87fc3d 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -43,9 +43,9 @@ async Task>> IKlineRestClient.GetKlin var result = await ExchangeData.GetKlinesAsync( request.GetSymbol(FormatSymbol), interval, - fromTimestamp ?? request.StartTime, - request.EndTime, - request.Limit ?? 1000, + fromTimestamp ?? request.Filter?.StartTime, + request.Filter?.EndTime, + request.Filter?.Limit ?? 1000, ct: ct ).ConfigureAwait(false); if (!result) @@ -53,10 +53,12 @@ async Task>> IKlineRestClient.GetKlin // Get next token DateTimeToken? nextToken = null; - if (result.Data.Count() == (request.Limit ?? 1000)) - nextToken = new DateTimeToken(result.Data.Max(o => o.OpenTime).AddSeconds((int)interval)); - if (nextToken?.LastTime >= request.EndTime) - nextToken = null; + if (request.Filter?.StartTime != null && result.Data.Any()) + { + var maxOpenTime = result.Data.Max(x => x.OpenTime); + if (maxOpenTime < request.Filter.EndTime!.Value.AddSeconds(-(int)request.Interval)) + nextToken = new DateTimeToken(maxOpenTime.AddSeconds((int)interval)); + } return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)), nextToken); } From aad8fe4ea1ebeb64ab648115483591e9c27c1f87 Mon Sep 17 00:00:00 2001 From: JKorf Date: Sun, 18 Aug 2024 20:04:51 +0200 Subject: [PATCH 12/54] wip --- .../BinanceRestClientCoinFuturesApiShared.cs | 22 +- .../SpotApi/BinanceRestClientSpotApiShared.cs | 296 +++++++++++++++--- .../BinanceRestClientUsdFuturesApiShared.cs | 22 +- .../IBinanceRestClientSpotApiShared.cs | 14 +- .../Models/Spot/BinanceWithdrawalPlaced.cs | 2 +- 5 files changed, 279 insertions(+), 77 deletions(-) diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs index e43608a43..a9ee072de 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -13,17 +13,10 @@ internal partial class BinanceRestClientCoinFuturesApi : IBinanceRestClientCoinF { public string Exchange => BinanceExchange.ExchangeName; - //GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } - // = new GetKlinesOptions( - // true, - // false, - // SharedKlineInterval.FiveMinutes, - // SharedKlineInterval.FifteenMinutes, - // SharedKlineInterval.OneHour, - // SharedKlineInterval.FifteenMinutes, - // SharedKlineInterval.OneDay, - // SharedKlineInterval.OneWeek, - // SharedKlineInterval.OneMonth); + GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(true) + { + MaxRequestDataPoints = 1000 + }; async Task>> IKlineRestClient.GetKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, CancellationToken ct) { @@ -86,7 +79,7 @@ async Task> ITickerRestClient.GetTickerAsync(Get return result.AsExchangeResult(Exchange, new SharedTicker(ticker.Symbol, ticker.LastPrice, ticker.HighPrice, ticker.LowPrice)); } - async Task>> ITickerRestClient.GetTickersAsync(SharedRequest request, CancellationToken ct) + async Task>> ITickerRestClient.GetTickersAsync(ApiType? apiType, CancellationToken ct) { var result = await ExchangeData.GetTickersAsync(ct: ct).ConfigureAwait(false); if (!result) @@ -95,16 +88,17 @@ async Task>> ITickerRestClient.GetTi return result.AsExchangeResult(Exchange, result.Data.Select( x => new SharedTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice))); } + GetRecentTradesOptions IRecentTradeRestClient.GetRecentTradesOptions { get; } = new GetRecentTradesOptions(1000); async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, CancellationToken ct) { - var result = await ExchangeData.GetAggregatedTradeHistoryAsync( + var result = await ExchangeData.GetRecentTradesAsync( request.GetSymbol(FormatSymbol), limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult>(Exchange, default); - return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedTrade(x.Quantity, x.Price, x.TradeTime))); + return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedTrade(x.BaseQuantity, x.Price, x.TradeTime))); } } } diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index 2a15154ae..a6b06bb81 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -14,45 +14,23 @@ internal partial class BinanceRestClientSpotApi : IBinanceRestClientSpotApiShare { public string Exchange => BinanceExchange.ExchangeName; - public IEnumerable SupportedOrderType { get; } = new[] - { - SharedOrderType.Limit, - SharedOrderType.Market, - SharedOrderType.LimitMaker - }; + #region Klines Client - public IEnumerable SupportedTimeInForce { get; } = new[] + GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(true) { - SharedTimeInForce.GoodTillCanceled, - SharedTimeInForce.ImmediateOrCancel, - SharedTimeInForce.FillOrKill + MaxRequestDataPoints = 1000 }; - public SharedQuantitySupport OrderQuantitySupport { get; } = - new SharedQuantitySupport( - SharedQuantityType.BaseAssetQuantity, - SharedQuantityType.BaseAssetQuantity, - SharedQuantityType.Both, - SharedQuantityType.Both); - - //GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } - // = new GetKlinesOptions( - // true, - // false, - // SharedKlineInterval.FiveMinutes, - // SharedKlineInterval.FifteenMinutes, - // SharedKlineInterval.OneHour, - // SharedKlineInterval.FifteenMinutes, - // SharedKlineInterval.OneDay, - // SharedKlineInterval.OneWeek, - // SharedKlineInterval.OneMonth); - async Task>> IKlineRestClient.GetKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, CancellationToken ct) { var interval = (Enums.KlineInterval)request.Interval; if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); + var validationError = ((IKlineRestClient)this).GetKlinesOptions.Validate(request); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + // Determine page token DateTime? fromTimestamp = null; if (pageToken is DateTimeToken dateTimeToken) @@ -82,7 +60,11 @@ async Task>> IKlineRestClient.GetKlin return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)), nextToken); } - async Task>> ISpotSymbolRestClient.GetSymbolsAsync(SharedRequest request, CancellationToken ct) + #endregion + + #region Spot Symbol client + + async Task>> ISpotSymbolRestClient.GetSpotSymbolsAsync(CancellationToken ct) { var result = await ExchangeData.GetExchangeInfoAsync(ct).ConfigureAwait(false); if (!result) @@ -97,6 +79,10 @@ async Task>> ISpotSymbolRestClie })); } + #endregion + + #region Ticker client + async Task> ITickerRestClient.GetTickerAsync(GetTickerRequest request, CancellationToken ct) { var result = await ExchangeData.GetTickerAsync(request.GetSymbol(FormatSymbol), ct).ConfigureAwait(false); @@ -106,7 +92,7 @@ async Task> ITickerRestClient.GetTickerAsync(Get return result.AsExchangeResult(Exchange, new SharedTicker(result.Data.Symbol, result.Data.LastPrice, result.Data.HighPrice, result.Data.LowPrice)); } - async Task>> ITickerRestClient.GetTickersAsync(SharedRequest request, CancellationToken ct) + async Task>> ITickerRestClient.GetTickersAsync(ApiType? apiType, CancellationToken ct) { var result = await ExchangeData.GetTickersAsync(ct: ct).ConfigureAwait(false); if (!result) @@ -121,10 +107,15 @@ async Task>> ITickerRestClient.GetTi })); } + #endregion + + #region Recent Trades client + GetRecentTradesOptions IRecentTradeRestClient.GetRecentTradesOptions { get; } = new GetRecentTradesOptions(1000); + async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, CancellationToken ct) { // Get data - var result = await ExchangeData.GetAggregatedTradeHistoryAsync( + var result = await ExchangeData.GetRecentTradesAsync( request.GetSymbol(FormatSymbol), limit: request.Limit, ct: ct).ConfigureAwait(false); @@ -132,10 +123,60 @@ async Task>> IRecentTradeRestClient.G return result.AsExchangeResult>(Exchange, default); // Return - return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedTrade(x.Quantity, x.Price, x.TradeTime))); + return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedTrade(x.BaseQuantity, x.Price, x.TradeTime))); + } + #endregion + + #region Trade History client + + async Task>> ITradeHistoryRestClient.GetTradeHistoryAsync(GetTradeHistoryRequest request, INextPageToken? pageToken, CancellationToken ct) + { + long? fromId = null; + if (pageToken is FromIdToken token) + fromId = long.Parse(token.FromToken); + + // Get data + var result = await ExchangeData.GetAggregatedTradeHistoryAsync( + request.GetSymbol(FormatSymbol), + startTime: fromId != null ? null : request.StartTime, + endTime: fromId != null ? null : request.EndTime, + limit: 1000, + fromId: fromId, + ct: ct).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult>(Exchange, default); + + FromIdToken? nextToken = null; + if (result.Data.Any() && result.Data.Last().TradeTime < request.EndTime) + nextToken = new FromIdToken(result.Data.Max(x => x.Id).ToString()); + + // Return + return result.AsExchangeResult(Exchange, result.Data.Where(x => x.TradeTime < request.EndTime).Select(x => new SharedTrade(x.Quantity, x.Price, x.TradeTime)), nextToken); + } + #endregion + + #region Order Book client + GetOrderBookOptions IOrderBookRestClient.GetOrderBookOptions { get; } = new GetOrderBookOptions(1, 5000); + async Task> IOrderBookRestClient.GetOrderBookAsync(GetOrderBookRequest request, CancellationToken ct) + { + var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.Validate(request); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + + var result = await ExchangeData.GetOrderBookAsync( + request.GetSymbol(FormatSymbol), + limit: request.Limit, + ct: ct).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult(Exchange, default); + + return result.AsExchangeResult(Exchange, new SharedOrderBook(result.Data.Asks, result.Data.Bids)); } + #endregion - async Task>> IBalanceRestClient.GetBalancesAsync(SharedRequest request, CancellationToken ct) + #region Balance Client + + async Task>> IBalanceRestClient.GetBalancesAsync(ApiType? apiType, CancellationToken ct) { var result = await Account.GetBalancesAsync(ct: ct).ConfigureAwait(false); if (!result) @@ -144,11 +185,38 @@ async Task>> IBalanceRestClient.Get return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedBalance(x.Asset, x.Available, x.Total))); } - async Task> ISpotOrderRestClient.PlaceOrderAsync(PlaceSpotOrderRequest request, CancellationToken ct = default) + #endregion + + #region Spot Order Client + + PlaceSpotOrderOptions ISpotOrderRestClient.PlaceSpotOrderOptions { get; } = new PlaceSpotOrderOptions( + new[] + { + SharedOrderType.Limit, + SharedOrderType.Market, + SharedOrderType.LimitMaker + }, + new[] + { + SharedTimeInForce.GoodTillCanceled, + SharedTimeInForce.ImmediateOrCancel, + SharedTimeInForce.FillOrKill + }, + new SharedQuantitySupport( + SharedQuantityType.BaseAssetQuantity, + SharedQuantityType.BaseAssetQuantity, + SharedQuantityType.Both, + SharedQuantityType.Both)); + + async Task> ISpotOrderRestClient.PlaceOrderAsync(PlaceSpotOrderRequest request, CancellationToken ct) { if (request.OrderType == SharedOrderType.Other) throw new ArgumentException("OrderType can't be `Other`", nameof(request.OrderType)); + var validationError = ((ISpotOrderRestClient)this).PlaceSpotOrderOptions.Validate(request); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + var result = await Trading.PlaceOrderAsync( request.GetSymbol(FormatSymbol), request.Side == SharedOrderSide.Buy ? Enums.OrderSide.Buy : Enums.OrderSide.Sell, @@ -159,12 +227,12 @@ async Task> ISpotOrderRestClient.PlaceOrderAsyn newClientOrderId: request.ClientOrderId).ConfigureAwait(false); if (!result) - return result.AsExchangeResult(Exchange, default); + return result.AsExchangeResult(Exchange, default); - return result.AsExchangeResult(Exchange, new SharedOrderId(result.Data.Id.ToString())); + return result.AsExchangeResult(Exchange, new SharedId(result.Data.Id.ToString())); } - async Task> ISpotOrderRestClient.GetOrderAsync(GetOrderRequest request, CancellationToken ct = default) + async Task> ISpotOrderRestClient.GetOrderAsync(GetOrderRequest request, CancellationToken ct) { if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); @@ -193,7 +261,7 @@ async Task> ISpotOrderRestClient.GetOrderAsyn }); } - async Task>> ISpotOrderRestClient.GetOpenOrdersAsync(GetSpotOpenOrdersRequest request, CancellationToken ct = default) + async Task>> ISpotOrderRestClient.GetOpenOrdersAsync(GetSpotOpenOrdersRequest request, CancellationToken ct) { string? symbol = null; if (request.BaseAsset != null && request.QuoteAsset != null) @@ -263,7 +331,7 @@ async Task>> ISpotOrderRestClient })); } - async Task>> ISpotOrderRestClient.GetOrderTradesAsync(GetOrderTradesRequest request, CancellationToken ct = default) + async Task>> ISpotOrderRestClient.GetOrderTradesAsync(GetOrderTradesRequest request, CancellationToken ct) { if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult>(Exchange, new ArgumentError("Invalid order id")); @@ -326,16 +394,16 @@ async Task>> ISpotOrderRestClient }), nextToken); } - async Task> ISpotOrderRestClient.CancelOrderAsync(CancelOrderRequest request, CancellationToken ct = default) + async Task> ISpotOrderRestClient.CancelOrderAsync(CancelOrderRequest request, CancellationToken ct) { if (!long.TryParse(request.OrderId, out var orderId)) - return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); + return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); var order = await Trading.CancelOrderAsync(request.GetSymbol(FormatSymbol), orderId).ConfigureAwait(false); if (!order) - return order.AsExchangeResult(Exchange, default); + return order.AsExchangeResult(Exchange, default); - return order.AsExchangeResult(Exchange, new SharedOrderId(order.Data.Id.ToString())); + return order.AsExchangeResult(Exchange, new SharedId(order.Data.Id.ToString())); } private SharedOrderStatus ParseOrderStatus(OrderStatus status) @@ -363,5 +431,145 @@ private SharedOrderType ParseOrderType(SpotOrderType type) return null; } + + #endregion + + #region Asset client + + async Task>> IAssetRestClient.GetAssetsAsync(CancellationToken ct) + { + var assets = await Account.GetUserAssetsAsync(ct: ct).ConfigureAwait(false); + if (!assets) + return assets.AsExchangeResult>(Exchange, default); + + return assets.AsExchangeResult(Exchange, assets.Data.Select(x => new SharedAsset(x.Asset) + { + FullName = x.Name, + Networks = x.NetworkList.Select(x => new SharedAssetNetwork(x.Network) + { + FullName = x.Name, + MinConfirmations = x.MinConfirmations, + DepositEnabled = x.DepositEnabled, + MinWithdrawQuantity = x.WithdrawMin, + MaxWithdrawQuantity = x.WithdrawMax, + WithdrawEnabled = x.WithdrawEnabled, + WithdrawFee = x.WithdrawFee + }) + })); + } + + #endregion + + #region Deposit client + + async Task>> IDepositRestClient.GetDepositAddressesAsync(GetDepositAddressesRequest request, CancellationToken ct) + { + var depositAddresses = await Account.GetDepositAddressAsync(request.Asset, request.Network).ConfigureAwait(false); + if (!depositAddresses) + return depositAddresses.AsExchangeResult>(Exchange, default); + + return depositAddresses.AsExchangeResult>(Exchange, new[] { new SharedDepositAddress(depositAddresses.Data.Asset, depositAddresses.Data.Address) + { + Tag = depositAddresses.Data.Tag + } + }); + } + + async Task>> IDepositRestClient.GetDepositsAsync(GetDepositsRequest request, INextPageToken? pageToken, CancellationToken ct) + { + // Determine page token + int? offset = null; + if (pageToken is OffsetToken offsetToken) + offset = offsetToken.Offset; + + // Get data + var deposits = await Account.GetDepositHistoryAsync( + request.Asset, + startTime: request.Filter?.StartTime, + endTime: request.Filter?.EndTime, + limit: request.Filter?.Limit ?? 100, + offset: offset, + ct: ct).ConfigureAwait(false); + if (!deposits) + return deposits.AsExchangeResult>(Exchange, default); + + // Determine next token + OffsetToken? nextToken = null; + if (deposits.Data.Count() == (request.Filter?.Limit ?? 100)) + nextToken = new OffsetToken((offset ?? 0) + deposits.Data.Count()); + + return deposits.AsExchangeResult(Exchange, deposits.Data.Select(x => new SharedDeposit(x.Asset, x.Quantity, x.Status == DepositStatus.Success, x.InsertTime) + { + Confirmations = x.Confirmations.Contains("/") ? int.Parse(x.Confirmations.Split(new[] { "/" }, StringSplitOptions.RemoveEmptyEntries)[0]) : null, + Network = x.Network, + TransactionId = x.TransactionId, + Tag = x.AddressTag + }), nextToken); + } + + #endregion + + #region Withdrawal client + + async Task>> IWithdrawalRestClient.GetWithdrawalsAsync(GetWithdrawalsRequest request, INextPageToken? pageToken, CancellationToken ct) + { + // Determine page token + int? offset = null; + if (pageToken is OffsetToken offsetToken) + offset = offsetToken.Offset; + + // Get data + var withdrawals = await Account.GetWithdrawalHistoryAsync( + request.Asset, + startTime: request.Filter?.StartTime, + endTime: request.Filter?.EndTime, + limit: request.Filter?.Limit ?? 100, + offset: offset, + ct: ct).ConfigureAwait(false); + if (!withdrawals) + return withdrawals.AsExchangeResult>(Exchange, default); + + // Determine next token + OffsetToken nextToken; + if (withdrawals.Data.Count() == (request.Filter?.Limit ?? 100)) + nextToken = new OffsetToken((offset ?? 0) + withdrawals.Data.Count()); + + return withdrawals.AsExchangeResult(Exchange, withdrawals.Data.Select(x => new SharedWithdrawal(x.Asset, x.Address, x.Quantity, x.Status == WithdrawalStatus.Completed, x.ApplyTime) + { + Confirmations = x.ConfirmTimes, + Network = x.Network, + Tag = x.AddressTag, + TransactionId = x.TransactionId, + Fee = x.TransactionFee + })); + } + + #endregion + + #region Withdraw client + + WithdrawOptions IWithdrawRestClient.WithdrawOptions { get; } = new WithdrawOptions(); + + async Task > IWithdrawRestClient.WithdrawAsync(WithdrawRequest request, CancellationToken ct) + { + var validationError = ((IWithdrawRestClient)this).WithdrawOptions.Validate(request); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + + // Get data + var withdrawal = await Account.WithdrawAsync( + request.Asset, + request.Address, + request.Quantity, + network: request.Network, + addressTag: request.AddressTag, + ct: ct).ConfigureAwait(false); + if (!withdrawal) + return withdrawal.AsExchangeResult(Exchange, default); + + return withdrawal.AsExchangeResult(Exchange, new SharedId(withdrawal.Data.Id)); + } + + #endregion } } diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs index d1d87fc3d..199928a0c 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -17,17 +17,10 @@ internal partial class BinanceRestClientUsdFuturesApi : IBinanceRestClientUsdFut { public string Exchange => BinanceExchange.ExchangeName; - //GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } - // = new GetKlinesOptions( - // true, - // false, - // SharedKlineInterval.FiveMinutes, - // SharedKlineInterval.FifteenMinutes, - // SharedKlineInterval.OneHour, - // SharedKlineInterval.FifteenMinutes, - // SharedKlineInterval.OneDay, - // SharedKlineInterval.OneWeek, - // SharedKlineInterval.OneMonth); + GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(true) + { + MaxRequestDataPoints = 1000 + }; async Task>> IKlineRestClient.GetKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, CancellationToken ct) { @@ -89,7 +82,7 @@ async Task> ITickerRestClient.GetTickerAsync(Get return result.AsExchangeResult(Exchange, new SharedTicker(result.Data.Symbol, result.Data.LastPrice, result.Data.HighPrice, result.Data.LowPrice)); } - async Task>> ITickerRestClient.GetTickersAsync(SharedRequest request, CancellationToken ct) + async Task>> ITickerRestClient.GetTickersAsync(ApiType? apiType, CancellationToken ct) { var result = await ExchangeData.GetTickersAsync(ct: ct).ConfigureAwait(false); if (!result) @@ -98,16 +91,17 @@ async Task>> ITickerRestClient.GetTi return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice))); } + GetRecentTradesOptions IRecentTradeRestClient.GetRecentTradesOptions { get; } = new GetRecentTradesOptions(1000); async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, CancellationToken ct) { - var result = await ExchangeData.GetAggregatedTradeHistoryAsync( + var result = await ExchangeData.GetRecentTradesAsync( request.GetSymbol((baseAsset, quoteAsset, apiType) => FormatSymbol(baseAsset, quoteAsset)), // Don't pass api type; need only the pair limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult< IEnumerable>(Exchange, default); - return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedTrade(x.Quantity, x.Price, x.TradeTime))); + return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedTrade(x.BaseQuantity, x.Price, x.TradeTime))); } } } diff --git a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs index 1365109d3..5ba8a6d3f 100644 --- a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs @@ -6,12 +6,18 @@ namespace Binance.Net.Interfaces.Clients.SpotApi { public interface IBinanceRestClientSpotApiShared: - ITickerRestClient, - ISpotSymbolRestClient, + IAssetRestClient, + IBalanceRestClient, + IDepositRestClient, IKlineRestClient, + IOrderBookRestClient, IRecentTradeRestClient, - IBalanceRestClient, - ISpotOrderRestClient + ISpotOrderRestClient, + ISpotSymbolRestClient, + ITickerRestClient, + ITradeHistoryRestClient, + IWithdrawalRestClient, + IWithdrawRestClient { } } diff --git a/Binance.Net/Objects/Models/Spot/BinanceWithdrawalPlaced.cs b/Binance.Net/Objects/Models/Spot/BinanceWithdrawalPlaced.cs index 8c03bb43b..cff1f5b2b 100644 --- a/Binance.Net/Objects/Models/Spot/BinanceWithdrawalPlaced.cs +++ b/Binance.Net/Objects/Models/Spot/BinanceWithdrawalPlaced.cs @@ -9,6 +9,6 @@ public record BinanceWithdrawalPlaced /// The id /// [JsonPropertyName("id")] - public string? Id { get; set; } + public string Id { get; set; } } } From b1d61dc338c4caf44faecb04e01a1a59ccd2a8ca Mon Sep 17 00:00:00 2001 From: JKorf Date: Tue, 20 Aug 2024 16:56:07 +0200 Subject: [PATCH 13/54] wip --- .../SpotApi/BinanceRestClientSpotApiShared.cs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index a6b06bb81..b5dbc83f8 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -172,11 +172,12 @@ async Task> IOrderBookRestClient.GetOrderBook return result.AsExchangeResult(Exchange, new SharedOrderBook(result.Data.Asks, result.Data.Bids)); } + #endregion #region Balance Client - async Task>> IBalanceRestClient.GetBalancesAsync(ApiType? apiType, CancellationToken ct) + async Task>> IBalanceRestClient.GetBalancesAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { var result = await Account.GetBalancesAsync(ct: ct).ConfigureAwait(false); if (!result) @@ -208,7 +209,7 @@ async Task>> IBalanceRestClient.Get SharedQuantityType.Both, SharedQuantityType.Both)); - async Task> ISpotOrderRestClient.PlaceOrderAsync(PlaceSpotOrderRequest request, CancellationToken ct) + async Task> ISpotOrderRestClient.PlaceOrderAsync(PlaceSpotOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { if (request.OrderType == SharedOrderType.Other) throw new ArgumentException("OrderType can't be `Other`", nameof(request.OrderType)); @@ -232,7 +233,7 @@ async Task> ISpotOrderRestClient.PlaceOrderAsync(Pla return result.AsExchangeResult(Exchange, new SharedId(result.Data.Id.ToString())); } - async Task> ISpotOrderRestClient.GetOrderAsync(GetOrderRequest request, CancellationToken ct) + async Task> ISpotOrderRestClient.GetOrderAsync(GetOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); @@ -261,7 +262,7 @@ async Task> ISpotOrderRestClient.GetOrderAsyn }); } - async Task>> ISpotOrderRestClient.GetOpenOrdersAsync(GetSpotOpenOrdersRequest request, CancellationToken ct) + async Task>> ISpotOrderRestClient.GetOpenOrdersAsync(GetSpotOpenOrdersRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { string? symbol = null; if (request.BaseAsset != null && request.QuoteAsset != null) @@ -291,7 +292,7 @@ async Task>> ISpotOrderRestClient })); } - async Task>> ISpotOrderRestClient.GetClosedOrdersAsync(GetSpotClosedOrdersRequest request, INextPageToken? pageToken, CancellationToken ct) + async Task>> ISpotOrderRestClient.GetClosedOrdersAsync(GetSpotClosedOrdersRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { // Determine page token DateTime? fromTimestamp = null; @@ -331,7 +332,7 @@ async Task>> ISpotOrderRestClient })); } - async Task>> ISpotOrderRestClient.GetOrderTradesAsync(GetOrderTradesRequest request, CancellationToken ct) + async Task>> ISpotOrderRestClient.GetOrderTradesAsync(GetOrderTradesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult>(Exchange, new ArgumentError("Invalid order id")); @@ -356,7 +357,7 @@ async Task>> ISpotOrderRestClient })); } - async Task>> ISpotOrderRestClient.GetUserTradesAsync(GetUserTradesRequest request, INextPageToken? pageToken, CancellationToken ct) + async Task>> ISpotOrderRestClient.GetUserTradesAsync(GetUserTradesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { // Determine page token long? fromId = null; @@ -394,7 +395,7 @@ async Task>> ISpotOrderRestClient }), nextToken); } - async Task> ISpotOrderRestClient.CancelOrderAsync(CancelOrderRequest request, CancellationToken ct) + async Task> ISpotOrderRestClient.CancelOrderAsync(CancelOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); @@ -550,7 +551,7 @@ async Task>> IWithdrawalRestClie WithdrawOptions IWithdrawRestClient.WithdrawOptions { get; } = new WithdrawOptions(); - async Task > IWithdrawRestClient.WithdrawAsync(WithdrawRequest request, CancellationToken ct) + async Task > IWithdrawRestClient.WithdrawAsync(WithdrawRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((IWithdrawRestClient)this).WithdrawOptions.Validate(request); if (validationError != null) From b029a83e174bfb6b8b28211624aa4ac150adb820 Mon Sep 17 00:00:00 2001 From: JKorf Date: Thu, 22 Aug 2024 15:33:49 +0200 Subject: [PATCH 14/54] wip --- .../BinanceRestClientCoinFuturesApiShared.cs | 12 +++---- .../SpotApi/BinanceRestClientSpotApiShared.cs | 36 ++++++++++++------- .../BinanceSocketClientSpotApiShared.cs | 6 ++-- .../BinanceRestClientUsdFuturesApiShared.cs | 12 +++---- 4 files changed, 38 insertions(+), 28 deletions(-) diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs index a9ee072de..4688fae46 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -13,12 +13,12 @@ internal partial class BinanceRestClientCoinFuturesApi : IBinanceRestClientCoinF { public string Exchange => BinanceExchange.ExchangeName; - GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(true) + GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(true, false) { MaxRequestDataPoints = 1000 }; - async Task>> IKlineRestClient.GetKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, CancellationToken ct) + async Task>> IKlineRestClient.GetKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { var interval = (Enums.KlineInterval)request.Interval; if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) @@ -52,7 +52,7 @@ async Task>> IKlineRestClient.GetKlin return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)), nextToken); } - async Task>> IFuturesSymbolRestClient.GetSymbolsAsync(SharedRequest request, CancellationToken ct) + async Task>> IFuturesSymbolRestClient.GetFuturesSymbolsAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { var result = await ExchangeData.GetExchangeInfoAsync(ct).ConfigureAwait(false); if (!result) @@ -69,7 +69,7 @@ async Task>> IFuturesSymbolRe })); } - async Task> ITickerRestClient.GetTickerAsync(GetTickerRequest request, CancellationToken ct) + async Task> ITickerRestClient.GetTickerAsync(GetTickerRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { var result = await ExchangeData.GetTickersAsync(symbol: request.GetSymbol(FormatSymbol), ct: ct).ConfigureAwait(false); if (!result) @@ -79,7 +79,7 @@ async Task> ITickerRestClient.GetTickerAsync(Get return result.AsExchangeResult(Exchange, new SharedTicker(ticker.Symbol, ticker.LastPrice, ticker.HighPrice, ticker.LowPrice)); } - async Task>> ITickerRestClient.GetTickersAsync(ApiType? apiType, CancellationToken ct) + async Task>> ITickerRestClient.GetTickersAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { var result = await ExchangeData.GetTickersAsync(ct: ct).ConfigureAwait(false); if (!result) @@ -89,7 +89,7 @@ async Task>> ITickerRestClient.GetTi } GetRecentTradesOptions IRecentTradeRestClient.GetRecentTradesOptions { get; } = new GetRecentTradesOptions(1000); - async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, CancellationToken ct) + async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { var result = await ExchangeData.GetRecentTradesAsync( request.GetSymbol(FormatSymbol), diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index b5dbc83f8..d68e59299 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -16,12 +16,12 @@ internal partial class BinanceRestClientSpotApi : IBinanceRestClientSpotApiShare #region Klines Client - GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(true) + GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(true, false) { MaxRequestDataPoints = 1000 }; - async Task>> IKlineRestClient.GetKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, CancellationToken ct) + async Task>> IKlineRestClient.GetKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { var interval = (Enums.KlineInterval)request.Interval; if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) @@ -64,7 +64,7 @@ async Task>> IKlineRestClient.GetKlin #region Spot Symbol client - async Task>> ISpotSymbolRestClient.GetSpotSymbolsAsync(CancellationToken ct) + async Task>> ISpotSymbolRestClient.GetSpotSymbolsAsync(ExchangeParameters? exchangeParameters, CancellationToken ct) { var result = await ExchangeData.GetExchangeInfoAsync(ct).ConfigureAwait(false); if (!result) @@ -83,7 +83,7 @@ async Task>> ISpotSymbolRestClie #region Ticker client - async Task> ITickerRestClient.GetTickerAsync(GetTickerRequest request, CancellationToken ct) + async Task> ITickerRestClient.GetTickerAsync(GetTickerRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { var result = await ExchangeData.GetTickerAsync(request.GetSymbol(FormatSymbol), ct).ConfigureAwait(false); if (!result) @@ -92,7 +92,7 @@ async Task> ITickerRestClient.GetTickerAsync(Get return result.AsExchangeResult(Exchange, new SharedTicker(result.Data.Symbol, result.Data.LastPrice, result.Data.HighPrice, result.Data.LowPrice)); } - async Task>> ITickerRestClient.GetTickersAsync(ApiType? apiType, CancellationToken ct) + async Task>> ITickerRestClient.GetTickersAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { var result = await ExchangeData.GetTickersAsync(ct: ct).ConfigureAwait(false); if (!result) @@ -112,7 +112,7 @@ async Task>> ITickerRestClient.GetTi #region Recent Trades client GetRecentTradesOptions IRecentTradeRestClient.GetRecentTradesOptions { get; } = new GetRecentTradesOptions(1000); - async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, CancellationToken ct) + async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { // Get data var result = await ExchangeData.GetRecentTradesAsync( @@ -129,7 +129,7 @@ async Task>> IRecentTradeRestClient.G #region Trade History client - async Task>> ITradeHistoryRestClient.GetTradeHistoryAsync(GetTradeHistoryRequest request, INextPageToken? pageToken, CancellationToken ct) + async Task>> ITradeHistoryRestClient.GetTradeHistoryAsync(GetTradeHistoryRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { long? fromId = null; if (pageToken is FromIdToken token) @@ -157,7 +157,7 @@ async Task>> ITradeHistoryRestClient. #region Order Book client GetOrderBookOptions IOrderBookRestClient.GetOrderBookOptions { get; } = new GetOrderBookOptions(1, 5000); - async Task> IOrderBookRestClient.GetOrderBookAsync(GetOrderBookRequest request, CancellationToken ct) + async Task> IOrderBookRestClient.GetOrderBookAsync(GetOrderBookRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.Validate(request); if (validationError != null) @@ -176,9 +176,14 @@ async Task> IOrderBookRestClient.GetOrderBook #endregion #region Balance Client + EndpointOptions IBalanceRestClient.GetBalancesOptions { get; } = new EndpointOptions(true); async Task>> IBalanceRestClient.GetBalancesAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { + var validationError = ((IBalanceRestClient)this).GetBalancesOptions.ValidateRequest(Exchange, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + var result = await Account.GetBalancesAsync(ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult>(Exchange, default); @@ -266,7 +271,7 @@ async Task>> ISpotOrderRestClient { string? symbol = null; if (request.BaseAsset != null && request.QuoteAsset != null) - symbol = FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType); + symbol = FormatSymbol(request.BaseAsset, request.QuoteAsset, ApiType.Spot); var orders = await Trading.GetOpenOrdersAsync(symbol).ConfigureAwait(false); if (!orders) @@ -436,9 +441,14 @@ private SharedOrderType ParseOrderType(SpotOrderType type) #endregion #region Asset client + EndpointOptions IAssetRestClient.GetAssetsOptions { get; } = new EndpointOptions(true); - async Task>> IAssetRestClient.GetAssetsAsync(CancellationToken ct) + async Task>> IAssetRestClient.GetAssetsAsync(ExchangeParameters? exchangeParameters, CancellationToken ct) { + var validationError = ((IAssetRestClient)this).GetAssetsOptions.ValidateRequest(Exchange, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + var assets = await Account.GetUserAssetsAsync(ct: ct).ConfigureAwait(false); if (!assets) return assets.AsExchangeResult>(Exchange, default); @@ -463,7 +473,7 @@ async Task>> IAssetRestClient.GetAsse #region Deposit client - async Task>> IDepositRestClient.GetDepositAddressesAsync(GetDepositAddressesRequest request, CancellationToken ct) + async Task>> IDepositRestClient.GetDepositAddressesAsync(GetDepositAddressesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { var depositAddresses = await Account.GetDepositAddressAsync(request.Asset, request.Network).ConfigureAwait(false); if (!depositAddresses) @@ -476,7 +486,7 @@ async Task>> IDepositRestCli }); } - async Task>> IDepositRestClient.GetDepositsAsync(GetDepositsRequest request, INextPageToken? pageToken, CancellationToken ct) + async Task>> IDepositRestClient.GetDepositsAsync(GetDepositsRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { // Determine page token int? offset = null; @@ -512,7 +522,7 @@ async Task>> IDepositRestClient.Get #region Withdrawal client - async Task>> IWithdrawalRestClient.GetWithdrawalsAsync(GetWithdrawalsRequest request, INextPageToken? pageToken, CancellationToken ct) + async Task>> IWithdrawalRestClient.GetWithdrawalsAsync(GetWithdrawalsRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { // Determine page token int? offset = null; diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs index 53735da8d..4de2ea2ef 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs @@ -17,7 +17,7 @@ internal partial class BinanceSocketClientSpotApi : IBinanceSocketClientSpotApiS { public string Exchange => BinanceExchange.ExchangeName; - async Task> ITickersSocketClient.SubscribeToAllTickerUpdatesAsync(SharedRequest request, Action>> handler, CancellationToken ct) + async Task> ITickersSocketClient.SubscribeToAllTickerUpdatesAsync(ApiType? apiType, Action>> handler, CancellationToken ct) { var result = await ExchangeData.SubscribeToAllMiniTickerUpdatesAsync(update => handler(update.As(update.Data.Select(x => new SharedTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice)))), ct).ConfigureAwait(false); @@ -48,7 +48,7 @@ async Task> IBookTickerSocketClient.Subscribe return new ExchangeResult(Exchange, result); } - async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(SharedRequest request, Action>> handler, CancellationToken ct) + async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(ApiType? apiType, Action>> handler, CancellationToken ct) { var listenKey = await Account.StartUserStreamAsync().ConfigureAwait(false); if (!listenKey) @@ -61,7 +61,7 @@ async Task> IBalanceSocketClient.SubscribeToB return new ExchangeResult(Exchange, result); } - async Task> ISpotOrderSocketClient.SubscribeToOrderUpdatesAsync(SharedRequest request, Action>> handler, CancellationToken ct) + async Task> ISpotOrderSocketClient.SubscribeToSpotOrderUpdatesAsync(Action>> handler, CancellationToken ct) { var listenKey = await Account.StartUserStreamAsync().ConfigureAwait(false); if (!listenKey) diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs index 199928a0c..9256a5dc8 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -17,12 +17,12 @@ internal partial class BinanceRestClientUsdFuturesApi : IBinanceRestClientUsdFut { public string Exchange => BinanceExchange.ExchangeName; - GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(true) + GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(true, false) { MaxRequestDataPoints = 1000 }; - async Task>> IKlineRestClient.GetKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, CancellationToken ct) + async Task>> IKlineRestClient.GetKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { var interval = (Enums.KlineInterval)request.Interval; if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) @@ -56,7 +56,7 @@ async Task>> IKlineRestClient.GetKlin return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)), nextToken); } - async Task>> IFuturesSymbolRestClient.GetSymbolsAsync(SharedRequest request, CancellationToken ct) + async Task>> IFuturesSymbolRestClient.GetFuturesSymbolsAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { var result = await ExchangeData.GetExchangeInfoAsync(ct).ConfigureAwait(false); if (!result) @@ -73,7 +73,7 @@ async Task>> IFuturesSymbolRe })); } - async Task> ITickerRestClient.GetTickerAsync(GetTickerRequest request, CancellationToken ct) + async Task> ITickerRestClient.GetTickerAsync(GetTickerRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { var result = await ExchangeData.GetTickerAsync(request.GetSymbol(FormatSymbol), ct).ConfigureAwait(false); if (!result) @@ -82,7 +82,7 @@ async Task> ITickerRestClient.GetTickerAsync(Get return result.AsExchangeResult(Exchange, new SharedTicker(result.Data.Symbol, result.Data.LastPrice, result.Data.HighPrice, result.Data.LowPrice)); } - async Task>> ITickerRestClient.GetTickersAsync(ApiType? apiType, CancellationToken ct) + async Task>> ITickerRestClient.GetTickersAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { var result = await ExchangeData.GetTickersAsync(ct: ct).ConfigureAwait(false); if (!result) @@ -92,7 +92,7 @@ async Task>> ITickerRestClient.GetTi } GetRecentTradesOptions IRecentTradeRestClient.GetRecentTradesOptions { get; } = new GetRecentTradesOptions(1000); - async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, CancellationToken ct) + async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { var result = await ExchangeData.GetRecentTradesAsync( request.GetSymbol((baseAsset, quoteAsset, apiType) => FormatSymbol(baseAsset, quoteAsset)), // Don't pass api type; need only the pair From 83bb0872d8b39a9709a9ac545793758aa2d44509 Mon Sep 17 00:00:00 2001 From: JKorf Date: Sun, 25 Aug 2024 18:47:34 +0200 Subject: [PATCH 15/54] wip --- .../BinanceRestClientCoinFuturesApiShared.cs | 8 +- .../SpotApi/BinanceRestClientSpotApiShared.cs | 98 +++++++++++++++---- .../BinanceSocketClientSpotApiShared.cs | 4 +- .../BinanceRestClientUsdFuturesApiShared.cs | 8 +- 4 files changed, 91 insertions(+), 27 deletions(-) diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs index 4688fae46..990b2141d 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -69,6 +69,7 @@ async Task>> IFuturesSymbolRe })); } + EndpointOptions ITickerRestClient.GetTickerOptions { get; } = new EndpointOptions(false); async Task> ITickerRestClient.GetTickerAsync(GetTickerRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { var result = await ExchangeData.GetTickersAsync(symbol: request.GetSymbol(FormatSymbol), ct: ct).ConfigureAwait(false); @@ -76,19 +77,20 @@ async Task> ITickerRestClient.GetTickerAsync(Get return result.AsExchangeResult(Exchange, default); var ticker = result.Data.Single(); - return result.AsExchangeResult(Exchange, new SharedTicker(ticker.Symbol, ticker.LastPrice, ticker.HighPrice, ticker.LowPrice)); + return result.AsExchangeResult(Exchange, new SharedTicker(ticker.Symbol, ticker.LastPrice, ticker.HighPrice, ticker.LowPrice, ticker.Volume)); } + EndpointOptions ITickerRestClient.GetTickersOptions { get; } = new EndpointOptions(false); async Task>> ITickerRestClient.GetTickersAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { var result = await ExchangeData.GetTickersAsync(ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult>(Exchange, default); - return result.AsExchangeResult(Exchange, result.Data.Select( x => new SharedTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice))); + return result.AsExchangeResult(Exchange, result.Data.Select( x => new SharedTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume))); } - GetRecentTradesOptions IRecentTradeRestClient.GetRecentTradesOptions { get; } = new GetRecentTradesOptions(1000); + GetRecentTradesOptions IRecentTradeRestClient.GetRecentTradesOptions { get; } = new GetRecentTradesOptions(1000, false); async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { var result = await ExchangeData.GetRecentTradesAsync( diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index d68e59299..51b818c4f 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -27,7 +27,7 @@ async Task>> IKlineRestClient.GetKlin if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IKlineRestClient)this).GetKlinesOptions.Validate(request); + var validationError = ((IKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -63,9 +63,14 @@ async Task>> IKlineRestClient.GetKlin #endregion #region Spot Symbol client + EndpointOptions ISpotSymbolRestClient.GetSpotSymbolsOptions { get; } = new EndpointOptions(false); async Task>> ISpotSymbolRestClient.GetSpotSymbolsAsync(ExchangeParameters? exchangeParameters, CancellationToken ct) { + var validationError = ((ISpotSymbolRestClient)this).GetSpotSymbolsOptions.ValidateRequest(Exchange, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + var result = await ExchangeData.GetExchangeInfoAsync(ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult>(Exchange, default); @@ -83,37 +88,45 @@ async Task>> ISpotSymbolRestClie #region Ticker client + EndpointOptions ITickerRestClient.GetTickerOptions { get; } = new EndpointOptions(false); async Task> ITickerRestClient.GetTickerAsync(GetTickerRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { + var validationError = ((ITickerRestClient)this).GetTickerOptions.ValidateRequest(Exchange, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + var result = await ExchangeData.GetTickerAsync(request.GetSymbol(FormatSymbol), ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); - return result.AsExchangeResult(Exchange, new SharedTicker(result.Data.Symbol, result.Data.LastPrice, result.Data.HighPrice, result.Data.LowPrice)); + return result.AsExchangeResult(Exchange, new SharedTicker(result.Data.Symbol, result.Data.LastPrice, result.Data.HighPrice, result.Data.LowPrice, result.Data.Volume)); } + EndpointOptions ITickerRestClient.GetTickersOptions { get; } = new EndpointOptions(false); async Task>> ITickerRestClient.GetTickersAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { + var validationError = ((ITickerRestClient)this).GetTickerOptions.ValidateRequest(Exchange, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + var result = await ExchangeData.GetTickersAsync(ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult>(Exchange, default); - return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice) - { - Symbol = x.Symbol, - HighPrice = x.HighPrice, - LastPrice = x.LastPrice, - LowPrice = x.LowPrice, - })); + return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume))); } #endregion #region Recent Trades client - GetRecentTradesOptions IRecentTradeRestClient.GetRecentTradesOptions { get; } = new GetRecentTradesOptions(1000); + GetRecentTradesOptions IRecentTradeRestClient.GetRecentTradesOptions { get; } = new GetRecentTradesOptions(1000, false); async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { + var validationError = ((IRecentTradeRestClient)this).GetRecentTradesOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + // Get data var result = await ExchangeData.GetRecentTradesAsync( request.GetSymbol(FormatSymbol), @@ -128,9 +141,14 @@ async Task>> IRecentTradeRestClient.G #endregion #region Trade History client - + PaginatedEndpointOptions ITradeHistoryRestClient.GetTradeHistoryOptions { get; } = new PaginatedEndpointOptions(true, false); + async Task>> ITradeHistoryRestClient.GetTradeHistoryAsync(GetTradeHistoryRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { + var validationError = ((ITradeHistoryRestClient)this).GetTradeHistoryOptions.ValidateRequest(Exchange, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + long? fromId = null; if (pageToken is FromIdToken token) fromId = long.Parse(token.FromToken); @@ -156,10 +174,10 @@ async Task>> ITradeHistoryRestClient. #endregion #region Order Book client - GetOrderBookOptions IOrderBookRestClient.GetOrderBookOptions { get; } = new GetOrderBookOptions(1, 5000); + GetOrderBookOptions IOrderBookRestClient.GetOrderBookOptions { get; } = new GetOrderBookOptions(1, 5000, false); async Task> IOrderBookRestClient.GetOrderBookAsync(GetOrderBookRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.Validate(request); + var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.ValidateRequest(Exchange, request, exchangeParameters); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -214,12 +232,9 @@ async Task>> IBalanceRestClient.Get SharedQuantityType.Both, SharedQuantityType.Both)); - async Task> ISpotOrderRestClient.PlaceOrderAsync(PlaceSpotOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> ISpotOrderRestClient.PlaceSpotOrderAsync(PlaceSpotOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - if (request.OrderType == SharedOrderType.Other) - throw new ArgumentException("OrderType can't be `Other`", nameof(request.OrderType)); - - var validationError = ((ISpotOrderRestClient)this).PlaceSpotOrderOptions.Validate(request); + var validationError = ((ISpotOrderRestClient)this).PlaceSpotOrderOptions.ValidateRequest(Exchange, request, exchangeParameters); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -238,8 +253,13 @@ async Task> ISpotOrderRestClient.PlaceOrderAsync(Pla return result.AsExchangeResult(Exchange, new SharedId(result.Data.Id.ToString())); } + EndpointOptions ISpotOrderRestClient.GetOrderOptions { get; } = new EndpointOptions(true); async Task> ISpotOrderRestClient.GetOrderAsync(GetOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { + var validationError = ((ISpotOrderRestClient)this).GetOrderOptions.ValidateRequest(Exchange, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); @@ -267,8 +287,13 @@ async Task> ISpotOrderRestClient.GetOrderAsyn }); } + EndpointOptions ISpotOrderRestClient.GetOpenOrdersOptions { get; } = new EndpointOptions(true); async Task>> ISpotOrderRestClient.GetOpenOrdersAsync(GetSpotOpenOrdersRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { + var validationError = ((ISpotOrderRestClient)this).GetOpenOrdersOptions.ValidateRequest(Exchange, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + string? symbol = null; if (request.BaseAsset != null && request.QuoteAsset != null) symbol = FormatSymbol(request.BaseAsset, request.QuoteAsset, ApiType.Spot); @@ -297,8 +322,13 @@ async Task>> ISpotOrderRestClient })); } + PaginatedEndpointOptions ISpotOrderRestClient.GetClosedOrdersOptions { get; } = new PaginatedEndpointOptions(true, true); async Task>> ISpotOrderRestClient.GetClosedOrdersAsync(GetSpotClosedOrdersRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { + var validationError = ((ISpotOrderRestClient)this).GetClosedOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + // Determine page token DateTime? fromTimestamp = null; if (pageToken is DateTimeToken dateTimeToken) @@ -337,8 +367,13 @@ async Task>> ISpotOrderRestClient })); } + EndpointOptions ISpotOrderRestClient.GetOrderTradesOptions { get; } = new EndpointOptions(true); async Task>> ISpotOrderRestClient.GetOrderTradesAsync(GetOrderTradesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { + var validationError = ((ISpotOrderRestClient)this).GetOrderTradesOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult>(Exchange, new ArgumentError("Invalid order id")); @@ -362,8 +397,13 @@ async Task>> ISpotOrderRestClient })); } + PaginatedEndpointOptions ISpotOrderRestClient.GetUserTradesOptions { get; } = new PaginatedEndpointOptions(true, true); async Task>> ISpotOrderRestClient.GetUserTradesAsync(GetUserTradesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { + var validationError = ((ISpotOrderRestClient)this).GetUserTradesOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + // Determine page token long? fromId = null; if (pageToken is FromIdToken fromIdToken) @@ -400,8 +440,13 @@ async Task>> ISpotOrderRestClient }), nextToken); } + EndpointOptions ISpotOrderRestClient.CancelOrderOptions { get; } = new EndpointOptions(true); async Task> ISpotOrderRestClient.CancelOrderAsync(CancelOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { + var validationError = ((ISpotOrderRestClient)this).CancelOrderOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); @@ -473,8 +518,13 @@ async Task>> IAssetRestClient.GetAsse #region Deposit client + EndpointOptions IDepositRestClient.GetDepositAddressesOptions { get; } = new EndpointOptions(true); async Task>> IDepositRestClient.GetDepositAddressesAsync(GetDepositAddressesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { + var validationError = ((IDepositRestClient)this).GetDepositAddressesOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + var depositAddresses = await Account.GetDepositAddressAsync(request.Asset, request.Network).ConfigureAwait(false); if (!depositAddresses) return depositAddresses.AsExchangeResult>(Exchange, default); @@ -486,8 +536,13 @@ async Task>> IDepositRestCli }); } + PaginatedEndpointOptions IDepositRestClient.GetDepositsOptions { get; } = new PaginatedEndpointOptions(true, true); async Task>> IDepositRestClient.GetDepositsAsync(GetDepositsRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { + var validationError = ((IDepositRestClient)this).GetDepositsOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + // Determine page token int? offset = null; if (pageToken is OffsetToken offsetToken) @@ -522,8 +577,13 @@ async Task>> IDepositRestClient.Get #region Withdrawal client + PaginatedEndpointOptions IWithdrawalRestClient.GetWithdrawalsOptions { get; } = new PaginatedEndpointOptions(true, true); async Task>> IWithdrawalRestClient.GetWithdrawalsAsync(GetWithdrawalsRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { + var validationError = ((IWithdrawalRestClient)this).GetWithdrawalsOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + // Determine page token int? offset = null; if (pageToken is OffsetToken offsetToken) @@ -563,7 +623,7 @@ async Task>> IWithdrawalRestClie async Task > IWithdrawRestClient.WithdrawAsync(WithdrawRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IWithdrawRestClient)this).WithdrawOptions.Validate(request); + var validationError = ((IWithdrawRestClient)this).WithdrawOptions.ValidateRequest(Exchange, request, exchangeParameters); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs index 4de2ea2ef..f89b976dd 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs @@ -19,7 +19,7 @@ internal partial class BinanceSocketClientSpotApi : IBinanceSocketClientSpotApiS async Task> ITickersSocketClient.SubscribeToAllTickerUpdatesAsync(ApiType? apiType, Action>> handler, CancellationToken ct) { - var result = await ExchangeData.SubscribeToAllMiniTickerUpdatesAsync(update => handler(update.As(update.Data.Select(x => new SharedTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice)))), ct).ConfigureAwait(false); + var result = await ExchangeData.SubscribeToAllMiniTickerUpdatesAsync(update => handler(update.As(update.Data.Select(x => new SharedTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume)))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); } @@ -27,7 +27,7 @@ async Task> ITickersSocketClient.SubscribeToA async Task> ITickerSocketClient.SubscribeToTickerUpdatesAsync(TickerSubscribeRequest request, Action> handler, CancellationToken ct) { var symbol = FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType); - var result = await ExchangeData.SubscribeToMiniTickerUpdatesAsync(symbol, update => handler(update.As(new SharedTicker(update.Data.Symbol, update.Data.LastPrice, update.Data.HighPrice, update.Data.LowPrice))), ct).ConfigureAwait(false); + var result = await ExchangeData.SubscribeToMiniTickerUpdatesAsync(symbol, update => handler(update.As(new SharedTicker(update.Data.Symbol, update.Data.LastPrice, update.Data.HighPrice, update.Data.LowPrice, update.Data.Volume))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); } diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs index 9256a5dc8..91f7bcd23 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -73,25 +73,27 @@ async Task>> IFuturesSymbolRe })); } + EndpointOptions ITickerRestClient.GetTickerOptions { get; } = new EndpointOptions(false); async Task> ITickerRestClient.GetTickerAsync(GetTickerRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { var result = await ExchangeData.GetTickerAsync(request.GetSymbol(FormatSymbol), ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); - return result.AsExchangeResult(Exchange, new SharedTicker(result.Data.Symbol, result.Data.LastPrice, result.Data.HighPrice, result.Data.LowPrice)); + return result.AsExchangeResult(Exchange, new SharedTicker(result.Data.Symbol, result.Data.LastPrice, result.Data.HighPrice, result.Data.LowPrice, result.Data.Volume)); } + EndpointOptions ITickerRestClient.GetTickersOptions { get; } = new EndpointOptions(false); async Task>> ITickerRestClient.GetTickersAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { var result = await ExchangeData.GetTickersAsync(ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult>(Exchange, default); - return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice))); + return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume))); } - GetRecentTradesOptions IRecentTradeRestClient.GetRecentTradesOptions { get; } = new GetRecentTradesOptions(1000); + GetRecentTradesOptions IRecentTradeRestClient.GetRecentTradesOptions { get; } = new GetRecentTradesOptions(1000, false); async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { var result = await ExchangeData.GetRecentTradesAsync( From a951021376c892b5c8fbeb4f5ce7602d13b89de4 Mon Sep 17 00:00:00 2001 From: JKorf Date: Sun, 25 Aug 2024 21:25:22 +0200 Subject: [PATCH 16/54] wip --- Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index 51b818c4f..8ac989abf 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -141,7 +141,7 @@ async Task>> IRecentTradeRestClient.G #endregion #region Trade History client - PaginatedEndpointOptions ITradeHistoryRestClient.GetTradeHistoryOptions { get; } = new PaginatedEndpointOptions(true, false); + GetTradeHistoryOptions ITradeHistoryRestClient.GetTradeHistoryOptions { get; } = new GetTradeHistoryOptions(true, false); async Task>> ITradeHistoryRestClient.GetTradeHistoryAsync(GetTradeHistoryRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { From 3c4c16abdd3110c1e92e0ea65ac3ac471cf8f1a2 Mon Sep 17 00:00:00 2001 From: JKorf Date: Wed, 28 Aug 2024 09:39:26 +0200 Subject: [PATCH 17/54] wip --- .../BinanceRestClientCoinFuturesApiShared.cs | 14 ++++++++++++- .../SpotApi/BinanceRestClientSpotApiShared.cs | 20 +++++++++---------- .../BinanceRestClientUsdFuturesApiShared.cs | 14 ++++++++++++- 3 files changed, 36 insertions(+), 12 deletions(-) diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs index 990b2141d..a2daa915c 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -24,6 +24,10 @@ async Task>> IKlineRestClient.GetKlin if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); + var validationError = ((IKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + // Determine page token DateTime? fromTimestamp = null; if (pageToken is DateTimeToken dateTimeToken) @@ -72,6 +76,10 @@ async Task>> IFuturesSymbolRe EndpointOptions ITickerRestClient.GetTickerOptions { get; } = new EndpointOptions(false); async Task> ITickerRestClient.GetTickerAsync(GetTickerRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { + var validationError = ((ITickerRestClient)this).GetTickerOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + var result = await ExchangeData.GetTickersAsync(symbol: request.GetSymbol(FormatSymbol), ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -80,7 +88,7 @@ async Task> ITickerRestClient.GetTickerAsync(Get return result.AsExchangeResult(Exchange, new SharedTicker(ticker.Symbol, ticker.LastPrice, ticker.HighPrice, ticker.LowPrice, ticker.Volume)); } - EndpointOptions ITickerRestClient.GetTickersOptions { get; } = new EndpointOptions(false); + EndpointOptions ITickerRestClient.GetTickersOptions { get; } = new EndpointOptions("GetTickersRequest", false); async Task>> ITickerRestClient.GetTickersAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { var result = await ExchangeData.GetTickersAsync(ct: ct).ConfigureAwait(false); @@ -93,6 +101,10 @@ async Task>> ITickerRestClient.GetTi GetRecentTradesOptions IRecentTradeRestClient.GetRecentTradesOptions { get; } = new GetRecentTradesOptions(1000, false); async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { + var validationError = ((IRecentTradeRestClient)this).GetRecentTradesOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + var result = await ExchangeData.GetRecentTradesAsync( request.GetSymbol(FormatSymbol), limit: request.Limit, diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index 8ac989abf..bb67b3692 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -63,7 +63,7 @@ async Task>> IKlineRestClient.GetKlin #endregion #region Spot Symbol client - EndpointOptions ISpotSymbolRestClient.GetSpotSymbolsOptions { get; } = new EndpointOptions(false); + EndpointOptions ISpotSymbolRestClient.GetSpotSymbolsOptions { get; } = new EndpointOptions("GetSpotSymbolsRequest", false); async Task>> ISpotSymbolRestClient.GetSpotSymbolsAsync(ExchangeParameters? exchangeParameters, CancellationToken ct) { @@ -91,7 +91,7 @@ async Task>> ISpotSymbolRestClie EndpointOptions ITickerRestClient.GetTickerOptions { get; } = new EndpointOptions(false); async Task> ITickerRestClient.GetTickerAsync(GetTickerRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ITickerRestClient)this).GetTickerOptions.ValidateRequest(Exchange, exchangeParameters); + var validationError = ((ITickerRestClient)this).GetTickerOptions.ValidateRequest(Exchange, request, exchangeParameters); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -102,7 +102,7 @@ async Task> ITickerRestClient.GetTickerAsync(Get return result.AsExchangeResult(Exchange, new SharedTicker(result.Data.Symbol, result.Data.LastPrice, result.Data.HighPrice, result.Data.LowPrice, result.Data.Volume)); } - EndpointOptions ITickerRestClient.GetTickersOptions { get; } = new EndpointOptions(false); + EndpointOptions ITickerRestClient.GetTickersOptions { get; } = new EndpointOptions("GetTickersRequest", false); async Task>> ITickerRestClient.GetTickersAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((ITickerRestClient)this).GetTickerOptions.ValidateRequest(Exchange, exchangeParameters); @@ -145,7 +145,7 @@ async Task>> IRecentTradeRestClient.G async Task>> ITradeHistoryRestClient.GetTradeHistoryAsync(GetTradeHistoryRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ITradeHistoryRestClient)this).GetTradeHistoryOptions.ValidateRequest(Exchange, exchangeParameters); + var validationError = ((ITradeHistoryRestClient)this).GetTradeHistoryOptions.ValidateRequest(Exchange, request, exchangeParameters); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -194,7 +194,7 @@ async Task> IOrderBookRestClient.GetOrderBook #endregion #region Balance Client - EndpointOptions IBalanceRestClient.GetBalancesOptions { get; } = new EndpointOptions(true); + EndpointOptions IBalanceRestClient.GetBalancesOptions { get; } = new EndpointOptions("GetBalancesRequest", true); async Task>> IBalanceRestClient.GetBalancesAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { @@ -256,7 +256,7 @@ async Task> ISpotOrderRestClient.PlaceSpotOrderAsync EndpointOptions ISpotOrderRestClient.GetOrderOptions { get; } = new EndpointOptions(true); async Task> ISpotOrderRestClient.GetOrderAsync(GetOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetOrderOptions.ValidateRequest(Exchange, exchangeParameters); + var validationError = ((ISpotOrderRestClient)this).GetOrderOptions.ValidateRequest(Exchange, request, exchangeParameters); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -290,7 +290,7 @@ async Task> ISpotOrderRestClient.GetOrderAsyn EndpointOptions ISpotOrderRestClient.GetOpenOrdersOptions { get; } = new EndpointOptions(true); async Task>> ISpotOrderRestClient.GetOpenOrdersAsync(GetSpotOpenOrdersRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetOpenOrdersOptions.ValidateRequest(Exchange, exchangeParameters); + var validationError = ((ISpotOrderRestClient)this).GetOpenOrdersOptions.ValidateRequest(Exchange, request,exchangeParameters); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -486,7 +486,7 @@ private SharedOrderType ParseOrderType(SpotOrderType type) #endregion #region Asset client - EndpointOptions IAssetRestClient.GetAssetsOptions { get; } = new EndpointOptions(true); + EndpointOptions IAssetRestClient.GetAssetsOptions { get; } = new EndpointOptions("GetAssetsRequest",true); async Task>> IAssetRestClient.GetAssetsAsync(ExchangeParameters? exchangeParameters, CancellationToken ct) { @@ -536,7 +536,7 @@ async Task>> IDepositRestCli }); } - PaginatedEndpointOptions IDepositRestClient.GetDepositsOptions { get; } = new PaginatedEndpointOptions(true, true); + GetDepositsOptions IDepositRestClient.GetDepositsOptions { get; } = new GetDepositsOptions(true, true); async Task>> IDepositRestClient.GetDepositsAsync(GetDepositsRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((IDepositRestClient)this).GetDepositsOptions.ValidateRequest(Exchange, request, exchangeParameters); @@ -577,7 +577,7 @@ async Task>> IDepositRestClient.Get #region Withdrawal client - PaginatedEndpointOptions IWithdrawalRestClient.GetWithdrawalsOptions { get; } = new PaginatedEndpointOptions(true, true); + GetWithdrawalsOptions IWithdrawalRestClient.GetWithdrawalsOptions { get; } = new GetWithdrawalsOptions(true, true); async Task>> IWithdrawalRestClient.GetWithdrawalsAsync(GetWithdrawalsRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((IWithdrawalRestClient)this).GetWithdrawalsOptions.ValidateRequest(Exchange, request, exchangeParameters); diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs index 91f7bcd23..47d680a24 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -28,6 +28,10 @@ async Task>> IKlineRestClient.GetKlin if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); + var validationError = ((IKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + // Determine page token DateTime? fromTimestamp = null; if (pageToken is DateTimeToken dateTimeToken) @@ -76,6 +80,10 @@ async Task>> IFuturesSymbolRe EndpointOptions ITickerRestClient.GetTickerOptions { get; } = new EndpointOptions(false); async Task> ITickerRestClient.GetTickerAsync(GetTickerRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { + var validationError = ((ITickerRestClient)this).GetTickerOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + var result = await ExchangeData.GetTickerAsync(request.GetSymbol(FormatSymbol), ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -83,7 +91,7 @@ async Task> ITickerRestClient.GetTickerAsync(Get return result.AsExchangeResult(Exchange, new SharedTicker(result.Data.Symbol, result.Data.LastPrice, result.Data.HighPrice, result.Data.LowPrice, result.Data.Volume)); } - EndpointOptions ITickerRestClient.GetTickersOptions { get; } = new EndpointOptions(false); + EndpointOptions ITickerRestClient.GetTickersOptions { get; } = new EndpointOptions("GetTickersRequest", false); async Task>> ITickerRestClient.GetTickersAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { var result = await ExchangeData.GetTickersAsync(ct: ct).ConfigureAwait(false); @@ -96,6 +104,10 @@ async Task>> ITickerRestClient.GetTi GetRecentTradesOptions IRecentTradeRestClient.GetRecentTradesOptions { get; } = new GetRecentTradesOptions(1000, false); async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { + var validationError = ((IRecentTradeRestClient)this).GetRecentTradesOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + var result = await ExchangeData.GetRecentTradesAsync( request.GetSymbol((baseAsset, quoteAsset, apiType) => FormatSymbol(baseAsset, quoteAsset)), // Don't pass api type; need only the pair limit: request.Limit, From 742a28c3bfab07e3cbcd8ed675a06db51fd09d3f Mon Sep 17 00:00:00 2001 From: JKorf Date: Sun, 1 Sep 2024 22:27:45 +0200 Subject: [PATCH 18/54] wip --- .../BinanceRestClientCoinFuturesApi.cs | 3 +- .../BinanceRestClientCoinFuturesApiShared.cs | 530 +++++++++++++++++- .../SpotApi/BinanceRestClientSpotApiShared.cs | 100 ++-- .../BinanceRestClientUsdFuturesApi.cs | 2 +- .../BinanceRestClientUsdFuturesApiShared.cs | 527 ++++++++++++++++- .../ServiceCollectionExtensions.cs | 6 + .../IBinanceRestClientCoinFuturesApiShared.cs | 11 +- .../IBinanceRestClientSpotApiShared.cs | 2 +- .../IBinanceRestClientUsdFuturesApiShared.cs | 11 +- 9 files changed, 1144 insertions(+), 48 deletions(-) diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs index 080ddfdb9..982d6e4d8 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs @@ -77,7 +77,8 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden /// public override string FormatSymbol(string baseAsset, string quoteAsset, ApiType? futuresType = null) { - return (baseAsset + quoteAsset).ToUpper(CultureInfo.InvariantCulture) + "_PERP"; + var suffix = futuresType == null ? string.Empty : "_PERP"; + return baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + suffix; } 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 a2daa915c..4aa671836 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -1,4 +1,5 @@ using Binance.Net.Interfaces.Clients.CoinFuturesApi; +using Binance.Net.Enums; using CryptoExchange.Net.SharedApis.Enums; using CryptoExchange.Net.SharedApis.Interfaces; using CryptoExchange.Net.SharedApis.Models; @@ -6,6 +7,7 @@ using CryptoExchange.Net.SharedApis.Models.Rest; using CryptoExchange.Net.SharedApis.RequestModels; using CryptoExchange.Net.SharedApis.ResponseModels; +using CryptoExchange.Net.SharedApis.Interfaces.Rest; namespace Binance.Net.Clients.CoinFuturesApi { @@ -13,6 +15,8 @@ internal partial class BinanceRestClientCoinFuturesApi : IBinanceRestClientCoinF { public string Exchange => BinanceExchange.ExchangeName; + #region Klines client + GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(true, false) { MaxRequestDataPoints = 1000 @@ -34,7 +38,7 @@ async Task>> IKlineRestClient.GetKlin fromTimestamp = dateTimeToken.LastTime; var result = await ExchangeData.GetKlinesAsync( - request.GetSymbol(FormatSymbol), + request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), interval, fromTimestamp ?? request.Filter?.StartTime, request.Filter?.EndTime, @@ -56,8 +60,17 @@ async Task>> IKlineRestClient.GetKlin return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)), nextToken); } + #endregion + + #region Futures Symbol client + + EndpointOptions IFuturesSymbolRestClient.GetFuturesSymbolsOptions { get; } = new EndpointOptions("GetFuturesSymbolsRequest", false); async Task>> IFuturesSymbolRestClient.GetFuturesSymbolsAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { + var validationError = ((IFuturesSymbolRestClient)this).GetFuturesSymbolsOptions.ValidateRequest(Exchange, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + var result = await ExchangeData.GetExchangeInfoAsync(ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult>(Exchange, default); @@ -73,6 +86,10 @@ async Task>> IFuturesSymbolRe })); } + #endregion + + #region Ticker client + EndpointOptions ITickerRestClient.GetTickerOptions { get; } = new EndpointOptions(false); async Task> ITickerRestClient.GetTickerAsync(GetTickerRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { @@ -80,7 +97,7 @@ async Task> ITickerRestClient.GetTickerAsync(Get if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var result = await ExchangeData.GetTickersAsync(symbol: request.GetSymbol(FormatSymbol), ct: ct).ConfigureAwait(false); + var result = await ExchangeData.GetTickersAsync(symbol: request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -91,6 +108,10 @@ async Task> ITickerRestClient.GetTickerAsync(Get EndpointOptions ITickerRestClient.GetTickersOptions { get; } = new EndpointOptions("GetTickersRequest", false); async Task>> ITickerRestClient.GetTickersAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { + var validationError = ((ITickerRestClient)this).GetTickersOptions.ValidateRequest(Exchange, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + var result = await ExchangeData.GetTickersAsync(ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult>(Exchange, default); @@ -98,6 +119,10 @@ async Task>> ITickerRestClient.GetTi return result.AsExchangeResult(Exchange, result.Data.Select( x => new SharedTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume))); } + #endregion + + #region Recent Trade client + GetRecentTradesOptions IRecentTradeRestClient.GetRecentTradesOptions { get; } = new GetRecentTradesOptions(1000, false); async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { @@ -106,7 +131,7 @@ async Task>> IRecentTradeRestClient.G return new ExchangeWebResult>(Exchange, validationError); var result = await ExchangeData.GetRecentTradesAsync( - request.GetSymbol(FormatSymbol), + request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) @@ -114,5 +139,504 @@ async Task>> IRecentTradeRestClient.G return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedTrade(x.BaseQuantity, x.Price, x.TradeTime))); } + + #endregion + + #region Futures Order Client + + PlaceFuturesOrderOptions IFuturesOrderRestClient.PlaceFuturesOrderOptions { get; } = new PlaceFuturesOrderOptions( + new[] + { + SharedOrderType.Limit, + SharedOrderType.Market + }, + new[] + { + SharedTimeInForce.GoodTillCanceled, + SharedTimeInForce.ImmediateOrCancel, + SharedTimeInForce.FillOrKill + }, + new SharedQuantitySupport( + SharedQuantityType.BaseAssetQuantity, + SharedQuantityType.BaseAssetQuantity, + SharedQuantityType.BaseAssetQuantity, + SharedQuantityType.BaseAssetQuantity)); + + async Task> IFuturesOrderRestClient.PlaceFuturesOrderAsync(PlaceFuturesOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IFuturesOrderRestClient)this).PlaceFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + + var result = await Trading.PlaceOrderAsync( + request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), + request.Side == SharedOrderSide.Buy ? Enums.OrderSide.Buy : Enums.OrderSide.Sell, + request.OrderType == SharedOrderType.Limit ? Enums.FuturesOrderType.Limit : Enums.FuturesOrderType.Market, + quantity: request.Quantity, + price: request.Price, + positionSide: request.PositionSide == SharedPositionSide.Both ? PositionSide.Both : request.PositionSide == SharedPositionSide.Long ? PositionSide.Long: PositionSide.Short, + reduceOnly: request.ReduceOnly, + closePosition: request.ClosePosition, + newClientOrderId: request.ClientOrderId).ConfigureAwait(false); + + if (!result) + return result.AsExchangeResult(Exchange, default); + + return result.AsExchangeResult(Exchange, new SharedId(result.Data.Id.ToString())); + } + + EndpointOptions IFuturesOrderRestClient.GetFuturesOrderOptions { get; } = new EndpointOptions(true); + async Task> IFuturesOrderRestClient.GetFuturesOrderAsync(GetOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + + if (!long.TryParse(request.OrderId, out var orderId)) + return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); + + var order = await Trading.GetOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), orderId).ConfigureAwait(false); + if (!order) + return order.AsExchangeResult(Exchange, default); + + return order.AsExchangeResult(Exchange, new SharedFuturesOrder( + order.Data.Symbol, + order.Data.Id.ToString(), + ParseOrderType(order.Data.Type), + order.Data.Side == OrderSide.Buy ? SharedOrderSide.Buy : SharedOrderSide.Sell, + ParseOrderStatus(order.Data.Status), + order.Data.CreateTime) + { + ClientOrderId = order.Data.ClientOrderId, + AveragePrice = order.Data.AveragePrice, + Price = order.Data.Price, + Quantity = order.Data.Quantity, + QuantityFilled = order.Data.QuantityFilled, + QuoteQuantityFilled = order.Data.QuoteQuantityFilled, + TimeInForce = ParseTimeInForce(order.Data.TimeInForce), + UpdateTime = order.Data.UpdateTime, + PositionSide = order.Data.PositionSide == PositionSide.Both ? SharedPositionSide.Both : order.Data.PositionSide == PositionSide.Long ? SharedPositionSide.Long : SharedPositionSide.Short, + ReduceOnly = order.Data.ReduceOnly + }); + } + + EndpointOptions IFuturesOrderRestClient.GetOpenFuturesOrdersOptions { get; } = new EndpointOptions(true); + async Task>> IFuturesOrderRestClient.GetOpenFuturesOrdersAsync(GetOpenOrdersRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IFuturesOrderRestClient)this).GetOpenFuturesOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + + var symbol = request.Symbol?.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)); + var orders = await Trading.GetOpenOrdersAsync(symbol).ConfigureAwait(false); + if (!orders) + return orders.AsExchangeResult>(Exchange, default); + + return orders.AsExchangeResult(Exchange, orders.Data.Select(x => new SharedFuturesOrder( + x.Symbol, + x.Id.ToString(), + ParseOrderType(x.Type), + x.Side == OrderSide.Buy ? SharedOrderSide.Buy : SharedOrderSide.Sell, + ParseOrderStatus(x.Status), + x.CreateTime) + { + ClientOrderId = x.ClientOrderId, + AveragePrice = x.AveragePrice, + Price = x.Price, + Quantity = x.Quantity, + QuantityFilled = x.QuantityFilled, + QuoteQuantityFilled = x.QuoteQuantityFilled, + TimeInForce = ParseTimeInForce(x.TimeInForce), + UpdateTime = x.UpdateTime, + PositionSide = x.PositionSide == PositionSide.Both ? SharedPositionSide.Both : x.PositionSide == PositionSide.Long ? SharedPositionSide.Long : SharedPositionSide.Short, + ReduceOnly = x.ReduceOnly + })); + } + + PaginatedEndpointOptions IFuturesOrderRestClient.GetClosedFuturesOrdersOptions { get; } = new PaginatedEndpointOptions(true, true); + async Task>> IFuturesOrderRestClient.GetClosedFuturesOrdersAsync(GetClosedOrdersRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IFuturesOrderRestClient)this).GetClosedFuturesOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + + // Determine page token + DateTime? fromTimestamp = null; + if (pageToken is DateTimeToken dateTimeToken) + fromTimestamp = dateTimeToken.LastTime; + + // Get data + var orders = await Trading.GetOrdersAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), + startTime: fromTimestamp ?? request.Filter?.StartTime, + endTime: request.Filter?.EndTime, + limit: request.Filter?.Limit ?? 1000).ConfigureAwait(false); + if (!orders) + return orders.AsExchangeResult>(Exchange, default); + + // Get next token + DateTimeToken? nextToken = null; + if (orders.Data.Count() == (request.Filter?.Limit ?? 1000)) + nextToken = new DateTimeToken(orders.Data.Max(o => o.CreateTime)); + + return orders.AsExchangeResult(Exchange, orders.Data.Where(x => x.Status == OrderStatus.Filled || x.Status == OrderStatus.Canceled || x.Status == OrderStatus.Expired).Select(x => new SharedFuturesOrder( + x.Symbol, + x.Id.ToString(), + ParseOrderType(x.Type), + x.Side == OrderSide.Buy ? SharedOrderSide.Buy : SharedOrderSide.Sell, + ParseOrderStatus(x.Status), + x.CreateTime) + { + ClientOrderId = x.ClientOrderId, + AveragePrice = x.AveragePrice, + Price = x.Price, + Quantity = x.Quantity, + QuantityFilled = x.QuantityFilled, + QuoteQuantityFilled = x.QuoteQuantityFilled, + TimeInForce = ParseTimeInForce(x.TimeInForce), + UpdateTime = x.UpdateTime, + PositionSide = x.PositionSide == PositionSide.Both ? SharedPositionSide.Both : x.PositionSide == PositionSide.Long ? SharedPositionSide.Long : SharedPositionSide.Short, + ReduceOnly = x.ReduceOnly + })); + } + + EndpointOptions IFuturesOrderRestClient.GetFuturesOrderTradesOptions { get; } = new EndpointOptions(true); + async Task>> IFuturesOrderRestClient.GetFuturesOrderTradesAsync(GetOrderTradesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderTradesOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + + if (!long.TryParse(request.OrderId, out var orderId)) + return new ExchangeWebResult>(Exchange, new ArgumentError("Invalid order id")); + + var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), orderId: orderId).ConfigureAwait(false); + if (!orders) + return orders.AsExchangeResult>(Exchange, default); + + return orders.AsExchangeResult(Exchange, orders.Data.Select(x => new SharedUserTrade( + x.Symbol, + x.OrderId.ToString(), + x.Id.ToString(), + x.Quantity, + x.Price, + x.Timestamp) + { + Price = x.Price, + Quantity = x.Quantity, + Fee = x.Fee, + FeeAsset = x.FeeAsset, + Role = x.Maker ? SharedRole.Maker : SharedRole.Taker + })); + } + + PaginatedEndpointOptions IFuturesOrderRestClient.GetFuturesUserTradesOptions { get; } = new PaginatedEndpointOptions(true, true); + async Task>> IFuturesOrderRestClient.GetFuturesUserTradesAsync(GetUserTradesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IFuturesOrderRestClient)this).GetFuturesUserTradesOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + + // Determine page token + long? fromId = null; + if (pageToken is FromIdToken fromIdToken) + fromId = long.Parse(fromIdToken.FromToken); + + // Get data + var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), + startTime: request.Filter?.StartTime, + endTime: request.Filter?.EndTime, + limit: request.Filter?.Limit ?? 500, + fromId: fromId + ).ConfigureAwait(false); + if (!orders) + return orders.AsExchangeResult>(Exchange, default); + + // Get next token + FromIdToken? nextToken = null; + if (orders.Data.Count() == (request.Filter?.Limit ?? 500)) + nextToken = new FromIdToken(orders.Data.Max(o => o.Id).ToString()); + + return orders.AsExchangeResult(Exchange, orders.Data.Select(x => new SharedUserTrade( + x.Symbol, + x.OrderId.ToString(), + x.Id.ToString(), + x.Quantity, + x.Price, + x.Timestamp) + { + Price = x.Price, + Quantity = x.Quantity, + Fee = x.Fee, + FeeAsset = x.FeeAsset, + Role = x.Maker ? SharedRole.Maker : SharedRole.Taker + }), nextToken); + } + + EndpointOptions IFuturesOrderRestClient.CancelFuturesOrderOptions { get; } = new EndpointOptions(true); + async Task> IFuturesOrderRestClient.CancelFuturesOrderAsync(CancelOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IFuturesOrderRestClient)this).CancelFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + + if (!long.TryParse(request.OrderId, out var orderId)) + return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); + + var order = await Trading.CancelOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), orderId).ConfigureAwait(false); + if (!order) + return order.AsExchangeResult(Exchange, default); + + return order.AsExchangeResult(Exchange, new SharedId(order.Data.Id.ToString())); + } + + private SharedOrderStatus ParseOrderStatus(OrderStatus status) + { + if (status == OrderStatus.PendingNew || status == OrderStatus.New || status == OrderStatus.PartiallyFilled || status == OrderStatus.PendingCancel) return SharedOrderStatus.Open; + if (status == OrderStatus.Canceled || status == OrderStatus.Rejected || status == OrderStatus.Expired) return SharedOrderStatus.Canceled; + return SharedOrderStatus.Filled; + } + + private SharedOrderType ParseOrderType(FuturesOrderType type) + { + if (type == FuturesOrderType.Market) return SharedOrderType.Market; + if (type == FuturesOrderType.Limit) return SharedOrderType.Limit; + + return SharedOrderType.Other; + } + + private SharedTimeInForce? ParseTimeInForce(TimeInForce tif) + { + if (tif == TimeInForce.GoodTillCanceled) return SharedTimeInForce.GoodTillCanceled; + if (tif == TimeInForce.ImmediateOrCancel) return SharedTimeInForce.ImmediateOrCancel; + if (tif == TimeInForce.FillOrKill) return SharedTimeInForce.FillOrKill; + if (tif == TimeInForce.GoodTillDate) return SharedTimeInForce.GoodTillDate; + + return null; + } + + #endregion + + #region Positions client + + EndpointOptions IPositionRestClient.GetPositionsOptions { get; } = new EndpointOptions(true); + async Task>> IPositionRestClient.GetPositionsAsync(GetPositionsRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IPositionRestClient)this).GetPositionsOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + + var result = await Account.GetPositionInformationAsync(pair: request.Symbol?.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), ct: ct).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult>(Exchange, default); + + return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedPosition(x.Symbol, x.Quantity, x.UpdateTime) + { + UnrealizedPnl = x.UnrealizedPnl, + LiquidationPrice = x.LiquidationPrice, + AverageEntryPrice = x.EntryPrice, + PositionSide = x.PositionSide == PositionSide.Both ? SharedPositionSide.Both : x.PositionSide == PositionSide.Short ? SharedPositionSide.Short : SharedPositionSide.Long + }).ToList()); + } + + #endregion + + #region Leverage client + + EndpointOptions ILeverageRestClient.GetLeverageOptions { get; } = new EndpointOptions(true); + async Task> ILeverageRestClient.GetLeverageAsync(GetLeverageRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((ILeverageRestClient)this).GetLeverageOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + + var result = await Account.GetPositionInformationAsync(pair: request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), ct: ct).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult(Exchange, default); + + if (!result.Data.Any()) + return result.AsExchangeError(Exchange, new ServerError("Not found")); + + return result.AsExchangeResult(Exchange, new SharedLeverage(result.Data.FirstOrDefault().Leverage)); + } + + EndpointOptions ILeverageRestClient.SetLeverageOptions { get; } = new EndpointOptions(true); + async Task> ILeverageRestClient.SetLeverageAsync(SetLeverageRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((ILeverageRestClient)this).SetLeverageOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + + var result = await Account.ChangeInitialLeverageAsync(symbol: request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), (int)request.Leverage ,ct: ct).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult(Exchange, default); + + return result.AsExchangeResult(Exchange, new SharedLeverage(result.Data.Leverage)); + } + #endregion + + #region Mark Klines client + + GetKlinesOptions IMarkKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(true, false) + { + MaxRequestDataPoints = 1000 + }; + + async Task>> IMarkKlineRestClient.GetMarkKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var interval = (Enums.KlineInterval)request.Interval; + if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) + return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); + + var validationError = ((IMarkKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + + // Determine page token + DateTime? fromTimestamp = null; + if (pageToken is DateTimeToken dateTimeToken) + fromTimestamp = dateTimeToken.LastTime; + + var result = await ExchangeData.GetMarkPriceKlinesAsync( + request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, ApiType.InverseFutures)), + interval, + request.Filter?.Limit ?? 1000, + fromTimestamp ?? request.Filter?.StartTime, + request.Filter?.EndTime, + ct: ct + ).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult>(Exchange, default); + + // Get next token + DateTimeToken? nextToken = null; + if (request.Filter?.StartTime != null && result.Data.Any()) + { + var maxOpenTime = result.Data.Max(x => x.OpenTime); + if (maxOpenTime < request.Filter.EndTime!.Value.AddSeconds(-(int)request.Interval)) + nextToken = new DateTimeToken(maxOpenTime.AddSeconds((int)interval)); + } + + return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedMarkKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)), nextToken); + } + + #endregion + + #region Order Book client + GetOrderBookOptions IOrderBookRestClient.GetOrderBookOptions { get; } = new GetOrderBookOptions(new[] { 5, 10, 20, 50, 100, 500, 1000 }, false); + async Task> IOrderBookRestClient.GetOrderBookAsync(GetOrderBookRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + + var result = await ExchangeData.GetOrderBookAsync( + request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), + limit: request.Limit, + ct: ct).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult(Exchange, default); + + return result.AsExchangeResult(Exchange, new SharedOrderBook(result.Data.Asks, result.Data.Bids)); + } + + #endregion + + #region Trade History client + GetTradeHistoryOptions ITradeHistoryRestClient.GetTradeHistoryOptions { get; } = new GetTradeHistoryOptions(true, false); + + async Task>> ITradeHistoryRestClient.GetTradeHistoryAsync(GetTradeHistoryRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((ITradeHistoryRestClient)this).GetTradeHistoryOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + + long? fromId = null; + if (pageToken is FromIdToken token) + fromId = long.Parse(token.FromToken); + + // Get data + var result = await ExchangeData.GetAggregatedTradeHistoryAsync( + request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, ApiType.InverseFutures)), + startTime: fromId != null ? null : request.StartTime, + endTime: fromId != null ? null : request.EndTime, + limit: 1000, + fromId: fromId, + ct: ct).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult>(Exchange, default); + + FromIdToken? nextToken = null; + if (result.Data.Any() && result.Data.Last().TradeTime < request.EndTime) + nextToken = new FromIdToken(result.Data.Max(x => x.Id).ToString()); + + // Return + return result.AsExchangeResult(Exchange, result.Data.Where(x => x.TradeTime < request.EndTime).Select(x => new SharedTrade(x.Quantity, x.Price, x.TradeTime)), nextToken); + } + #endregion + + #region Index Klines client + + GetKlinesOptions IIndexKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(true, false) + { + MaxRequestDataPoints = 1000 + }; + + async Task>> IIndexKlineRestClient.GetIndexKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var interval = (Enums.KlineInterval)request.Interval; + if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) + return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); + + var validationError = ((IIndexKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + + // Determine page token + DateTime? fromTimestamp = null; + if (pageToken is DateTimeToken dateTimeToken) + fromTimestamp = dateTimeToken.LastTime; + + var result = await ExchangeData.GetMarkPriceKlinesAsync( + request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), + interval, + request.Filter?.Limit ?? 1000, + fromTimestamp ?? request.Filter?.StartTime, + request.Filter?.EndTime, + ct: ct + ).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult>(Exchange, default); + + // Get next token + DateTimeToken? nextToken = null; + if (request.Filter?.StartTime != null && result.Data.Any()) + { + var maxOpenTime = result.Data.Max(x => x.OpenTime); + if (maxOpenTime < request.Filter.EndTime!.Value.AddSeconds(-(int)request.Interval)) + nextToken = new DateTimeToken(maxOpenTime.AddSeconds((int)interval)); + } + + return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedMarkKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)), nextToken); + } + + #endregion + + #region Open Interest client + + EndpointOptions IOpenInterestRestClient.GetOpenInterestOptions { get; } = new EndpointOptions(true); + async Task> IOpenInterestRestClient.GetOpenInterestAsync(GetOpenInterestRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IOpenInterestRestClient)this).GetOpenInterestOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + + var result = await ExchangeData.GetOpenInterestAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, ApiType.InverseFutures)), ct: ct).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult(Exchange, default); + + return result.AsExchangeResult(Exchange, new SharedOpenInterest(result.Data.OpenInterest)); + } + + #endregion } } diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index bb67b3692..652896f92 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -38,7 +38,7 @@ async Task>> IKlineRestClient.GetKlin // Get data var result = await ExchangeData.GetKlinesAsync( - request.GetSymbol(FormatSymbol), + request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), interval, fromTimestamp ?? request.Filter?.StartTime, request.Filter?.EndTime?.AddSeconds(-1), @@ -95,7 +95,7 @@ async Task> ITickerRestClient.GetTickerAsync(Get if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var result = await ExchangeData.GetTickerAsync(request.GetSymbol(FormatSymbol), ct).ConfigureAwait(false); + var result = await ExchangeData.GetTickerAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -129,7 +129,7 @@ async Task>> IRecentTradeRestClient.G // Get data var result = await ExchangeData.GetRecentTradesAsync( - request.GetSymbol(FormatSymbol), + request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) @@ -155,7 +155,7 @@ async Task>> ITradeHistoryRestClient. // Get data var result = await ExchangeData.GetAggregatedTradeHistoryAsync( - request.GetSymbol(FormatSymbol), + request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), startTime: fromId != null ? null : request.StartTime, endTime: fromId != null ? null : request.EndTime, limit: 1000, @@ -182,7 +182,7 @@ async Task> IOrderBookRestClient.GetOrderBook return new ExchangeWebResult(Exchange, validationError); var result = await ExchangeData.GetOrderBookAsync( - request.GetSymbol(FormatSymbol), + request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) @@ -239,7 +239,7 @@ async Task> ISpotOrderRestClient.PlaceSpotOrderAsync return new ExchangeWebResult(Exchange, validationError); var result = await Trading.PlaceOrderAsync( - request.GetSymbol(FormatSymbol), + request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), request.Side == SharedOrderSide.Buy ? Enums.OrderSide.Buy : Enums.OrderSide.Sell, request.OrderType == SharedOrderType.Limit ? Enums.SpotOrderType.Limit : request.OrderType == SharedOrderType.Market ? Enums.SpotOrderType.Market: Enums.SpotOrderType.LimitMaker, quantity: request.Quantity, @@ -253,17 +253,17 @@ async Task> ISpotOrderRestClient.PlaceSpotOrderAsync return result.AsExchangeResult(Exchange, new SharedId(result.Data.Id.ToString())); } - EndpointOptions ISpotOrderRestClient.GetOrderOptions { get; } = new EndpointOptions(true); - async Task> ISpotOrderRestClient.GetOrderAsync(GetOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + EndpointOptions ISpotOrderRestClient.GetSpotOrderOptions { get; } = new EndpointOptions(true); + async Task> ISpotOrderRestClient.GetSpotOrderAsync(GetOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetOrderOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((ISpotOrderRestClient)this).GetSpotOrderOptions.ValidateRequest(Exchange, request, exchangeParameters); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); - var order = await Trading.GetOrderAsync(request.GetSymbol(FormatSymbol), orderId).ConfigureAwait(false); + var order = await Trading.GetOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), orderId).ConfigureAwait(false); if (!order) return order.AsExchangeResult(Exchange, default); @@ -287,17 +287,14 @@ async Task> ISpotOrderRestClient.GetOrderAsyn }); } - EndpointOptions ISpotOrderRestClient.GetOpenOrdersOptions { get; } = new EndpointOptions(true); - async Task>> ISpotOrderRestClient.GetOpenOrdersAsync(GetSpotOpenOrdersRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + EndpointOptions ISpotOrderRestClient.GetOpenSpotOrdersOptions { get; } = new EndpointOptions(true); + async Task>> ISpotOrderRestClient.GetOpenSpotOrdersAsync(GetOpenOrdersRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetOpenOrdersOptions.ValidateRequest(Exchange, request,exchangeParameters); + var validationError = ((ISpotOrderRestClient)this).GetOpenSpotOrdersOptions.ValidateRequest(Exchange, request,exchangeParameters); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); - string? symbol = null; - if (request.BaseAsset != null && request.QuoteAsset != null) - symbol = FormatSymbol(request.BaseAsset, request.QuoteAsset, ApiType.Spot); - + var symbol = request.Symbol?.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, ApiType.Spot)); var orders = await Trading.GetOpenOrdersAsync(symbol).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); @@ -322,10 +319,10 @@ async Task>> ISpotOrderRestClient })); } - PaginatedEndpointOptions ISpotOrderRestClient.GetClosedOrdersOptions { get; } = new PaginatedEndpointOptions(true, true); - async Task>> ISpotOrderRestClient.GetClosedOrdersAsync(GetSpotClosedOrdersRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + PaginatedEndpointOptions ISpotOrderRestClient.GetClosedSpotOrdersOptions { get; } = new PaginatedEndpointOptions(true, true); + async Task>> ISpotOrderRestClient.GetClosedSpotOrdersAsync(GetClosedOrdersRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetClosedOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((ISpotOrderRestClient)this).GetClosedSpotOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -335,7 +332,7 @@ async Task>> ISpotOrderRestClient fromTimestamp = dateTimeToken.LastTime; // Get data - var orders = await Trading.GetOrdersAsync(request.GetSymbol(FormatSymbol), + var orders = await Trading.GetOrdersAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), startTime: fromTimestamp ?? request.Filter?.StartTime, endTime: request.Filter?.EndTime, limit: request.Filter?.Limit ?? 1000).ConfigureAwait(false); @@ -367,17 +364,17 @@ async Task>> ISpotOrderRestClient })); } - EndpointOptions ISpotOrderRestClient.GetOrderTradesOptions { get; } = new EndpointOptions(true); - async Task>> ISpotOrderRestClient.GetOrderTradesAsync(GetOrderTradesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + EndpointOptions ISpotOrderRestClient.GetSpotOrderTradesOptions { get; } = new EndpointOptions(true); + async Task>> ISpotOrderRestClient.GetSpotOrderTradesAsync(GetOrderTradesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetOrderTradesOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((ISpotOrderRestClient)this).GetSpotOrderTradesOptions.ValidateRequest(Exchange, request, exchangeParameters); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult>(Exchange, new ArgumentError("Invalid order id")); - var orders = await Trading.GetUserTradesAsync(request.GetSymbol(FormatSymbol), orderId: orderId).ConfigureAwait(false); + var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), orderId: orderId).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); @@ -397,10 +394,10 @@ async Task>> ISpotOrderRestClient })); } - PaginatedEndpointOptions ISpotOrderRestClient.GetUserTradesOptions { get; } = new PaginatedEndpointOptions(true, true); - async Task>> ISpotOrderRestClient.GetUserTradesAsync(GetUserTradesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + PaginatedEndpointOptions ISpotOrderRestClient.GetSpotUserTradesOptions { get; } = new PaginatedEndpointOptions(true, true); + async Task>> ISpotOrderRestClient.GetSpotUserTradesAsync(GetUserTradesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetUserTradesOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((ISpotOrderRestClient)this).GetSpotUserTradesOptions.ValidateRequest(Exchange, request, exchangeParameters); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -410,7 +407,7 @@ async Task>> ISpotOrderRestClient fromId = long.Parse(fromIdToken.FromToken); // Get data - var orders = await Trading.GetUserTradesAsync(request.GetSymbol(FormatSymbol), + var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), startTime: request.Filter?.StartTime, endTime: request.Filter?.EndTime, limit: request.Filter?.Limit ?? 500, @@ -440,17 +437,17 @@ async Task>> ISpotOrderRestClient }), nextToken); } - EndpointOptions ISpotOrderRestClient.CancelOrderOptions { get; } = new EndpointOptions(true); - async Task> ISpotOrderRestClient.CancelOrderAsync(CancelOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + EndpointOptions ISpotOrderRestClient.CancelSpotOrderOptions { get; } = new EndpointOptions(true); + async Task> ISpotOrderRestClient.CancelSpotOrderAsync(CancelOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).CancelOrderOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((ISpotOrderRestClient)this).CancelSpotOrderOptions.ValidateRequest(Exchange, request, exchangeParameters); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); - var order = await Trading.CancelOrderAsync(request.GetSymbol(FormatSymbol), orderId).ConfigureAwait(false); + var order = await Trading.CancelOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), orderId).ConfigureAwait(false); if (!order) return order.AsExchangeResult(Exchange, default); @@ -486,11 +483,11 @@ private SharedOrderType ParseOrderType(SpotOrderType type) #endregion #region Asset client - EndpointOptions IAssetRestClient.GetAssetsOptions { get; } = new EndpointOptions("GetAssetsRequest",true); + EndpointOptions IAssetsRestClient.GetAssetsOptions { get; } = new EndpointOptions("GetAssetsRequest", true); - async Task>> IAssetRestClient.GetAssetsAsync(ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IAssetsRestClient.GetAssetsAsync(ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IAssetRestClient)this).GetAssetsOptions.ValidateRequest(Exchange, exchangeParameters); + var validationError = ((IAssetsRestClient)this).GetAssetsOptions.ValidateRequest(Exchange, exchangeParameters); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -514,6 +511,37 @@ async Task>> IAssetRestClient.GetAsse })); } + EndpointOptions IAssetsRestClient.GetAssetOptions { get; } = new EndpointOptions(false); + async Task> IAssetsRestClient.GetAssetAsync(GetAssetRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IAssetsRestClient)this).GetAssetOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + + var assets = await Account.GetUserAssetsAsync(ct: ct).ConfigureAwait(false); + if (!assets) + return assets.AsExchangeResult(Exchange, default); + + var asset = assets.Data.SingleOrDefault(x => x.Asset.Equals(request.Asset, StringComparison.InvariantCultureIgnoreCase)); + if (asset == null) + return assets.AsExchangeError(Exchange, new ServerError("Asset not found")); + + return assets.AsExchangeResult(Exchange,new SharedAsset(asset.Asset) + { + FullName = asset.Name, + Networks = asset.NetworkList.Select(x => new SharedAssetNetwork(x.Network) + { + FullName = x.Name, + MinConfirmations = x.MinConfirmations, + DepositEnabled = x.DepositEnabled, + MinWithdrawQuantity = x.WithdrawMin, + MaxWithdrawQuantity = x.WithdrawMax, + WithdrawEnabled = x.WithdrawEnabled, + WithdrawFee = x.WithdrawFee + }) + }); + } + #endregion #region Deposit client diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs index ecdcd584e..9be3d1409 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs @@ -51,7 +51,7 @@ internal partial class BinanceRestClientUsdFuturesApi : RestApiClient, IBinanceR /// public override string FormatSymbol(string baseAsset, string quoteAsset, ApiType? futuresType = null) { - var suffix = futuresType == null ? string.Empty : "_PERP"; + var suffix = futuresType == null ? string.Empty : "_PERP"; // _PERP Actually ever needed? return baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + suffix; } diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs index 47d680a24..005b8a378 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -1,7 +1,8 @@ -using Binance.Net.Interfaces.Clients.SpotApi; +using Binance.Net.Enums; using Binance.Net.Interfaces.Clients.UsdFuturesApi; using CryptoExchange.Net.SharedApis.Enums; using CryptoExchange.Net.SharedApis.Interfaces; +using CryptoExchange.Net.SharedApis.Interfaces.Rest; using CryptoExchange.Net.SharedApis.Models; using CryptoExchange.Net.SharedApis.Models.FilterOptions; using CryptoExchange.Net.SharedApis.Models.Rest; @@ -17,6 +18,8 @@ internal partial class BinanceRestClientUsdFuturesApi : IBinanceRestClientUsdFut { public string Exchange => BinanceExchange.ExchangeName; + #region Klines client + GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(true, false) { MaxRequestDataPoints = 1000 @@ -38,7 +41,7 @@ async Task>> IKlineRestClient.GetKlin fromTimestamp = dateTimeToken.LastTime; var result = await ExchangeData.GetKlinesAsync( - request.GetSymbol(FormatSymbol), + request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), interval, fromTimestamp ?? request.Filter?.StartTime, request.Filter?.EndTime, @@ -60,8 +63,64 @@ async Task>> IKlineRestClient.GetKlin return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)), nextToken); } + #endregion + + #region Mark Klines client + + GetKlinesOptions IMarkKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(true, false) + { + MaxRequestDataPoints = 1000 + }; + + async Task>> IMarkKlineRestClient.GetMarkKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var interval = (Enums.KlineInterval)request.Interval; + if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) + return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); + + var validationError = ((IMarkKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + + // Determine page token + DateTime? fromTimestamp = null; + if (pageToken is DateTimeToken dateTimeToken) + fromTimestamp = dateTimeToken.LastTime; + + var result = await ExchangeData.GetMarkPriceKlinesAsync( + request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), + interval, + request.Filter?.Limit ?? 1000, + fromTimestamp ?? request.Filter?.StartTime, + request.Filter?.EndTime, + ct: ct + ).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult>(Exchange, default); + + // Get next token + DateTimeToken? nextToken = null; + if (request.Filter?.StartTime != null && result.Data.Any()) + { + var maxOpenTime = result.Data.Max(x => x.OpenTime); + if (maxOpenTime < request.Filter.EndTime!.Value.AddSeconds(-(int)request.Interval)) + nextToken = new DateTimeToken(maxOpenTime.AddSeconds((int)interval)); + } + + return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedMarkKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)), nextToken); + } + + #endregion + + #region Futures Symbol client + + EndpointOptions IFuturesSymbolRestClient.GetFuturesSymbolsOptions { get; } = new EndpointOptions("GetFuturesSymbolsRequest", false); async Task>> IFuturesSymbolRestClient.GetFuturesSymbolsAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { + var validationError = ((IFuturesSymbolRestClient)this).GetFuturesSymbolsOptions.ValidateRequest(Exchange, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + var result = await ExchangeData.GetExchangeInfoAsync(ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult< IEnumerable>(Exchange, default); @@ -77,6 +136,10 @@ async Task>> IFuturesSymbolRe })); } + #endregion + + #region Ticker client + EndpointOptions ITickerRestClient.GetTickerOptions { get; } = new EndpointOptions(false); async Task> ITickerRestClient.GetTickerAsync(GetTickerRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { @@ -84,7 +147,7 @@ async Task> ITickerRestClient.GetTickerAsync(Get if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var result = await ExchangeData.GetTickerAsync(request.GetSymbol(FormatSymbol), ct).ConfigureAwait(false); + var result = await ExchangeData.GetTickerAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -101,6 +164,10 @@ async Task>> ITickerRestClient.GetTi return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume))); } + #endregion + + #region Recent Trade client + GetRecentTradesOptions IRecentTradeRestClient.GetRecentTradesOptions { get; } = new GetRecentTradesOptions(1000, false); async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { @@ -109,7 +176,7 @@ async Task>> IRecentTradeRestClient.G return new ExchangeWebResult>(Exchange, validationError); var result = await ExchangeData.GetRecentTradesAsync( - request.GetSymbol((baseAsset, quoteAsset, apiType) => FormatSymbol(baseAsset, quoteAsset)), // Don't pass api type; need only the pair + request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), // Don't pass api type; need only the pair limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) @@ -117,5 +184,457 @@ async Task>> IRecentTradeRestClient.G return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedTrade(x.BaseQuantity, x.Price, x.TradeTime))); } + + #endregion + + #region Futures Order Client + + PlaceFuturesOrderOptions IFuturesOrderRestClient.PlaceFuturesOrderOptions { get; } = new PlaceFuturesOrderOptions( + new[] + { + SharedOrderType.Limit, + SharedOrderType.Market + }, + new[] + { + SharedTimeInForce.GoodTillCanceled, + SharedTimeInForce.ImmediateOrCancel, + SharedTimeInForce.FillOrKill + }, + new SharedQuantitySupport( + SharedQuantityType.BaseAssetQuantity, + SharedQuantityType.BaseAssetQuantity, + SharedQuantityType.BaseAssetQuantity, + SharedQuantityType.BaseAssetQuantity)); + + async Task> IFuturesOrderRestClient.PlaceFuturesOrderAsync(PlaceFuturesOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IFuturesOrderRestClient)this).PlaceFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + + var result = await Trading.PlaceOrderAsync( + request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), + request.Side == SharedOrderSide.Buy ? Enums.OrderSide.Buy : Enums.OrderSide.Sell, + request.OrderType == SharedOrderType.Limit ? Enums.FuturesOrderType.Limit : Enums.FuturesOrderType.Market, + quantity: request.Quantity, + price: request.Price, + positionSide: request.PositionSide == SharedPositionSide.Both ? PositionSide.Both : request.PositionSide == SharedPositionSide.Long ? PositionSide.Long : PositionSide.Short, + reduceOnly: request.ReduceOnly, + closePosition: request.ClosePosition, + newClientOrderId: request.ClientOrderId).ConfigureAwait(false); + + if (!result) + return result.AsExchangeResult(Exchange, default); + + return result.AsExchangeResult(Exchange, new SharedId(result.Data.Id.ToString())); + } + + EndpointOptions IFuturesOrderRestClient.GetFuturesOrderOptions { get; } = new EndpointOptions(true); + async Task> IFuturesOrderRestClient.GetFuturesOrderAsync(GetOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + + if (!long.TryParse(request.OrderId, out var orderId)) + return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); + + var order = await Trading.GetOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), orderId).ConfigureAwait(false); + if (!order) + return order.AsExchangeResult(Exchange, default); + + return order.AsExchangeResult(Exchange, new SharedFuturesOrder( + order.Data.Symbol, + order.Data.Id.ToString(), + ParseOrderType(order.Data.Type), + order.Data.Side == OrderSide.Buy ? SharedOrderSide.Buy : SharedOrderSide.Sell, + ParseOrderStatus(order.Data.Status), + order.Data.CreateTime) + { + ClientOrderId = order.Data.ClientOrderId, + AveragePrice = order.Data.AveragePrice, + Price = order.Data.Price, + Quantity = order.Data.Quantity, + QuantityFilled = order.Data.QuantityFilled, + QuoteQuantityFilled = order.Data.QuoteQuantityFilled, + TimeInForce = ParseTimeInForce(order.Data.TimeInForce), + UpdateTime = order.Data.UpdateTime, + PositionSide = order.Data.PositionSide == PositionSide.Both ? SharedPositionSide.Both : order.Data.PositionSide == PositionSide.Long ? SharedPositionSide.Long : SharedPositionSide.Short, + ReduceOnly = order.Data.ReduceOnly + }); + } + + EndpointOptions IFuturesOrderRestClient.GetOpenFuturesOrdersOptions { get; } = new EndpointOptions(true); + async Task>> IFuturesOrderRestClient.GetOpenFuturesOrdersAsync(GetOpenOrdersRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IFuturesOrderRestClient)this).GetOpenFuturesOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + + var symbol = request.Symbol?.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)); + var orders = await Trading.GetOpenOrdersAsync(symbol).ConfigureAwait(false); + if (!orders) + return orders.AsExchangeResult>(Exchange, default); + + return orders.AsExchangeResult(Exchange, orders.Data.Select(x => new SharedFuturesOrder( + x.Symbol, + x.Id.ToString(), + ParseOrderType(x.Type), + x.Side == OrderSide.Buy ? SharedOrderSide.Buy : SharedOrderSide.Sell, + ParseOrderStatus(x.Status), + x.CreateTime) + { + ClientOrderId = x.ClientOrderId, + AveragePrice = x.AveragePrice, + Price = x.Price, + Quantity = x.Quantity, + QuantityFilled = x.QuantityFilled, + QuoteQuantityFilled = x.QuoteQuantityFilled, + TimeInForce = ParseTimeInForce(x.TimeInForce), + UpdateTime = x.UpdateTime, + PositionSide = x.PositionSide == PositionSide.Both ? SharedPositionSide.Both : x.PositionSide == PositionSide.Long ? SharedPositionSide.Long : SharedPositionSide.Short, + ReduceOnly = x.ReduceOnly + })); + } + + PaginatedEndpointOptions IFuturesOrderRestClient.GetClosedFuturesOrdersOptions { get; } = new PaginatedEndpointOptions(true, true); + async Task>> IFuturesOrderRestClient.GetClosedFuturesOrdersAsync(GetClosedOrdersRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IFuturesOrderRestClient)this).GetClosedFuturesOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + + // Determine page token + DateTime? fromTimestamp = null; + if (pageToken is DateTimeToken dateTimeToken) + fromTimestamp = dateTimeToken.LastTime; + + // Get data + var orders = await Trading.GetOrdersAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), + startTime: fromTimestamp ?? request.Filter?.StartTime, + endTime: request.Filter?.EndTime, + limit: request.Filter?.Limit ?? 1000).ConfigureAwait(false); + if (!orders) + return orders.AsExchangeResult>(Exchange, default); + + // Get next token + DateTimeToken? nextToken = null; + if (orders.Data.Count() == (request.Filter?.Limit ?? 1000)) + nextToken = new DateTimeToken(orders.Data.Max(o => o.CreateTime)); + + return orders.AsExchangeResult(Exchange, orders.Data.Where(x => x.Status == OrderStatus.Filled || x.Status == OrderStatus.Canceled || x.Status == OrderStatus.Expired).Select(x => new SharedFuturesOrder( + x.Symbol, + x.Id.ToString(), + ParseOrderType(x.Type), + x.Side == OrderSide.Buy ? SharedOrderSide.Buy : SharedOrderSide.Sell, + ParseOrderStatus(x.Status), + x.CreateTime) + { + ClientOrderId = x.ClientOrderId, + AveragePrice = x.AveragePrice, + Price = x.Price, + Quantity = x.Quantity, + QuantityFilled = x.QuantityFilled, + QuoteQuantityFilled = x.QuoteQuantityFilled, + TimeInForce = ParseTimeInForce(x.TimeInForce), + UpdateTime = x.UpdateTime, + PositionSide = x.PositionSide == PositionSide.Both ? SharedPositionSide.Both : x.PositionSide == PositionSide.Long ? SharedPositionSide.Long : SharedPositionSide.Short, + ReduceOnly = x.ReduceOnly + })); + } + + EndpointOptions IFuturesOrderRestClient.GetFuturesOrderTradesOptions { get; } = new EndpointOptions(true); + async Task>> IFuturesOrderRestClient.GetFuturesOrderTradesAsync(GetOrderTradesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderTradesOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + + if (!long.TryParse(request.OrderId, out var orderId)) + return new ExchangeWebResult>(Exchange, new ArgumentError("Invalid order id")); + + var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), orderId: orderId).ConfigureAwait(false); + if (!orders) + return orders.AsExchangeResult>(Exchange, default); + + return orders.AsExchangeResult(Exchange, orders.Data.Select(x => new SharedUserTrade( + x.Symbol, + x.OrderId.ToString(), + x.Id.ToString(), + x.Quantity, + x.Price, + x.Timestamp) + { + Price = x.Price, + Quantity = x.Quantity, + Fee = x.Fee, + FeeAsset = x.FeeAsset, + Role = x.Maker ? SharedRole.Maker : SharedRole.Taker + })); + } + + PaginatedEndpointOptions IFuturesOrderRestClient.GetFuturesUserTradesOptions { get; } = new PaginatedEndpointOptions(true, true); + async Task>> IFuturesOrderRestClient.GetFuturesUserTradesAsync(GetUserTradesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IFuturesOrderRestClient)this).GetFuturesUserTradesOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + + // Determine page token + long? fromId = null; + if (pageToken is FromIdToken fromIdToken) + fromId = long.Parse(fromIdToken.FromToken); + + // Get data + var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), + startTime: request.Filter?.StartTime, + endTime: request.Filter?.EndTime, + limit: request.Filter?.Limit ?? 500, + fromId: fromId + ).ConfigureAwait(false); + if (!orders) + return orders.AsExchangeResult>(Exchange, default); + + // Get next token + FromIdToken? nextToken = null; + if (orders.Data.Count() == (request.Filter?.Limit ?? 500)) + nextToken = new FromIdToken(orders.Data.Max(o => o.Id).ToString()); + + return orders.AsExchangeResult(Exchange, orders.Data.Select(x => new SharedUserTrade( + x.Symbol, + x.OrderId.ToString(), + x.Id.ToString(), + x.Quantity, + x.Price, + x.Timestamp) + { + Price = x.Price, + Quantity = x.Quantity, + Fee = x.Fee, + FeeAsset = x.FeeAsset, + Role = x.Maker ? SharedRole.Maker : SharedRole.Taker + }), nextToken); + } + + EndpointOptions IFuturesOrderRestClient.CancelFuturesOrderOptions { get; } = new EndpointOptions(true); + async Task> IFuturesOrderRestClient.CancelFuturesOrderAsync(CancelOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IFuturesOrderRestClient)this).CancelFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + + if (!long.TryParse(request.OrderId, out var orderId)) + return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); + + var order = await Trading.CancelOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), orderId).ConfigureAwait(false); + if (!order) + return order.AsExchangeResult(Exchange, default); + + return order.AsExchangeResult(Exchange, new SharedId(order.Data.Id.ToString())); + } + + private SharedOrderStatus ParseOrderStatus(OrderStatus status) + { + if (status == OrderStatus.PendingNew || status == OrderStatus.New || status == OrderStatus.PartiallyFilled || status == OrderStatus.PendingCancel) return SharedOrderStatus.Open; + if (status == OrderStatus.Canceled || status == OrderStatus.Rejected || status == OrderStatus.Expired) return SharedOrderStatus.Canceled; + return SharedOrderStatus.Filled; + } + + private SharedOrderType ParseOrderType(FuturesOrderType type) + { + if (type == FuturesOrderType.Market) return SharedOrderType.Market; + if (type == FuturesOrderType.Limit) return SharedOrderType.Limit; + + return SharedOrderType.Other; + } + + private SharedTimeInForce? ParseTimeInForce(TimeInForce tif) + { + if (tif == TimeInForce.GoodTillCanceled) return SharedTimeInForce.GoodTillCanceled; + if (tif == TimeInForce.ImmediateOrCancel) return SharedTimeInForce.ImmediateOrCancel; + if (tif == TimeInForce.FillOrKill) return SharedTimeInForce.FillOrKill; + if (tif == TimeInForce.GoodTillDate) return SharedTimeInForce.GoodTillDate; + + return null; + } + + #endregion + + #region Positions client + + EndpointOptions IPositionRestClient.GetPositionsOptions { get; } = new EndpointOptions(true); + async Task>> IPositionRestClient.GetPositionsAsync(GetPositionsRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IPositionRestClient)this).GetPositionsOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + + var result = await Account.GetPositionInformationAsync(symbol: request.Symbol?.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), ct: ct).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult>(Exchange, default); + + return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedPosition(x.Symbol, x.Quantity, x.UpdateTime) + { + UnrealizedPnl = x.UnrealizedPnl, + LiquidationPrice = x.LiquidationPrice, + AverageEntryPrice = x.EntryPrice, + PositionSide = x.PositionSide == PositionSide.Both ? SharedPositionSide.Both : x.PositionSide == PositionSide.Short ? SharedPositionSide.Short : SharedPositionSide.Long + }).ToList()); + } + + #endregion + + #region Leverage client + + EndpointOptions ILeverageRestClient.GetLeverageOptions { get; } = new EndpointOptions(true); + async Task> ILeverageRestClient.GetLeverageAsync(GetLeverageRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((ILeverageRestClient)this).GetLeverageOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + + var result = await Account.GetPositionInformationAsync(symbol: request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), ct: ct).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult(Exchange, default); + + if (!result.Data.Any()) + return result.AsExchangeError(Exchange, new ServerError("Not found")); + + return result.AsExchangeResult(Exchange, new SharedLeverage(result.Data.FirstOrDefault().Leverage)); + } + + EndpointOptions ILeverageRestClient.SetLeverageOptions { get; } = new EndpointOptions(true); + async Task> ILeverageRestClient.SetLeverageAsync(SetLeverageRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((ILeverageRestClient)this).SetLeverageOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + + var result = await Account.ChangeInitialLeverageAsync(symbol: request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), (int)request.Leverage, ct: ct).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult(Exchange, default); + + return result.AsExchangeResult(Exchange, new SharedLeverage(result.Data.Leverage)); + } + #endregion + + #region Order Book client + GetOrderBookOptions IOrderBookRestClient.GetOrderBookOptions { get; } = new GetOrderBookOptions(new[] { 5, 10, 20, 50, 100, 500, 1000 }, false); + async Task> IOrderBookRestClient.GetOrderBookAsync(GetOrderBookRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + + var result = await ExchangeData.GetOrderBookAsync( + request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), + limit: request.Limit, + ct: ct).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult(Exchange, default); + + return result.AsExchangeResult(Exchange, new SharedOrderBook(result.Data.Asks, result.Data.Bids)); + } + + #endregion + + #region Trade History client + GetTradeHistoryOptions ITradeHistoryRestClient.GetTradeHistoryOptions { get; } = new GetTradeHistoryOptions(true, false); + + async Task>> ITradeHistoryRestClient.GetTradeHistoryAsync(GetTradeHistoryRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((ITradeHistoryRestClient)this).GetTradeHistoryOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + + long? fromId = null; + if (pageToken is FromIdToken token) + fromId = long.Parse(token.FromToken); + + // Get data + var result = await ExchangeData.GetAggregatedTradeHistoryAsync( + request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), + startTime: fromId != null ? null : request.StartTime, + endTime: fromId != null ? null : request.EndTime, + limit: 1000, + fromId: fromId, + ct: ct).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult>(Exchange, default); + + FromIdToken? nextToken = null; + if (result.Data.Any() && result.Data.Last().TradeTime < request.EndTime) + nextToken = new FromIdToken(result.Data.Max(x => x.Id).ToString()); + + // Return + return result.AsExchangeResult(Exchange, result.Data.Where(x => x.TradeTime < request.EndTime).Select(x => new SharedTrade(x.Quantity, x.Price, x.TradeTime)), nextToken); + } + #endregion + + #region Index Klines client + + GetKlinesOptions IIndexKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(true, false) + { + MaxRequestDataPoints = 1000 + }; + + async Task>> IIndexKlineRestClient.GetIndexKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var interval = (Enums.KlineInterval)request.Interval; + if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) + return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); + + var validationError = ((IIndexKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + + // Determine page token + DateTime? fromTimestamp = null; + if (pageToken is DateTimeToken dateTimeToken) + fromTimestamp = dateTimeToken.LastTime; + + var result = await ExchangeData.GetMarkPriceKlinesAsync( + request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), + interval, + request.Filter?.Limit ?? 1000, + fromTimestamp ?? request.Filter?.StartTime, + request.Filter?.EndTime, + ct: ct + ).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult>(Exchange, default); + + // Get next token + DateTimeToken? nextToken = null; + if (request.Filter?.StartTime != null && result.Data.Any()) + { + var maxOpenTime = result.Data.Max(x => x.OpenTime); + if (maxOpenTime < request.Filter.EndTime!.Value.AddSeconds(-(int)request.Interval)) + nextToken = new DateTimeToken(maxOpenTime.AddSeconds((int)interval)); + } + + return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedMarkKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)), nextToken); + } + + #endregion + + #region Open Interest client + + EndpointOptions IOpenInterestRestClient.GetOpenInterestOptions { get; } = new EndpointOptions(true); + async Task> IOpenInterestRestClient.GetOpenInterestAsync(GetOpenInterestRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IOpenInterestRestClient)this).GetOpenInterestOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + + var result = await ExchangeData.GetOpenInterestAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), ct: ct).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult(Exchange, default); + + return result.AsExchangeResult(Exchange, new SharedOpenInterest(result.Data.OpenInterest)); + } + + #endregion } } diff --git a/Binance.Net/ExtensionMethods/ServiceCollectionExtensions.cs b/Binance.Net/ExtensionMethods/ServiceCollectionExtensions.cs index a1dec4c8a..6dc845388 100644 --- a/Binance.Net/ExtensionMethods/ServiceCollectionExtensions.cs +++ b/Binance.Net/ExtensionMethods/ServiceCollectionExtensions.cs @@ -1,9 +1,11 @@ using Binance.Net.Clients; using Binance.Net.Interfaces; using Binance.Net.Interfaces.Clients; +using Binance.Net.Interfaces.Clients.SpotApi; using Binance.Net.Objects.Options; using Binance.Net.SymbolOrderBooks; using CryptoExchange.Net.Clients; +using CryptoExchange.Net.SharedApis.Interfaces; using System.Net; namespace Microsoft.Extensions.DependencyInjection @@ -61,6 +63,10 @@ public static IServiceCollection AddBinance( services.AddTransient(x => x.GetRequiredService().SpotApi.CommonSpotClient); services.AddTransient(x => x.GetRequiredService().UsdFuturesApi.CommonFuturesClient); services.AddTransient(x => x.GetRequiredService().CoinFuturesApi.CommonFuturesClient); + + services.RegisterSharedRestInterfaces(x => x.GetRequiredService().SpotApi.SharedClient); + services.RegisterSharedSocketInterfaces(x => x.GetRequiredService().SpotApi.SharedClient); + if (socketClientLifeTime == null) services.AddSingleton(); else diff --git a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs index a87d4b6fc..3f9785934 100644 --- a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs @@ -1,4 +1,5 @@ using CryptoExchange.Net.SharedApis.Interfaces; +using CryptoExchange.Net.SharedApis.Interfaces.Rest; using System; using System.Collections.Generic; using System.Text; @@ -8,8 +9,16 @@ namespace Binance.Net.Interfaces.Clients.CoinFuturesApi public interface IBinanceRestClientCoinFuturesApiShared : ITickerRestClient, IFuturesSymbolRestClient, + IFuturesOrderRestClient, IKlineRestClient, - IRecentTradeRestClient + IRecentTradeRestClient, + ITradeHistoryRestClient, + ILeverageRestClient, + IPositionRestClient, + IMarkKlineRestClient, + IIndexKlineRestClient, + IOrderBookRestClient, + IOpenInterestRestClient { } } diff --git a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs index 5ba8a6d3f..e5b5c981f 100644 --- a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs @@ -6,7 +6,7 @@ namespace Binance.Net.Interfaces.Clients.SpotApi { public interface IBinanceRestClientSpotApiShared: - IAssetRestClient, + IAssetsRestClient, IBalanceRestClient, IDepositRestClient, IKlineRestClient, diff --git a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs index 784d11938..6e4fb5238 100644 --- a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs @@ -1,4 +1,5 @@ using CryptoExchange.Net.SharedApis.Interfaces; +using CryptoExchange.Net.SharedApis.Interfaces.Rest; using System; using System.Collections.Generic; using System.Text; @@ -8,8 +9,16 @@ namespace Binance.Net.Interfaces.Clients.UsdFuturesApi public interface IBinanceRestClientUsdFuturesApiShared : ITickerRestClient, IFuturesSymbolRestClient, + IFuturesOrderRestClient, IKlineRestClient, - IRecentTradeRestClient + IRecentTradeRestClient, + ITradeHistoryRestClient, + ILeverageRestClient, + IPositionRestClient, + IMarkKlineRestClient, + IIndexKlineRestClient, + IOrderBookRestClient, + IOpenInterestRestClient { } } From e854dc6b0d672d0b3bb5bc7cd53f99fc985107b5 Mon Sep 17 00:00:00 2001 From: Jkorf Date: Mon, 2 Sep 2024 16:39:55 +0200 Subject: [PATCH 19/54] wip --- .../BinanceRestClientCoinFuturesApiShared.cs | 127 +++++++++++++---- .../SpotApi/BinanceRestClientSpotApiShared.cs | 25 ++-- .../BinanceSocketClientSpotApiShared.cs | 8 +- .../BinanceRestClientUsdFuturesApiShared.cs | 130 ++++++++++++++---- .../IBinanceRestClientCoinFuturesApiShared.cs | 12 +- .../IBinanceRestClientSpotApiShared.cs | 3 +- .../IBinanceRestClientUsdFuturesApiShared.cs | 12 +- 7 files changed, 235 insertions(+), 82 deletions(-) diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs index 4aa671836..f139dadc5 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -7,7 +7,9 @@ using CryptoExchange.Net.SharedApis.Models.Rest; using CryptoExchange.Net.SharedApis.RequestModels; using CryptoExchange.Net.SharedApis.ResponseModels; -using CryptoExchange.Net.SharedApis.Interfaces.Rest; +using CryptoExchange.Net.SharedApis.Interfaces.Rest.Futures; +using CryptoExchange.Net.SharedApis.Interfaces.Rest.Spot; +using CryptoExchange.Net.SharedApis.Models.EndpointOptions; namespace Binance.Net.Clients.CoinFuturesApi { @@ -90,33 +92,58 @@ async Task>> IFuturesSymbolRe #region Ticker client - EndpointOptions ITickerRestClient.GetTickerOptions { get; } = new EndpointOptions(false); - async Task> ITickerRestClient.GetTickerAsync(GetTickerRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + EndpointOptions IFuturesTickerRestClient.GetFuturesTickerOptions { get; } = new EndpointOptions(false); + async Task> IFuturesTickerRestClient.GetFuturesTickerAsync(GetTickerRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ITickerRestClient)this).GetTickerOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickerOptions.ValidateRequest(Exchange, request, exchangeParameters); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return new ExchangeWebResult(Exchange, validationError); - var result = await ExchangeData.GetTickersAsync(symbol: request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), ct: ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult(Exchange, default); + var resultTicker = ExchangeData.GetTickersAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, ApiType.InverseFutures)), ct: ct); + var resultMarkPrice = ExchangeData.GetMarkPricesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, ApiType.InverseFutures)), ct: ct); + await Task.WhenAll(resultTicker, resultMarkPrice).ConfigureAwait(false); + if (!resultTicker.Result) + return resultTicker.Result.AsExchangeResult(Exchange, default); + if (!resultMarkPrice.Result) + return resultMarkPrice.Result.AsExchangeResult(Exchange, default); - var ticker = result.Data.Single(); - return result.AsExchangeResult(Exchange, new SharedTicker(ticker.Symbol, ticker.LastPrice, ticker.HighPrice, ticker.LowPrice, ticker.Volume)); - } + var ticker = resultTicker.Result.Data.SingleOrDefault(); + var mark = resultMarkPrice.Result.Data.SingleOrDefault(); - EndpointOptions ITickerRestClient.GetTickersOptions { get; } = new EndpointOptions("GetTickersRequest", false); - async Task>> ITickerRestClient.GetTickersAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) - { - var validationError = ((ITickerRestClient)this).GetTickersOptions.ValidateRequest(Exchange, exchangeParameters); - if (validationError != null) - return new ExchangeWebResult>(Exchange, validationError); + if (ticker == null || mark == null) + return resultTicker.Result.AsExchangeError(Exchange, new ServerError("Not found")); - var result = await ExchangeData.GetTickersAsync(ct: ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult>(Exchange, default); + return resultTicker.Result.AsExchangeResult(Exchange, new SharedFuturesTicker(ticker.Symbol, ticker.LastPrice, ticker.HighPrice, ticker.LowPrice, ticker.Volume) + { + IndexPrice = mark.IndexPrice, + MarkPrice = mark.MarkPrice, + FundingRate = mark.FundingRate, + NextFundingTime = mark.NextFundingTime + }); + } - return result.AsExchangeResult(Exchange, result.Data.Select( x => new SharedTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume))); + EndpointOptions IFuturesTickerRestClient.GetFuturesTickersOptions { get; } = new EndpointOptions("GetTickersRequest", false); + async Task>> IFuturesTickerRestClient.GetFuturesTickersAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var resultTickers = ExchangeData.GetTickersAsync(ct: ct); + var resultMarkPrices = ExchangeData.GetMarkPricesAsync(ct: ct); + await Task.WhenAll(resultTickers, resultMarkPrices).ConfigureAwait(false); + if (!resultTickers.Result) + return resultTickers.Result.AsExchangeResult>(Exchange, default); + if (!resultMarkPrices.Result) + return resultMarkPrices.Result.AsExchangeResult>(Exchange, default); + + return resultTickers.Result.AsExchangeResult>(Exchange, resultTickers.Result.Data.Select(x => + { + var markPrice = resultMarkPrices.Result.Data.Single(p => p.Symbol == x.Symbol); + return new SharedFuturesTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume) + { + IndexPrice = markPrice.IndexPrice, + MarkPrice = markPrice.MarkPrice, + FundingRate = markPrice.FundingRate, + NextFundingTime = markPrice.NextFundingTime + }; + })); } #endregion @@ -456,10 +483,18 @@ async Task> ILeverageRestClient.GetLeverageAsy if (!result.Data.Any()) return result.AsExchangeError(Exchange, new ServerError("Not found")); - return result.AsExchangeResult(Exchange, new SharedLeverage(result.Data.FirstOrDefault().Leverage)); + var sideData = + request.Side == SharedPositionSide.Short ? result.Data.SingleOrDefault(x => x.PositionSide == PositionSide.Short) : + request.Side == SharedPositionSide.Long ? result.Data.SingleOrDefault(x => x.PositionSide == PositionSide.Long) : + result.Data.SingleOrDefault(x => x.PositionSide == PositionSide.Both); + + return result.AsExchangeResult(Exchange, new SharedLeverage(sideData.Leverage) + { + Side = request.Side + }); } - EndpointOptions ILeverageRestClient.SetLeverageOptions { get; } = new EndpointOptions(true); + SetLeverageOptions ILeverageRestClient.SetLeverageOptions { get; } = new SetLeverageOptions(false); async Task> ILeverageRestClient.SetLeverageAsync(SetLeverageRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((ILeverageRestClient)this).SetLeverageOptions.ValidateRequest(Exchange, request, exchangeParameters); @@ -470,24 +505,24 @@ async Task> ILeverageRestClient.SetLeverageAsy if (!result) return result.AsExchangeResult(Exchange, default); - return result.AsExchangeResult(Exchange, new SharedLeverage(result.Data.Leverage)); + return result.AsExchangeResult(Exchange, new SharedLeverage(result.Data.Leverage)); } #endregion #region Mark Klines client - GetKlinesOptions IMarkKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(true, false) + GetKlinesOptions IMarkPriceKlineRestClient.GetMarkPriceKlinesOptions { get; } = new GetKlinesOptions(true, false) { MaxRequestDataPoints = 1000 }; - async Task>> IMarkKlineRestClient.GetMarkKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IMarkPriceKlineRestClient.GetMarkPriceKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { var interval = (Enums.KlineInterval)request.Interval; if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IMarkKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IMarkPriceKlineRestClient)this).GetMarkPriceKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -576,18 +611,18 @@ async Task>> ITradeHistoryRestClient. #region Index Klines client - GetKlinesOptions IIndexKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(true, false) + GetKlinesOptions IIndexPriceKlineRestClient.GetIndexPriceKlinesOptions { get; } = new GetKlinesOptions(true, false) { MaxRequestDataPoints = 1000 }; - async Task>> IIndexKlineRestClient.GetIndexKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IIndexPriceKlineRestClient.GetIndexPriceKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { var interval = (Enums.KlineInterval)request.Interval; if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IIndexKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IIndexPriceKlineRestClient)this).GetIndexPriceKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -638,5 +673,37 @@ async Task> IOpenInterestRestClient.GetOpe } #endregion + + #region Funding Rate client + GetFundingRateHistoryOptions IFundingRateRestClient.GetFundingRateHistoryOptions { get; } = new GetFundingRateHistoryOptions(true, false); + + async Task>> IFundingRateRestClient.GetFundingRateHistoryAsync(GetFundingRateHistoryRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IFundingRateRestClient)this).GetFundingRateHistoryOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + + DateTime? fromTime = null; + if (pageToken is DateTimeToken token) + fromTime = token.LastTime; + + // Get data + var result = await ExchangeData.GetFundingRatesAsync( + request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, ApiType.InverseFutures)), + startTime: fromTime ?? request.StartTime, + endTime: request.EndTime, + limit: 1000, + ct: ct).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult>(Exchange, default); + + DateTimeToken? nextToken = null; + if (result.Data.Count() == 1000) + nextToken = new DateTimeToken(result.Data.Max(x => x.FundingTime)); + + // Return + return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedFundingRate(x.FundingRate, x.FundingTime)), nextToken); + } + #endregion } } diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index 652896f92..b40c194da 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -7,6 +7,7 @@ using Binance.Net.Enums; using CryptoExchange.Net.SharedApis.Models.FilterOptions; using CryptoExchange.Net.SharedApis.Models; +using CryptoExchange.Net.SharedApis.Interfaces.Rest.Spot; namespace Binance.Net.Clients.SpotApi { @@ -88,32 +89,32 @@ async Task>> ISpotSymbolRestClie #region Ticker client - EndpointOptions ITickerRestClient.GetTickerOptions { get; } = new EndpointOptions(false); - async Task> ITickerRestClient.GetTickerAsync(GetTickerRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + EndpointOptions ISpotTickerRestClient.GetSpotTickerOptions { get; } = new EndpointOptions(false); + async Task> ISpotTickerRestClient.GetSpotTickerAsync(GetTickerRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ITickerRestClient)this).GetTickerOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((ISpotTickerRestClient)this).GetSpotTickerOptions.ValidateRequest(Exchange, request, exchangeParameters); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return new ExchangeWebResult(Exchange, validationError); var result = await ExchangeData.GetTickerAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult(Exchange, default); + return result.AsExchangeResult(Exchange, default); - return result.AsExchangeResult(Exchange, new SharedTicker(result.Data.Symbol, result.Data.LastPrice, result.Data.HighPrice, result.Data.LowPrice, result.Data.Volume)); + return result.AsExchangeResult(Exchange, new SharedSpotTicker(result.Data.Symbol, result.Data.LastPrice, result.Data.HighPrice, result.Data.LowPrice, result.Data.Volume)); } - EndpointOptions ITickerRestClient.GetTickersOptions { get; } = new EndpointOptions("GetTickersRequest", false); - async Task>> ITickerRestClient.GetTickersAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + EndpointOptions ISpotTickerRestClient.GetSpotTickersOptions { get; } = new EndpointOptions("GetSpotTickersRequest", false); + async Task>> ISpotTickerRestClient.GetSpotTickersAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ITickerRestClient)this).GetTickerOptions.ValidateRequest(Exchange, exchangeParameters); + var validationError = ((ISpotTickerRestClient)this).GetSpotTickerOptions.ValidateRequest(Exchange, exchangeParameters); if (validationError != null) - return new ExchangeWebResult>(Exchange, validationError); + return new ExchangeWebResult>(Exchange, validationError); var result = await ExchangeData.GetTickersAsync(ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult>(Exchange, default); + return result.AsExchangeResult>(Exchange, default); - return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume))); + return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedSpotTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume))); } #endregion diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs index f89b976dd..a176c2f32 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs @@ -17,17 +17,17 @@ internal partial class BinanceSocketClientSpotApi : IBinanceSocketClientSpotApiS { public string Exchange => BinanceExchange.ExchangeName; - async Task> ITickersSocketClient.SubscribeToAllTickerUpdatesAsync(ApiType? apiType, Action>> handler, CancellationToken ct) + async Task> ITickersSocketClient.SubscribeToAllTickerUpdatesAsync(ApiType? apiType, Action>> handler, CancellationToken ct) { - var result = await ExchangeData.SubscribeToAllMiniTickerUpdatesAsync(update => handler(update.As(update.Data.Select(x => new SharedTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume)))), ct).ConfigureAwait(false); + var result = await ExchangeData.SubscribeToAllMiniTickerUpdatesAsync(update => handler(update.As(update.Data.Select(x => new SharedSpotTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume)))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); } - async Task> ITickerSocketClient.SubscribeToTickerUpdatesAsync(TickerSubscribeRequest request, Action> handler, CancellationToken ct) + async Task> ITickerSocketClient.SubscribeToTickerUpdatesAsync(TickerSubscribeRequest request, Action> handler, CancellationToken ct) { var symbol = FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType); - var result = await ExchangeData.SubscribeToMiniTickerUpdatesAsync(symbol, update => handler(update.As(new SharedTicker(update.Data.Symbol, update.Data.LastPrice, update.Data.HighPrice, update.Data.LowPrice, update.Data.Volume))), ct).ConfigureAwait(false); + var result = await ExchangeData.SubscribeToMiniTickerUpdatesAsync(symbol, update => handler(update.As(new SharedSpotTicker(update.Data.Symbol, update.Data.LastPrice, update.Data.HighPrice, update.Data.LowPrice, update.Data.Volume))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); } diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs index 005b8a378..40b724f0b 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -2,8 +2,10 @@ using Binance.Net.Interfaces.Clients.UsdFuturesApi; using CryptoExchange.Net.SharedApis.Enums; using CryptoExchange.Net.SharedApis.Interfaces; -using CryptoExchange.Net.SharedApis.Interfaces.Rest; +using CryptoExchange.Net.SharedApis.Interfaces.Rest.Futures; +using CryptoExchange.Net.SharedApis.Interfaces.Rest.Spot; using CryptoExchange.Net.SharedApis.Models; +using CryptoExchange.Net.SharedApis.Models.EndpointOptions; using CryptoExchange.Net.SharedApis.Models.FilterOptions; using CryptoExchange.Net.SharedApis.Models.Rest; using CryptoExchange.Net.SharedApis.RequestModels; @@ -67,18 +69,18 @@ async Task>> IKlineRestClient.GetKlin #region Mark Klines client - GetKlinesOptions IMarkKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(true, false) + GetKlinesOptions IMarkPriceKlineRestClient.GetMarkPriceKlinesOptions { get; } = new GetKlinesOptions(true, false) { MaxRequestDataPoints = 1000 }; - async Task>> IMarkKlineRestClient.GetMarkKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IMarkPriceKlineRestClient.GetMarkPriceKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { var interval = (Enums.KlineInterval)request.Interval; if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IMarkKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IMarkPriceKlineRestClient)this).GetMarkPriceKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -140,28 +142,53 @@ async Task>> IFuturesSymbolRe #region Ticker client - EndpointOptions ITickerRestClient.GetTickerOptions { get; } = new EndpointOptions(false); - async Task> ITickerRestClient.GetTickerAsync(GetTickerRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + EndpointOptions IFuturesTickerRestClient.GetFuturesTickerOptions { get; } = new EndpointOptions(false); + async Task> IFuturesTickerRestClient.GetFuturesTickerAsync(GetTickerRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ITickerRestClient)this).GetTickerOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickerOptions.ValidateRequest(Exchange, request, exchangeParameters); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return new ExchangeWebResult(Exchange, validationError); - var result = await ExchangeData.GetTickerAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult(Exchange, default); + var resultTicker = ExchangeData.GetTickerAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), ct); + var resultMarkPrice = ExchangeData.GetMarkPriceAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), ct); + await Task.WhenAll(resultTicker, resultMarkPrice).ConfigureAwait(false); + + if (!resultTicker.Result) + return resultTicker.Result.AsExchangeResult(Exchange, default); + if (!resultMarkPrice.Result) + return resultMarkPrice.Result.AsExchangeResult(Exchange, default); - return result.AsExchangeResult(Exchange, new SharedTicker(result.Data.Symbol, result.Data.LastPrice, result.Data.HighPrice, result.Data.LowPrice, result.Data.Volume)); + return resultTicker.Result.AsExchangeResult(Exchange, new SharedFuturesTicker(resultTicker.Result.Data.Symbol, resultTicker.Result.Data.LastPrice, resultTicker.Result.Data.HighPrice, resultTicker.Result.Data.LowPrice, resultTicker.Result.Data.Volume) + { + MarkPrice = resultMarkPrice.Result.Data.MarkPrice, + IndexPrice = resultMarkPrice.Result.Data.IndexPrice, + FundingRate = resultMarkPrice.Result.Data.FundingRate, + NextFundingTime = resultMarkPrice.Result.Data.NextFundingTime + }); } - EndpointOptions ITickerRestClient.GetTickersOptions { get; } = new EndpointOptions("GetTickersRequest", false); - async Task>> ITickerRestClient.GetTickersAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + EndpointOptions IFuturesTickerRestClient.GetFuturesTickersOptions { get; } = new EndpointOptions("GetTickersRequest", false); + async Task>> IFuturesTickerRestClient.GetFuturesTickersAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var result = await ExchangeData.GetTickersAsync(ct: ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult>(Exchange, default); - - return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume))); + var resultTickers = ExchangeData.GetTickersAsync(ct: ct); + var resultMarkPrices = ExchangeData.GetMarkPricesAsync(ct: ct); + await Task.WhenAll(resultTickers, resultMarkPrices).ConfigureAwait(false); + if (!resultTickers.Result) + return resultTickers.Result.AsExchangeResult>(Exchange, default); + if (!resultMarkPrices.Result) + return resultMarkPrices.Result.AsExchangeResult>(Exchange, default); + + return resultTickers.Result.AsExchangeResult>(Exchange, resultTickers.Result.Data.Select(x => + { + var markPrice = resultMarkPrices.Result.Data.Single(p => p.Symbol == x.Symbol); + return new SharedFuturesTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume) + { + IndexPrice = markPrice.IndexPrice, + MarkPrice = markPrice.MarkPrice, + FundingRate = markPrice.FundingRate, + NextFundingTime = markPrice.NextFundingTime + }; + })); } #endregion @@ -222,6 +249,7 @@ async Task> IFuturesOrderRestClient.PlaceFuturesOrde positionSide: request.PositionSide == SharedPositionSide.Both ? PositionSide.Both : request.PositionSide == SharedPositionSide.Long ? PositionSide.Long : PositionSide.Short, reduceOnly: request.ReduceOnly, closePosition: request.ClosePosition, + timeInForce: GetTimeInForce(request.TimeInForce), newClientOrderId: request.ClientOrderId).ConfigureAwait(false); if (!result) @@ -434,6 +462,18 @@ async Task> IFuturesOrderRestClient.CancelFuturesOrd return order.AsExchangeResult(Exchange, new SharedId(order.Data.Id.ToString())); } + private TimeInForce? GetTimeInForce(SharedTimeInForce? tif) + { + if (tif == null) + return null; + + if (tif == SharedTimeInForce.ImmediateOrCancel) return TimeInForce.ImmediateOrCancel; + if (tif == SharedTimeInForce.FillOrKill) return TimeInForce.FillOrKill; + if (tif == SharedTimeInForce.GoodTillCanceled) return TimeInForce.GoodTillCanceled; + + return null; + } + private SharedOrderStatus ParseOrderStatus(OrderStatus status) { if (status == OrderStatus.PendingNew || status == OrderStatus.New || status == OrderStatus.PartiallyFilled || status == OrderStatus.PendingCancel) return SharedOrderStatus.Open; @@ -501,10 +541,18 @@ async Task> ILeverageRestClient.GetLeverageAsy if (!result.Data.Any()) return result.AsExchangeError(Exchange, new ServerError("Not found")); - return result.AsExchangeResult(Exchange, new SharedLeverage(result.Data.FirstOrDefault().Leverage)); + var sideData = + request.Side == SharedPositionSide.Short ? result.Data.SingleOrDefault(x => x.PositionSide == PositionSide.Short) : + request.Side == SharedPositionSide.Long ? result.Data.SingleOrDefault(x => x.PositionSide == PositionSide.Long) : + result.Data.SingleOrDefault(x => x.PositionSide == PositionSide.Both); + + return result.AsExchangeResult(Exchange, new SharedLeverage(sideData.Leverage) + { + Side = request.Side + }); } - EndpointOptions ILeverageRestClient.SetLeverageOptions { get; } = new EndpointOptions(true); + SetLeverageOptions ILeverageRestClient.SetLeverageOptions { get; } = new SetLeverageOptions(false); async Task> ILeverageRestClient.SetLeverageAsync(SetLeverageRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((ILeverageRestClient)this).SetLeverageOptions.ValidateRequest(Exchange, request, exchangeParameters); @@ -515,7 +563,7 @@ async Task> ILeverageRestClient.SetLeverageAsy if (!result) return result.AsExchangeResult(Exchange, default); - return result.AsExchangeResult(Exchange, new SharedLeverage(result.Data.Leverage)); + return result.AsExchangeResult(Exchange, new SharedLeverage(result.Data.Leverage)); } #endregion @@ -574,18 +622,18 @@ async Task>> ITradeHistoryRestClient. #region Index Klines client - GetKlinesOptions IIndexKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(true, false) + GetKlinesOptions IIndexPriceKlineRestClient.GetIndexPriceKlinesOptions { get; } = new GetKlinesOptions(true, false) { MaxRequestDataPoints = 1000 }; - async Task>> IIndexKlineRestClient.GetIndexKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IIndexPriceKlineRestClient.GetIndexPriceKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { var interval = (Enums.KlineInterval)request.Interval; if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IIndexKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IIndexPriceKlineRestClient)this).GetIndexPriceKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -636,5 +684,37 @@ async Task> IOpenInterestRestClient.GetOpe } #endregion + + #region Funding Rate client + GetFundingRateHistoryOptions IFundingRateRestClient.GetFundingRateHistoryOptions { get; } = new GetFundingRateHistoryOptions(true, false); + + async Task>> IFundingRateRestClient.GetFundingRateHistoryAsync(GetFundingRateHistoryRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IFundingRateRestClient)this).GetFundingRateHistoryOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + + DateTime? fromTime = null; + if (pageToken is DateTimeToken token) + fromTime = token.LastTime; + + // Get data + var result = await ExchangeData.GetFundingRatesAsync( + request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), + startTime: fromTime ?? request.StartTime, + endTime: request.EndTime, + limit: 1000, + ct: ct).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult>(Exchange, default); + + DateTimeToken? nextToken = null; + if (result.Data.Count() == 1000) + nextToken = new DateTimeToken(result.Data.Max(x => x.FundingTime)); + + // Return + return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedFundingRate(x.FundingRate, x.FundingTime)), nextToken); + } + #endregion } } diff --git a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs index 3f9785934..c9803352d 100644 --- a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs @@ -1,5 +1,6 @@ using CryptoExchange.Net.SharedApis.Interfaces; -using CryptoExchange.Net.SharedApis.Interfaces.Rest; +using CryptoExchange.Net.SharedApis.Interfaces.Rest.Futures; +using CryptoExchange.Net.SharedApis.Interfaces.Rest.Spot; using System; using System.Collections.Generic; using System.Text; @@ -7,7 +8,7 @@ namespace Binance.Net.Interfaces.Clients.CoinFuturesApi { public interface IBinanceRestClientCoinFuturesApiShared : - ITickerRestClient, + IFuturesTickerRestClient, IFuturesSymbolRestClient, IFuturesOrderRestClient, IKlineRestClient, @@ -15,10 +16,11 @@ public interface IBinanceRestClientCoinFuturesApiShared : ITradeHistoryRestClient, ILeverageRestClient, IPositionRestClient, - IMarkKlineRestClient, - IIndexKlineRestClient, + IMarkPriceKlineRestClient, + IIndexPriceKlineRestClient, IOrderBookRestClient, - IOpenInterestRestClient + IOpenInterestRestClient, + IFundingRateRestClient { } } diff --git a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs index e5b5c981f..badcc5100 100644 --- a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs @@ -1,4 +1,5 @@ using CryptoExchange.Net.SharedApis.Interfaces; +using CryptoExchange.Net.SharedApis.Interfaces.Rest.Spot; using System; using System.Collections.Generic; using System.Text; @@ -14,7 +15,7 @@ public interface IBinanceRestClientSpotApiShared: IRecentTradeRestClient, ISpotOrderRestClient, ISpotSymbolRestClient, - ITickerRestClient, + ISpotTickerRestClient, ITradeHistoryRestClient, IWithdrawalRestClient, IWithdrawRestClient diff --git a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs index 6e4fb5238..5cf74388b 100644 --- a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs @@ -1,5 +1,6 @@ using CryptoExchange.Net.SharedApis.Interfaces; -using CryptoExchange.Net.SharedApis.Interfaces.Rest; +using CryptoExchange.Net.SharedApis.Interfaces.Rest.Futures; +using CryptoExchange.Net.SharedApis.Interfaces.Rest.Spot; using System; using System.Collections.Generic; using System.Text; @@ -7,7 +8,7 @@ namespace Binance.Net.Interfaces.Clients.UsdFuturesApi { public interface IBinanceRestClientUsdFuturesApiShared : - ITickerRestClient, + IFuturesTickerRestClient, IFuturesSymbolRestClient, IFuturesOrderRestClient, IKlineRestClient, @@ -15,10 +16,11 @@ public interface IBinanceRestClientUsdFuturesApiShared : ITradeHistoryRestClient, ILeverageRestClient, IPositionRestClient, - IMarkKlineRestClient, - IIndexKlineRestClient, + IMarkPriceKlineRestClient, + IIndexPriceKlineRestClient, IOrderBookRestClient, - IOpenInterestRestClient + IOpenInterestRestClient, + IFundingRateRestClient { } } From 2ab6cc28c9665f858e84e92268368e937dc2c79c Mon Sep 17 00:00:00 2001 From: Jkorf Date: Tue, 3 Sep 2024 16:28:34 +0200 Subject: [PATCH 20/54] wip --- .../BinanceRestClientCoinFuturesApiShared.cs | 85 +++++++++++++------ .../BinanceRestClientUsdFuturesApiShared.cs | 85 +++++++++++++------ .../IBinanceRestClientCoinFuturesApiShared.cs | 4 +- .../IBinanceRestClientUsdFuturesApiShared.cs | 2 +- 4 files changed, 123 insertions(+), 53 deletions(-) diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs index f139dadc5..c3bfc0a2b 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -203,7 +203,6 @@ async Task> IFuturesOrderRestClient.PlaceFuturesOrde price: request.Price, positionSide: request.PositionSide == SharedPositionSide.Both ? PositionSide.Both : request.PositionSide == SharedPositionSide.Long ? PositionSide.Long: PositionSide.Short, reduceOnly: request.ReduceOnly, - closePosition: request.ClosePosition, newClientOrderId: request.ClientOrderId).ConfigureAwait(false); if (!result) @@ -416,6 +415,48 @@ async Task> IFuturesOrderRestClient.CancelFuturesOrd return order.AsExchangeResult(Exchange, new SharedId(order.Data.Id.ToString())); } + EndpointOptions IFuturesOrderRestClient.GetPositionsOptions { get; } = new EndpointOptions(true); + async Task>> IFuturesOrderRestClient.GetPositionsAsync(GetPositionsRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IFuturesOrderRestClient)this).GetPositionsOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + + var result = await Account.GetPositionInformationAsync(pair: request.Symbol?.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), ct: ct).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult>(Exchange, default); + + return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedPosition(x.Symbol, x.Quantity, x.UpdateTime) + { + UnrealizedPnl = x.UnrealizedPnl, + LiquidationPrice = x.LiquidationPrice, + Leverage = x.Leverage, + AverageEntryPrice = x.EntryPrice, + PositionSide = x.PositionSide == PositionSide.Both ? SharedPositionSide.Both : x.PositionSide == PositionSide.Short ? SharedPositionSide.Short : SharedPositionSide.Long + }).ToList()); + } + + EndpointOptions IFuturesOrderRestClient.ClosePositionOptions { get; } = new EndpointOptions(true); + async Task> IFuturesOrderRestClient.ClosePositionAsync(ClosePositionRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IFuturesOrderRestClient)this).ClosePositionOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + + var result = await Trading.PlaceOrderAsync( + request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), + request.PositionSide == SharedPositionSide.Long ? OrderSide.Sell : OrderSide.Buy, +#warning check if works correctly. If side is both, what to do..? + FuturesOrderType.Market, + null, + closePosition: true, + ct: ct).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult(Exchange, default); + + return result.AsExchangeResult(Exchange, new SharedId(result.Data.Id.ToString())); + } + private SharedOrderStatus ParseOrderStatus(OrderStatus status) { if (status == OrderStatus.PendingNew || status == OrderStatus.New || status == OrderStatus.PartiallyFilled || status == OrderStatus.PendingCancel) return SharedOrderStatus.Open; @@ -443,30 +484,6 @@ private SharedOrderType ParseOrderType(FuturesOrderType type) #endregion - #region Positions client - - EndpointOptions IPositionRestClient.GetPositionsOptions { get; } = new EndpointOptions(true); - async Task>> IPositionRestClient.GetPositionsAsync(GetPositionsRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) - { - var validationError = ((IPositionRestClient)this).GetPositionsOptions.ValidateRequest(Exchange, request, exchangeParameters); - if (validationError != null) - return new ExchangeWebResult>(Exchange, validationError); - - var result = await Account.GetPositionInformationAsync(pair: request.Symbol?.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), ct: ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult>(Exchange, default); - - return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedPosition(x.Symbol, x.Quantity, x.UpdateTime) - { - UnrealizedPnl = x.UnrealizedPnl, - LiquidationPrice = x.LiquidationPrice, - AverageEntryPrice = x.EntryPrice, - PositionSide = x.PositionSide == PositionSide.Both ? SharedPositionSide.Both : x.PositionSide == PositionSide.Short ? SharedPositionSide.Short : SharedPositionSide.Long - }).ToList()); - } - - #endregion - #region Leverage client EndpointOptions ILeverageRestClient.GetLeverageOptions { get; } = new EndpointOptions(true); @@ -705,5 +722,23 @@ async Task>> IFundingRateRestCl return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedFundingRate(x.FundingRate, x.FundingTime)), nextToken); } #endregion + + #region Balance Client + EndpointOptions IBalanceRestClient.GetBalancesOptions { get; } = new EndpointOptions("GetBalancesRequest", true); + + async Task>> IBalanceRestClient.GetBalancesAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IBalanceRestClient)this).GetBalancesOptions.ValidateRequest(Exchange, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + + var result = await Account.GetBalancesAsync(ct: ct).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult>(Exchange, default); + + return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedBalance(x.Asset, x.AvailableBalance, x.WalletBalance))); + } + + #endregion } } diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs index 40b724f0b..c9658860d 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -248,7 +248,6 @@ async Task> IFuturesOrderRestClient.PlaceFuturesOrde price: request.Price, positionSide: request.PositionSide == SharedPositionSide.Both ? PositionSide.Both : request.PositionSide == SharedPositionSide.Long ? PositionSide.Long : PositionSide.Short, reduceOnly: request.ReduceOnly, - closePosition: request.ClosePosition, timeInForce: GetTimeInForce(request.TimeInForce), newClientOrderId: request.ClientOrderId).ConfigureAwait(false); @@ -462,6 +461,48 @@ async Task> IFuturesOrderRestClient.CancelFuturesOrd return order.AsExchangeResult(Exchange, new SharedId(order.Data.Id.ToString())); } + EndpointOptions IFuturesOrderRestClient.GetPositionsOptions { get; } = new EndpointOptions(true); + async Task>> IFuturesOrderRestClient.GetPositionsAsync(GetPositionsRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IFuturesOrderRestClient)this).GetPositionsOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + + var result = await Account.GetPositionInformationAsync(symbol: request.Symbol?.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), ct: ct).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult>(Exchange, default); + + return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedPosition(x.Symbol, x.Quantity, x.UpdateTime) + { + UnrealizedPnl = x.UnrealizedPnl, + LiquidationPrice = x.LiquidationPrice, + Leverage = x.Leverage, + AverageEntryPrice = x.EntryPrice, + PositionSide = x.PositionSide == PositionSide.Both ? SharedPositionSide.Both : x.PositionSide == PositionSide.Short ? SharedPositionSide.Short : SharedPositionSide.Long + }).ToList()); + } + + EndpointOptions IFuturesOrderRestClient.ClosePositionOptions { get; } = new EndpointOptions(true); + async Task> IFuturesOrderRestClient.ClosePositionAsync(ClosePositionRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IFuturesOrderRestClient)this).ClosePositionOptions.ValidateRequest(Exchange, request, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + + var result = await Trading.PlaceOrderAsync( + request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), + request.PositionSide == SharedPositionSide.Long ? OrderSide.Sell : OrderSide.Buy, +#warning check if works correctly. If side is both, what to do..? + FuturesOrderType.Market, + null, + closePosition: true, + ct: ct).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult(Exchange, default); + + return result.AsExchangeResult(Exchange, new SharedId(result.Data.Id.ToString())); + } + private TimeInForce? GetTimeInForce(SharedTimeInForce? tif) { if (tif == null) @@ -501,30 +542,6 @@ private SharedOrderType ParseOrderType(FuturesOrderType type) #endregion - #region Positions client - - EndpointOptions IPositionRestClient.GetPositionsOptions { get; } = new EndpointOptions(true); - async Task>> IPositionRestClient.GetPositionsAsync(GetPositionsRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) - { - var validationError = ((IPositionRestClient)this).GetPositionsOptions.ValidateRequest(Exchange, request, exchangeParameters); - if (validationError != null) - return new ExchangeWebResult>(Exchange, validationError); - - var result = await Account.GetPositionInformationAsync(symbol: request.Symbol?.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), ct: ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult>(Exchange, default); - - return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedPosition(x.Symbol, x.Quantity, x.UpdateTime) - { - UnrealizedPnl = x.UnrealizedPnl, - LiquidationPrice = x.LiquidationPrice, - AverageEntryPrice = x.EntryPrice, - PositionSide = x.PositionSide == PositionSide.Both ? SharedPositionSide.Both : x.PositionSide == PositionSide.Short ? SharedPositionSide.Short : SharedPositionSide.Long - }).ToList()); - } - - #endregion - #region Leverage client EndpointOptions ILeverageRestClient.GetLeverageOptions { get; } = new EndpointOptions(true); @@ -716,5 +733,23 @@ async Task>> IFundingRateRestCl return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedFundingRate(x.FundingRate, x.FundingTime)), nextToken); } #endregion + + #region Balance Client + EndpointOptions IBalanceRestClient.GetBalancesOptions { get; } = new EndpointOptions("GetBalancesRequest", true); + + async Task>> IBalanceRestClient.GetBalancesAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IBalanceRestClient)this).GetBalancesOptions.ValidateRequest(Exchange, exchangeParameters); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + + var result = await Account.GetBalancesAsync(ct: ct).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult>(Exchange, default); + + return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedBalance(x.Asset, x.AvailableBalance, x.WalletBalance))); + } + + #endregion } } diff --git a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs index c9803352d..116a5acc6 100644 --- a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs @@ -15,12 +15,12 @@ public interface IBinanceRestClientCoinFuturesApiShared : IRecentTradeRestClient, ITradeHistoryRestClient, ILeverageRestClient, - IPositionRestClient, IMarkPriceKlineRestClient, IIndexPriceKlineRestClient, IOrderBookRestClient, IOpenInterestRestClient, - IFundingRateRestClient + IFundingRateRestClient, + IBalanceRestClient { } } diff --git a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs index 5cf74388b..1aa699ac2 100644 --- a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs @@ -8,6 +8,7 @@ namespace Binance.Net.Interfaces.Clients.UsdFuturesApi { public interface IBinanceRestClientUsdFuturesApiShared : + IBalanceRestClient, IFuturesTickerRestClient, IFuturesSymbolRestClient, IFuturesOrderRestClient, @@ -15,7 +16,6 @@ public interface IBinanceRestClientUsdFuturesApiShared : IRecentTradeRestClient, ITradeHistoryRestClient, ILeverageRestClient, - IPositionRestClient, IMarkPriceKlineRestClient, IIndexPriceKlineRestClient, IOrderBookRestClient, From 4a68b15f111ef85b1cd436a2996289f2348b5228 Mon Sep 17 00:00:00 2001 From: Jkorf Date: Wed, 4 Sep 2024 14:53:16 +0200 Subject: [PATCH 21/54] wip --- .../CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs | 2 +- Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs | 2 +- .../Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs | 3 +-- .../UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs index c3bfc0a2b..66316150f 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -77,7 +77,7 @@ async Task>> IFuturesSymbolRe if (!result) return result.AsExchangeResult>(Exchange, default); - return result.AsExchangeResult(Exchange, result.Data.Symbols.Select(s => new SharedFuturesSymbol(s.BaseAsset, s.QuoteAsset, s.Name) + return result.AsExchangeResult(Exchange, result.Data.Symbols.Select(s => new SharedFuturesSymbol(s.ContractType == ContractType.Perpetual ? SharedSymbolType.PerpetualInverse : SharedSymbolType.DeliveryInverse, s.BaseAsset, s.QuoteAsset, s.Name) { MinTradeQuantity = s.LotSizeFilter?.MinQuantity, MaxTradeQuantity = s.LotSizeFilter?.MaxQuantity, diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index b40c194da..723271ccc 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -104,7 +104,7 @@ async Task> ISpotTickerRestClient.GetSpotTic } EndpointOptions ISpotTickerRestClient.GetSpotTickersOptions { get; } = new EndpointOptions("GetSpotTickersRequest", false); - async Task>> ISpotTickerRestClient.GetSpotTickersAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> ISpotTickerRestClient.GetSpotTickersAsync(ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((ISpotTickerRestClient)this).GetSpotTickerOptions.ValidateRequest(Exchange, exchangeParameters); if (validationError != null) diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs index 9be3d1409..67a855443 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs @@ -51,8 +51,7 @@ internal partial class BinanceRestClientUsdFuturesApi : RestApiClient, IBinanceR /// public override string FormatSymbol(string baseAsset, string quoteAsset, ApiType? futuresType = null) { - var suffix = futuresType == null ? string.Empty : "_PERP"; // _PERP Actually ever needed? - return baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + suffix; + return baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); } #region constructor/destructor diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs index c9658860d..0b5ecbb53 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -127,7 +127,7 @@ async Task>> IFuturesSymbolRe if (!result) return result.AsExchangeResult< IEnumerable>(Exchange, default); - return result.AsExchangeResult(Exchange, result.Data.Symbols.Select(s => new SharedFuturesSymbol(s.BaseAsset, s.QuoteAsset, s.Name) + return result.AsExchangeResult(Exchange, result.Data.Symbols.Select(s => new SharedFuturesSymbol(s.ContractType == ContractType.Perpetual ? SharedSymbolType.PerpetualLinear : SharedSymbolType.DeliveryLinear, s.BaseAsset, s.QuoteAsset, s.Name) { MinTradeQuantity = s.LotSizeFilter?.MinQuantity, MaxTradeQuantity = s.LotSizeFilter?.MaxQuantity, From b5b6c185b61b620578abe3139dc8f65a153f2d6a Mon Sep 17 00:00:00 2001 From: Jkorf Date: Wed, 4 Sep 2024 16:30:20 +0200 Subject: [PATCH 22/54] wip --- .../BinanceRestClientCoinFuturesApiShared.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs index 66316150f..0dad2aef7 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -99,8 +99,8 @@ async Task> IFuturesTickerRestClient.GetF if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var resultTicker = ExchangeData.GetTickersAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, ApiType.InverseFutures)), ct: ct); - var resultMarkPrice = ExchangeData.GetMarkPricesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, ApiType.InverseFutures)), ct: ct); + var resultTicker = ExchangeData.GetTickersAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), ct: ct); + var resultMarkPrice = ExchangeData.GetMarkPricesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), ct: ct); await Task.WhenAll(resultTicker, resultMarkPrice).ConfigureAwait(false); if (!resultTicker.Result) return resultTicker.Result.AsExchangeResult(Exchange, default); @@ -549,7 +549,7 @@ async Task>> IMarkPriceKlineRestC fromTimestamp = dateTimeToken.LastTime; var result = await ExchangeData.GetMarkPriceKlinesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, ApiType.InverseFutures)), + request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), interval, request.Filter?.Limit ?? 1000, fromTimestamp ?? request.Filter?.StartTime, @@ -608,7 +608,7 @@ async Task>> ITradeHistoryRestClient. // Get data var result = await ExchangeData.GetAggregatedTradeHistoryAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, ApiType.InverseFutures)), + request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), startTime: fromId != null ? null : request.StartTime, endTime: fromId != null ? null : request.EndTime, limit: 1000, @@ -682,7 +682,7 @@ async Task> IOpenInterestRestClient.GetOpe if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var result = await ExchangeData.GetOpenInterestAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, ApiType.InverseFutures)), ct: ct).ConfigureAwait(false); + var result = await ExchangeData.GetOpenInterestAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -706,7 +706,7 @@ async Task>> IFundingRateRestCl // Get data var result = await ExchangeData.GetFundingRatesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, ApiType.InverseFutures)), + request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), startTime: fromTime ?? request.StartTime, endTime: request.EndTime, limit: 1000, From db82414e683bbb3ba13a6f636188c43f5de50c2f Mon Sep 17 00:00:00 2001 From: JKorf Date: Wed, 4 Sep 2024 22:14:19 +0200 Subject: [PATCH 23/54] wip --- .../BinanceRestClientCoinFuturesApiShared.cs | 56 ++++++++++--------- .../SpotApi/BinanceRestClientSpotApiShared.cs | 45 +++++++-------- .../BinanceSocketClientSpotApiShared.cs | 1 + .../BinanceRestClientUsdFuturesApiShared.cs | 56 ++++++++++--------- 4 files changed, 86 insertions(+), 72 deletions(-) diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs index 0dad2aef7..3ae82347f 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -17,6 +17,8 @@ internal partial class BinanceRestClientCoinFuturesApi : IBinanceRestClientCoinF { public string Exchange => BinanceExchange.ExchangeName; + public ApiType[] SupportedApiTypes => new[] { ApiType.DeliveryInverse, ApiType.PerpetualInverse }; + #region Klines client GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(true, false) @@ -30,7 +32,7 @@ async Task>> IKlineRestClient.GetKlin if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -67,9 +69,9 @@ async Task>> IKlineRestClient.GetKlin #region Futures Symbol client EndpointOptions IFuturesSymbolRestClient.GetFuturesSymbolsOptions { get; } = new EndpointOptions("GetFuturesSymbolsRequest", false); - async Task>> IFuturesSymbolRestClient.GetFuturesSymbolsAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IFuturesSymbolRestClient.GetFuturesSymbolsAsync(ApiType apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesSymbolRestClient)this).GetFuturesSymbolsOptions.ValidateRequest(Exchange, exchangeParameters); + var validationError = ((IFuturesSymbolRestClient)this).GetFuturesSymbolsOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -95,7 +97,7 @@ async Task>> IFuturesSymbolRe EndpointOptions IFuturesTickerRestClient.GetFuturesTickerOptions { get; } = new EndpointOptions(false); async Task> IFuturesTickerRestClient.GetFuturesTickerAsync(GetTickerRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickerOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -123,8 +125,12 @@ async Task> IFuturesTickerRestClient.GetF } EndpointOptions IFuturesTickerRestClient.GetFuturesTickersOptions { get; } = new EndpointOptions("GetTickersRequest", false); - async Task>> IFuturesTickerRestClient.GetFuturesTickersAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IFuturesTickerRestClient.GetFuturesTickersAsync(ApiType apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { + var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickerOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + var resultTickers = ExchangeData.GetTickersAsync(ct: ct); var resultMarkPrices = ExchangeData.GetMarkPricesAsync(ct: ct); await Task.WhenAll(resultTickers, resultMarkPrices).ConfigureAwait(false); @@ -153,7 +159,7 @@ async Task>> IFuturesTickerRe GetRecentTradesOptions IRecentTradeRestClient.GetRecentTradesOptions { get; } = new GetRecentTradesOptions(1000, false); async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IRecentTradeRestClient)this).GetRecentTradesOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IRecentTradeRestClient)this).GetRecentTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -191,7 +197,7 @@ async Task>> IRecentTradeRestClient.G async Task> IFuturesOrderRestClient.PlaceFuturesOrderAsync(PlaceFuturesOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).PlaceFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IFuturesOrderRestClient)this).PlaceFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -214,7 +220,7 @@ async Task> IFuturesOrderRestClient.PlaceFuturesOrde EndpointOptions IFuturesOrderRestClient.GetFuturesOrderOptions { get; } = new EndpointOptions(true); async Task> IFuturesOrderRestClient.GetFuturesOrderAsync(GetOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -249,7 +255,7 @@ async Task> IFuturesOrderRestClient.GetFut EndpointOptions IFuturesOrderRestClient.GetOpenFuturesOrdersOptions { get; } = new EndpointOptions(true); async Task>> IFuturesOrderRestClient.GetOpenFuturesOrdersAsync(GetOpenOrdersRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetOpenFuturesOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IFuturesOrderRestClient)this).GetOpenFuturesOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -282,7 +288,7 @@ async Task>> IFuturesOrderRest PaginatedEndpointOptions IFuturesOrderRestClient.GetClosedFuturesOrdersOptions { get; } = new PaginatedEndpointOptions(true, true); async Task>> IFuturesOrderRestClient.GetClosedFuturesOrdersAsync(GetClosedOrdersRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetClosedFuturesOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IFuturesOrderRestClient)this).GetClosedFuturesOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -328,7 +334,7 @@ async Task>> IFuturesOrderRest EndpointOptions IFuturesOrderRestClient.GetFuturesOrderTradesOptions { get; } = new EndpointOptions(true); async Task>> IFuturesOrderRestClient.GetFuturesOrderTradesAsync(GetOrderTradesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderTradesOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -358,7 +364,7 @@ async Task>> IFuturesOrderRestCli PaginatedEndpointOptions IFuturesOrderRestClient.GetFuturesUserTradesOptions { get; } = new PaginatedEndpointOptions(true, true); async Task>> IFuturesOrderRestClient.GetFuturesUserTradesAsync(GetUserTradesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetFuturesUserTradesOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IFuturesOrderRestClient)this).GetFuturesUserTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -401,7 +407,7 @@ async Task>> IFuturesOrderRestCli EndpointOptions IFuturesOrderRestClient.CancelFuturesOrderOptions { get; } = new EndpointOptions(true); async Task> IFuturesOrderRestClient.CancelFuturesOrderAsync(CancelOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).CancelFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IFuturesOrderRestClient)this).CancelFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -418,7 +424,7 @@ async Task> IFuturesOrderRestClient.CancelFuturesOrd EndpointOptions IFuturesOrderRestClient.GetPositionsOptions { get; } = new EndpointOptions(true); async Task>> IFuturesOrderRestClient.GetPositionsAsync(GetPositionsRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetPositionsOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IFuturesOrderRestClient)this).GetPositionsOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -439,7 +445,7 @@ async Task>> IFuturesOrderRestClie EndpointOptions IFuturesOrderRestClient.ClosePositionOptions { get; } = new EndpointOptions(true); async Task> IFuturesOrderRestClient.ClosePositionAsync(ClosePositionRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).ClosePositionOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IFuturesOrderRestClient)this).ClosePositionOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -489,7 +495,7 @@ private SharedOrderType ParseOrderType(FuturesOrderType type) EndpointOptions ILeverageRestClient.GetLeverageOptions { get; } = new EndpointOptions(true); async Task> ILeverageRestClient.GetLeverageAsync(GetLeverageRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ILeverageRestClient)this).GetLeverageOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((ILeverageRestClient)this).GetLeverageOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -514,7 +520,7 @@ async Task> ILeverageRestClient.GetLeverageAsy SetLeverageOptions ILeverageRestClient.SetLeverageOptions { get; } = new SetLeverageOptions(false); async Task> ILeverageRestClient.SetLeverageAsync(SetLeverageRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ILeverageRestClient)this).SetLeverageOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((ILeverageRestClient)this).SetLeverageOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -539,7 +545,7 @@ async Task>> IMarkPriceKlineRestC if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IMarkPriceKlineRestClient)this).GetMarkPriceKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IMarkPriceKlineRestClient)this).GetMarkPriceKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -577,7 +583,7 @@ async Task>> IMarkPriceKlineRestC GetOrderBookOptions IOrderBookRestClient.GetOrderBookOptions { get; } = new GetOrderBookOptions(new[] { 5, 10, 20, 50, 100, 500, 1000 }, false); async Task> IOrderBookRestClient.GetOrderBookAsync(GetOrderBookRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -598,7 +604,7 @@ async Task> IOrderBookRestClient.GetOrderBook async Task>> ITradeHistoryRestClient.GetTradeHistoryAsync(GetTradeHistoryRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ITradeHistoryRestClient)this).GetTradeHistoryOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((ITradeHistoryRestClient)this).GetTradeHistoryOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -639,7 +645,7 @@ async Task>> IIndexPriceKlineRest if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IIndexPriceKlineRestClient)this).GetIndexPriceKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IIndexPriceKlineRestClient)this).GetIndexPriceKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -678,7 +684,7 @@ async Task>> IIndexPriceKlineRest EndpointOptions IOpenInterestRestClient.GetOpenInterestOptions { get; } = new EndpointOptions(true); async Task> IOpenInterestRestClient.GetOpenInterestAsync(GetOpenInterestRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IOpenInterestRestClient)this).GetOpenInterestOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IOpenInterestRestClient)this).GetOpenInterestOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -696,7 +702,7 @@ async Task> IOpenInterestRestClient.GetOpe async Task>> IFundingRateRestClient.GetFundingRateHistoryAsync(GetFundingRateHistoryRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFundingRateRestClient)this).GetFundingRateHistoryOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IFundingRateRestClient)this).GetFundingRateHistoryOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -726,9 +732,9 @@ async Task>> IFundingRateRestCl #region Balance Client EndpointOptions IBalanceRestClient.GetBalancesOptions { get; } = new EndpointOptions("GetBalancesRequest", true); - async Task>> IBalanceRestClient.GetBalancesAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IBalanceRestClient.GetBalancesAsync(ApiType apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IBalanceRestClient)this).GetBalancesOptions.ValidateRequest(Exchange, exchangeParameters); + var validationError = ((IBalanceRestClient)this).GetBalancesOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index 723271ccc..3ee80fc6b 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -14,6 +14,7 @@ namespace Binance.Net.Clients.SpotApi internal partial class BinanceRestClientSpotApi : IBinanceRestClientSpotApiShared { public string Exchange => BinanceExchange.ExchangeName; + public ApiType[] SupportedApiTypes => new[] { ApiType.Spot }; #region Klines Client @@ -28,7 +29,7 @@ async Task>> IKlineRestClient.GetKlin if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -68,7 +69,7 @@ async Task>> IKlineRestClient.GetKlin async Task>> ISpotSymbolRestClient.GetSpotSymbolsAsync(ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ISpotSymbolRestClient)this).GetSpotSymbolsOptions.ValidateRequest(Exchange, exchangeParameters); + var validationError = ((ISpotSymbolRestClient)this).GetSpotSymbolsOptions.ValidateRequest(Exchange, exchangeParameters, ApiType.Spot, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -92,7 +93,7 @@ async Task>> ISpotSymbolRestClie EndpointOptions ISpotTickerRestClient.GetSpotTickerOptions { get; } = new EndpointOptions(false); async Task> ISpotTickerRestClient.GetSpotTickerAsync(GetTickerRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ISpotTickerRestClient)this).GetSpotTickerOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((ISpotTickerRestClient)this).GetSpotTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -106,7 +107,7 @@ async Task> ISpotTickerRestClient.GetSpotTic EndpointOptions ISpotTickerRestClient.GetSpotTickersOptions { get; } = new EndpointOptions("GetSpotTickersRequest", false); async Task>> ISpotTickerRestClient.GetSpotTickersAsync(ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ISpotTickerRestClient)this).GetSpotTickerOptions.ValidateRequest(Exchange, exchangeParameters); + var validationError = ((ISpotTickerRestClient)this).GetSpotTickersOptions.ValidateRequest(Exchange, exchangeParameters, ApiType.Spot, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -124,7 +125,7 @@ async Task>> ISpotTickerRestClie async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IRecentTradeRestClient)this).GetRecentTradesOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IRecentTradeRestClient)this).GetRecentTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -146,7 +147,7 @@ async Task>> IRecentTradeRestClient.G async Task>> ITradeHistoryRestClient.GetTradeHistoryAsync(GetTradeHistoryRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ITradeHistoryRestClient)this).GetTradeHistoryOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((ITradeHistoryRestClient)this).GetTradeHistoryOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -178,7 +179,7 @@ async Task>> ITradeHistoryRestClient. GetOrderBookOptions IOrderBookRestClient.GetOrderBookOptions { get; } = new GetOrderBookOptions(1, 5000, false); async Task> IOrderBookRestClient.GetOrderBookAsync(GetOrderBookRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -197,9 +198,9 @@ async Task> IOrderBookRestClient.GetOrderBook #region Balance Client EndpointOptions IBalanceRestClient.GetBalancesOptions { get; } = new EndpointOptions("GetBalancesRequest", true); - async Task>> IBalanceRestClient.GetBalancesAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IBalanceRestClient.GetBalancesAsync(ApiType apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IBalanceRestClient)this).GetBalancesOptions.ValidateRequest(Exchange, exchangeParameters); + var validationError = ((IBalanceRestClient)this).GetBalancesOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -235,7 +236,7 @@ async Task>> IBalanceRestClient.Get async Task> ISpotOrderRestClient.PlaceSpotOrderAsync(PlaceSpotOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).PlaceSpotOrderOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((ISpotOrderRestClient)this).PlaceSpotOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -257,7 +258,7 @@ async Task> ISpotOrderRestClient.PlaceSpotOrderAsync EndpointOptions ISpotOrderRestClient.GetSpotOrderOptions { get; } = new EndpointOptions(true); async Task> ISpotOrderRestClient.GetSpotOrderAsync(GetOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetSpotOrderOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((ISpotOrderRestClient)this).GetSpotOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -291,7 +292,7 @@ async Task> ISpotOrderRestClient.GetSpotOrder EndpointOptions ISpotOrderRestClient.GetOpenSpotOrdersOptions { get; } = new EndpointOptions(true); async Task>> ISpotOrderRestClient.GetOpenSpotOrdersAsync(GetOpenOrdersRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetOpenSpotOrdersOptions.ValidateRequest(Exchange, request,exchangeParameters); + var validationError = ((ISpotOrderRestClient)this).GetOpenSpotOrdersOptions.ValidateRequest(Exchange, request,exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -323,7 +324,7 @@ async Task>> ISpotOrderRestClient PaginatedEndpointOptions ISpotOrderRestClient.GetClosedSpotOrdersOptions { get; } = new PaginatedEndpointOptions(true, true); async Task>> ISpotOrderRestClient.GetClosedSpotOrdersAsync(GetClosedOrdersRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetClosedSpotOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((ISpotOrderRestClient)this).GetClosedSpotOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -368,7 +369,7 @@ async Task>> ISpotOrderRestClient EndpointOptions ISpotOrderRestClient.GetSpotOrderTradesOptions { get; } = new EndpointOptions(true); async Task>> ISpotOrderRestClient.GetSpotOrderTradesAsync(GetOrderTradesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetSpotOrderTradesOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((ISpotOrderRestClient)this).GetSpotOrderTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -398,7 +399,7 @@ async Task>> ISpotOrderRestClient PaginatedEndpointOptions ISpotOrderRestClient.GetSpotUserTradesOptions { get; } = new PaginatedEndpointOptions(true, true); async Task>> ISpotOrderRestClient.GetSpotUserTradesAsync(GetUserTradesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetSpotUserTradesOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((ISpotOrderRestClient)this).GetSpotUserTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -441,7 +442,7 @@ async Task>> ISpotOrderRestClient EndpointOptions ISpotOrderRestClient.CancelSpotOrderOptions { get; } = new EndpointOptions(true); async Task> ISpotOrderRestClient.CancelSpotOrderAsync(CancelOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).CancelSpotOrderOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((ISpotOrderRestClient)this).CancelSpotOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -488,7 +489,7 @@ private SharedOrderType ParseOrderType(SpotOrderType type) async Task>> IAssetsRestClient.GetAssetsAsync(ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IAssetsRestClient)this).GetAssetsOptions.ValidateRequest(Exchange, exchangeParameters); + var validationError = ((IAssetsRestClient)this).GetAssetsOptions.ValidateRequest(Exchange, exchangeParameters, ApiType.Spot, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -515,7 +516,7 @@ async Task>> IAssetsRestClient.GetAss EndpointOptions IAssetsRestClient.GetAssetOptions { get; } = new EndpointOptions(false); async Task> IAssetsRestClient.GetAssetAsync(GetAssetRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IAssetsRestClient)this).GetAssetOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IAssetsRestClient)this).GetAssetOptions.ValidateRequest(Exchange, request, exchangeParameters, ApiType.Spot, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -550,7 +551,7 @@ async Task> IAssetsRestClient.GetAssetAsync(GetAs EndpointOptions IDepositRestClient.GetDepositAddressesOptions { get; } = new EndpointOptions(true); async Task>> IDepositRestClient.GetDepositAddressesAsync(GetDepositAddressesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IDepositRestClient)this).GetDepositAddressesOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IDepositRestClient)this).GetDepositAddressesOptions.ValidateRequest(Exchange, request, exchangeParameters, ApiType.Spot, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -568,7 +569,7 @@ async Task>> IDepositRestCli GetDepositsOptions IDepositRestClient.GetDepositsOptions { get; } = new GetDepositsOptions(true, true); async Task>> IDepositRestClient.GetDepositsAsync(GetDepositsRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IDepositRestClient)this).GetDepositsOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IDepositRestClient)this).GetDepositsOptions.ValidateRequest(Exchange, request, exchangeParameters, ApiType.Spot, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -609,7 +610,7 @@ async Task>> IDepositRestClient.Get GetWithdrawalsOptions IWithdrawalRestClient.GetWithdrawalsOptions { get; } = new GetWithdrawalsOptions(true, true); async Task>> IWithdrawalRestClient.GetWithdrawalsAsync(GetWithdrawalsRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IWithdrawalRestClient)this).GetWithdrawalsOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IWithdrawalRestClient)this).GetWithdrawalsOptions.ValidateRequest(Exchange, request, exchangeParameters, ApiType.Spot, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -652,7 +653,7 @@ async Task>> IWithdrawalRestClie async Task > IWithdrawRestClient.WithdrawAsync(WithdrawRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IWithdrawRestClient)this).WithdrawOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IWithdrawRestClient)this).WithdrawOptions.ValidateRequest(Exchange, request, exchangeParameters, ApiType.Spot, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs index a176c2f32..d70758c26 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs @@ -16,6 +16,7 @@ namespace Binance.Net.Clients.SpotApi internal partial class BinanceSocketClientSpotApi : IBinanceSocketClientSpotApiShared { public string Exchange => BinanceExchange.ExchangeName; + public ApiType[] SupportedApiTypes => new[] { ApiType.DeliveryInverse, ApiType.Spot }; async Task> ITickersSocketClient.SubscribeToAllTickerUpdatesAsync(ApiType? apiType, Action>> handler, CancellationToken ct) { diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs index 0b5ecbb53..3520573e4 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -20,6 +20,8 @@ internal partial class BinanceRestClientUsdFuturesApi : IBinanceRestClientUsdFut { public string Exchange => BinanceExchange.ExchangeName; + public ApiType[] SupportedApiTypes => new[] { ApiType.DeliveryLinear, ApiType.PerpetualLinear }; + #region Klines client GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(true, false) @@ -33,7 +35,7 @@ async Task>> IKlineRestClient.GetKlin if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -80,7 +82,7 @@ async Task>> IMarkPriceKlineRestC if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IMarkPriceKlineRestClient)this).GetMarkPriceKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IMarkPriceKlineRestClient)this).GetMarkPriceKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -117,9 +119,9 @@ async Task>> IMarkPriceKlineRestC #region Futures Symbol client EndpointOptions IFuturesSymbolRestClient.GetFuturesSymbolsOptions { get; } = new EndpointOptions("GetFuturesSymbolsRequest", false); - async Task>> IFuturesSymbolRestClient.GetFuturesSymbolsAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IFuturesSymbolRestClient.GetFuturesSymbolsAsync(ApiType apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesSymbolRestClient)this).GetFuturesSymbolsOptions.ValidateRequest(Exchange, exchangeParameters); + var validationError = ((IFuturesSymbolRestClient)this).GetFuturesSymbolsOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -145,7 +147,7 @@ async Task>> IFuturesSymbolRe EndpointOptions IFuturesTickerRestClient.GetFuturesTickerOptions { get; } = new EndpointOptions(false); async Task> IFuturesTickerRestClient.GetFuturesTickerAsync(GetTickerRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickerOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -168,8 +170,12 @@ async Task> IFuturesTickerRestClient.GetF } EndpointOptions IFuturesTickerRestClient.GetFuturesTickersOptions { get; } = new EndpointOptions("GetTickersRequest", false); - async Task>> IFuturesTickerRestClient.GetFuturesTickersAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IFuturesTickerRestClient.GetFuturesTickersAsync(ApiType apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { + var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickerOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeWebResult>(Exchange, validationError); + var resultTickers = ExchangeData.GetTickersAsync(ct: ct); var resultMarkPrices = ExchangeData.GetMarkPricesAsync(ct: ct); await Task.WhenAll(resultTickers, resultMarkPrices).ConfigureAwait(false); @@ -198,7 +204,7 @@ async Task>> IFuturesTickerRe GetRecentTradesOptions IRecentTradeRestClient.GetRecentTradesOptions { get; } = new GetRecentTradesOptions(1000, false); async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IRecentTradeRestClient)this).GetRecentTradesOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IRecentTradeRestClient)this).GetRecentTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -236,7 +242,7 @@ async Task>> IRecentTradeRestClient.G async Task> IFuturesOrderRestClient.PlaceFuturesOrderAsync(PlaceFuturesOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).PlaceFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IFuturesOrderRestClient)this).PlaceFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -260,7 +266,7 @@ async Task> IFuturesOrderRestClient.PlaceFuturesOrde EndpointOptions IFuturesOrderRestClient.GetFuturesOrderOptions { get; } = new EndpointOptions(true); async Task> IFuturesOrderRestClient.GetFuturesOrderAsync(GetOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -295,7 +301,7 @@ async Task> IFuturesOrderRestClient.GetFut EndpointOptions IFuturesOrderRestClient.GetOpenFuturesOrdersOptions { get; } = new EndpointOptions(true); async Task>> IFuturesOrderRestClient.GetOpenFuturesOrdersAsync(GetOpenOrdersRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetOpenFuturesOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IFuturesOrderRestClient)this).GetOpenFuturesOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -328,7 +334,7 @@ async Task>> IFuturesOrderRest PaginatedEndpointOptions IFuturesOrderRestClient.GetClosedFuturesOrdersOptions { get; } = new PaginatedEndpointOptions(true, true); async Task>> IFuturesOrderRestClient.GetClosedFuturesOrdersAsync(GetClosedOrdersRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetClosedFuturesOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IFuturesOrderRestClient)this).GetClosedFuturesOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -374,7 +380,7 @@ async Task>> IFuturesOrderRest EndpointOptions IFuturesOrderRestClient.GetFuturesOrderTradesOptions { get; } = new EndpointOptions(true); async Task>> IFuturesOrderRestClient.GetFuturesOrderTradesAsync(GetOrderTradesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderTradesOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -404,7 +410,7 @@ async Task>> IFuturesOrderRestCli PaginatedEndpointOptions IFuturesOrderRestClient.GetFuturesUserTradesOptions { get; } = new PaginatedEndpointOptions(true, true); async Task>> IFuturesOrderRestClient.GetFuturesUserTradesAsync(GetUserTradesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetFuturesUserTradesOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IFuturesOrderRestClient)this).GetFuturesUserTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -447,7 +453,7 @@ async Task>> IFuturesOrderRestCli EndpointOptions IFuturesOrderRestClient.CancelFuturesOrderOptions { get; } = new EndpointOptions(true); async Task> IFuturesOrderRestClient.CancelFuturesOrderAsync(CancelOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).CancelFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IFuturesOrderRestClient)this).CancelFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -464,7 +470,7 @@ async Task> IFuturesOrderRestClient.CancelFuturesOrd EndpointOptions IFuturesOrderRestClient.GetPositionsOptions { get; } = new EndpointOptions(true); async Task>> IFuturesOrderRestClient.GetPositionsAsync(GetPositionsRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetPositionsOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IFuturesOrderRestClient)this).GetPositionsOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -485,7 +491,7 @@ async Task>> IFuturesOrderRestClie EndpointOptions IFuturesOrderRestClient.ClosePositionOptions { get; } = new EndpointOptions(true); async Task> IFuturesOrderRestClient.ClosePositionAsync(ClosePositionRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).ClosePositionOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IFuturesOrderRestClient)this).ClosePositionOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -547,7 +553,7 @@ private SharedOrderType ParseOrderType(FuturesOrderType type) EndpointOptions ILeverageRestClient.GetLeverageOptions { get; } = new EndpointOptions(true); async Task> ILeverageRestClient.GetLeverageAsync(GetLeverageRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ILeverageRestClient)this).GetLeverageOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((ILeverageRestClient)this).GetLeverageOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -572,7 +578,7 @@ async Task> ILeverageRestClient.GetLeverageAsy SetLeverageOptions ILeverageRestClient.SetLeverageOptions { get; } = new SetLeverageOptions(false); async Task> ILeverageRestClient.SetLeverageAsync(SetLeverageRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ILeverageRestClient)this).SetLeverageOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((ILeverageRestClient)this).SetLeverageOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -588,7 +594,7 @@ async Task> ILeverageRestClient.SetLeverageAsy GetOrderBookOptions IOrderBookRestClient.GetOrderBookOptions { get; } = new GetOrderBookOptions(new[] { 5, 10, 20, 50, 100, 500, 1000 }, false); async Task> IOrderBookRestClient.GetOrderBookAsync(GetOrderBookRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -609,7 +615,7 @@ async Task> IOrderBookRestClient.GetOrderBook async Task>> ITradeHistoryRestClient.GetTradeHistoryAsync(GetTradeHistoryRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ITradeHistoryRestClient)this).GetTradeHistoryOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((ITradeHistoryRestClient)this).GetTradeHistoryOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -650,7 +656,7 @@ async Task>> IIndexPriceKlineRest if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IIndexPriceKlineRestClient)this).GetIndexPriceKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IIndexPriceKlineRestClient)this).GetIndexPriceKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -689,7 +695,7 @@ async Task>> IIndexPriceKlineRest EndpointOptions IOpenInterestRestClient.GetOpenInterestOptions { get; } = new EndpointOptions(true); async Task> IOpenInterestRestClient.GetOpenInterestAsync(GetOpenInterestRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IOpenInterestRestClient)this).GetOpenInterestOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IOpenInterestRestClient)this).GetOpenInterestOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -707,7 +713,7 @@ async Task> IOpenInterestRestClient.GetOpe async Task>> IFundingRateRestClient.GetFundingRateHistoryAsync(GetFundingRateHistoryRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFundingRateRestClient)this).GetFundingRateHistoryOptions.ValidateRequest(Exchange, request, exchangeParameters); + var validationError = ((IFundingRateRestClient)this).GetFundingRateHistoryOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -737,9 +743,9 @@ async Task>> IFundingRateRestCl #region Balance Client EndpointOptions IBalanceRestClient.GetBalancesOptions { get; } = new EndpointOptions("GetBalancesRequest", true); - async Task>> IBalanceRestClient.GetBalancesAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IBalanceRestClient.GetBalancesAsync(ApiType apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IBalanceRestClient)this).GetBalancesOptions.ValidateRequest(Exchange, exchangeParameters); + var validationError = ((IBalanceRestClient)this).GetBalancesOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); From 7bc39882da5a60db8bb9fa6a12505b260af793f4 Mon Sep 17 00:00:00 2001 From: Jkorf Date: Thu, 5 Sep 2024 11:13:30 +0200 Subject: [PATCH 24/54] wip --- .../CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs | 3 ++- Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs | 2 +- .../UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs index 3ae82347f..f6b07700c 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -79,7 +79,8 @@ async Task>> IFuturesSymbolRe if (!result) return result.AsExchangeResult>(Exchange, default); - return result.AsExchangeResult(Exchange, result.Data.Symbols.Select(s => new SharedFuturesSymbol(s.ContractType == ContractType.Perpetual ? SharedSymbolType.PerpetualInverse : SharedSymbolType.DeliveryInverse, s.BaseAsset, s.QuoteAsset, s.Name) + var data = result.Data.Symbols.Where(x => apiType == ApiType.PerpetualInverse ? x.ContractType == ContractType.Perpetual : x.ContractType != ContractType.Perpetual); + return result.AsExchangeResult(Exchange, data.Select(s => new SharedFuturesSymbol(s.ContractType == ContractType.Perpetual ? SharedSymbolType.PerpetualInverse : SharedSymbolType.DeliveryInverse, s.BaseAsset, s.QuoteAsset, s.Name, s.Status == SymbolStatus.Trading) { MinTradeQuantity = s.LotSizeFilter?.MinQuantity, MaxTradeQuantity = s.LotSizeFilter?.MaxQuantity, diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index 3ee80fc6b..95ff9e183 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -77,7 +77,7 @@ async Task>> ISpotSymbolRestClie if (!result) return result.AsExchangeResult>(Exchange, default); - return result.AsExchangeResult(Exchange, result.Data.Symbols.Select(s => new SharedSpotSymbol(s.BaseAsset, s.QuoteAsset, s.Name) + return result.AsExchangeResult(Exchange, result.Data.Symbols.Select(s => new SharedSpotSymbol(s.BaseAsset, s.QuoteAsset, s.Name, s.Status == SymbolStatus.Trading) { MinTradeQuantity = s.LotSizeFilter?.MinQuantity, MaxTradeQuantity = s.LotSizeFilter?.MaxQuantity, diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs index 3520573e4..871217efe 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -129,7 +129,8 @@ async Task>> IFuturesSymbolRe if (!result) return result.AsExchangeResult< IEnumerable>(Exchange, default); - return result.AsExchangeResult(Exchange, result.Data.Symbols.Select(s => new SharedFuturesSymbol(s.ContractType == ContractType.Perpetual ? SharedSymbolType.PerpetualLinear : SharedSymbolType.DeliveryLinear, s.BaseAsset, s.QuoteAsset, s.Name) + var data = result.Data.Symbols.Where(x => apiType == ApiType.PerpetualLinear ? x.ContractType == ContractType.Perpetual : x.ContractType != ContractType.Perpetual); + return result.AsExchangeResult(Exchange, data.Select(s => new SharedFuturesSymbol(s.ContractType == ContractType.Perpetual ? SharedSymbolType.PerpetualLinear : SharedSymbolType.DeliveryLinear, s.BaseAsset, s.QuoteAsset, s.Name, s.Status == SymbolStatus.Trading) { MinTradeQuantity = s.LotSizeFilter?.MinQuantity, MaxTradeQuantity = s.LotSizeFilter?.MaxQuantity, From e118bcf81f93d36422ba72cc9e5fac4086438b54 Mon Sep 17 00:00:00 2001 From: Jkorf Date: Thu, 5 Sep 2024 16:30:05 +0200 Subject: [PATCH 25/54] wip --- .../BinanceRestClientCoinFuturesApiShared.cs | 96 ++++++++++++------- .../SpotApi/BinanceRestClientSpotApiShared.cs | 42 ++++---- .../BinanceRestClientUsdFuturesApiShared.cs | 95 +++++++++++------- .../IBinanceRestClientCoinFuturesApiShared.cs | 3 +- .../IBinanceRestClientUsdFuturesApiShared.cs | 3 +- 5 files changed, 152 insertions(+), 87 deletions(-) diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs index f6b07700c..2c4705447 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -44,9 +44,9 @@ async Task>> IKlineRestClient.GetKlin var result = await ExchangeData.GetKlinesAsync( request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), interval, - fromTimestamp ?? request.Filter?.StartTime, - request.Filter?.EndTime, - request.Filter?.Limit ?? 1000, + fromTimestamp ?? request.StartTime, + request.EndTime, + request.Limit ?? 1000, ct: ct ).ConfigureAwait(false); if (!result) @@ -54,10 +54,10 @@ async Task>> IKlineRestClient.GetKlin // Get next token DateTimeToken? nextToken = null; - if (request.Filter?.StartTime != null && result.Data.Any()) + if (request.StartTime != null && result.Data.Any()) { var maxOpenTime = result.Data.Max(x => x.OpenTime); - if (maxOpenTime < request.Filter.EndTime!.Value.AddSeconds(-(int)request.Interval)) + if (maxOpenTime < request.EndTime!.Value.AddSeconds(-(int)request.Interval)) nextToken = new DateTimeToken(maxOpenTime.AddSeconds((int)interval)); } @@ -208,7 +208,7 @@ async Task> IFuturesOrderRestClient.PlaceFuturesOrde request.OrderType == SharedOrderType.Limit ? Enums.FuturesOrderType.Limit : Enums.FuturesOrderType.Market, quantity: request.Quantity, price: request.Price, - positionSide: request.PositionSide == SharedPositionSide.Both ? PositionSide.Both : request.PositionSide == SharedPositionSide.Long ? PositionSide.Long: PositionSide.Short, + positionSide: request.PositionSide == null ? null : request.PositionSide == SharedPositionSide.Long ? PositionSide.Long: PositionSide.Short, reduceOnly: request.ReduceOnly, newClientOrderId: request.ClientOrderId).ConfigureAwait(false); @@ -248,7 +248,7 @@ async Task> IFuturesOrderRestClient.GetFut QuoteQuantityFilled = order.Data.QuoteQuantityFilled, TimeInForce = ParseTimeInForce(order.Data.TimeInForce), UpdateTime = order.Data.UpdateTime, - PositionSide = order.Data.PositionSide == PositionSide.Both ? SharedPositionSide.Both : order.Data.PositionSide == PositionSide.Long ? SharedPositionSide.Long : SharedPositionSide.Short, + PositionSide = order.Data.PositionSide == PositionSide.Both ? null : order.Data.PositionSide == PositionSide.Long ? SharedPositionSide.Long : SharedPositionSide.Short, ReduceOnly = order.Data.ReduceOnly }); } @@ -281,7 +281,7 @@ async Task>> IFuturesOrderRest QuoteQuantityFilled = x.QuoteQuantityFilled, TimeInForce = ParseTimeInForce(x.TimeInForce), UpdateTime = x.UpdateTime, - PositionSide = x.PositionSide == PositionSide.Both ? SharedPositionSide.Both : x.PositionSide == PositionSide.Long ? SharedPositionSide.Long : SharedPositionSide.Short, + PositionSide = x.PositionSide == PositionSide.Both ? null : x.PositionSide == PositionSide.Long ? SharedPositionSide.Long : SharedPositionSide.Short, ReduceOnly = x.ReduceOnly })); } @@ -300,15 +300,15 @@ async Task>> IFuturesOrderRest // Get data var orders = await Trading.GetOrdersAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), - startTime: fromTimestamp ?? request.Filter?.StartTime, - endTime: request.Filter?.EndTime, - limit: request.Filter?.Limit ?? 1000).ConfigureAwait(false); + startTime: fromTimestamp ?? request.StartTime, + endTime: request.EndTime, + limit: request.Limit ?? 1000).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); // Get next token DateTimeToken? nextToken = null; - if (orders.Data.Count() == (request.Filter?.Limit ?? 1000)) + if (orders.Data.Count() == (request.Limit ?? 1000)) nextToken = new DateTimeToken(orders.Data.Max(o => o.CreateTime)); return orders.AsExchangeResult(Exchange, orders.Data.Where(x => x.Status == OrderStatus.Filled || x.Status == OrderStatus.Canceled || x.Status == OrderStatus.Expired).Select(x => new SharedFuturesOrder( @@ -327,7 +327,7 @@ async Task>> IFuturesOrderRest QuoteQuantityFilled = x.QuoteQuantityFilled, TimeInForce = ParseTimeInForce(x.TimeInForce), UpdateTime = x.UpdateTime, - PositionSide = x.PositionSide == PositionSide.Both ? SharedPositionSide.Both : x.PositionSide == PositionSide.Long ? SharedPositionSide.Long : SharedPositionSide.Short, + PositionSide = x.PositionSide == PositionSide.Both ? null : x.PositionSide == PositionSide.Long ? SharedPositionSide.Long : SharedPositionSide.Short, ReduceOnly = x.ReduceOnly })); } @@ -376,9 +376,9 @@ async Task>> IFuturesOrderRestCli // Get data var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), - startTime: request.Filter?.StartTime, - endTime: request.Filter?.EndTime, - limit: request.Filter?.Limit ?? 500, + startTime: request.StartTime, + endTime: request.EndTime, + limit: request.Limit ?? 500, fromId: fromId ).ConfigureAwait(false); if (!orders) @@ -386,7 +386,7 @@ async Task>> IFuturesOrderRestCli // Get next token FromIdToken? nextToken = null; - if (orders.Data.Count() == (request.Filter?.Limit ?? 500)) + if (orders.Data.Count() == (request.Limit ?? 500)) nextToken = new FromIdToken(orders.Data.Max(o => o.Id).ToString()); return orders.AsExchangeResult(Exchange, orders.Data.Select(x => new SharedUserTrade( @@ -433,13 +433,13 @@ async Task>> IFuturesOrderRestClie if (!result) return result.AsExchangeResult>(Exchange, default); - return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedPosition(x.Symbol, x.Quantity, x.UpdateTime) + return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedPosition(x.Symbol, Math.Abs(x.Quantity), x.UpdateTime) { UnrealizedPnl = x.UnrealizedPnl, LiquidationPrice = x.LiquidationPrice, Leverage = x.Leverage, AverageEntryPrice = x.EntryPrice, - PositionSide = x.PositionSide == PositionSide.Both ? SharedPositionSide.Both : x.PositionSide == PositionSide.Short ? SharedPositionSide.Short : SharedPositionSide.Long + PositionSide = x.PositionSide == PositionSide.Both ? (x.Quantity > 0 ? SharedPositionSide.Long : SharedPositionSide.Short) : x.PositionSide == PositionSide.Short ? SharedPositionSide.Short : SharedPositionSide.Long }).ToList()); } @@ -453,10 +453,10 @@ async Task> IFuturesOrderRestClient.ClosePositionAsy var result = await Trading.PlaceOrderAsync( request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), request.PositionSide == SharedPositionSide.Long ? OrderSide.Sell : OrderSide.Buy, -#warning check if works correctly. If side is both, what to do..? FuturesOrderType.Market, - null, - closePosition: true, + request.Quantity, + positionSide: request.PositionSide == null ? null : request.PositionSide == SharedPositionSide.Short ? PositionSide.Short : PositionSide.Long, + reduceOnly: true, ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -558,9 +558,9 @@ async Task>> IMarkPriceKlineRestC var result = await ExchangeData.GetMarkPriceKlinesAsync( request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), interval, - request.Filter?.Limit ?? 1000, - fromTimestamp ?? request.Filter?.StartTime, - request.Filter?.EndTime, + request.Limit ?? 1000, + fromTimestamp ?? request.StartTime, + request.EndTime, ct: ct ).ConfigureAwait(false); if (!result) @@ -568,10 +568,10 @@ async Task>> IMarkPriceKlineRestC // Get next token DateTimeToken? nextToken = null; - if (request.Filter?.StartTime != null && result.Data.Any()) + if (request.StartTime != null && result.Data.Any()) { var maxOpenTime = result.Data.Max(x => x.OpenTime); - if (maxOpenTime < request.Filter.EndTime!.Value.AddSeconds(-(int)request.Interval)) + if (maxOpenTime < request.EndTime!.Value.AddSeconds(-(int)request.Interval)) nextToken = new DateTimeToken(maxOpenTime.AddSeconds((int)interval)); } @@ -658,9 +658,9 @@ async Task>> IIndexPriceKlineRest var result = await ExchangeData.GetMarkPriceKlinesAsync( request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), interval, - request.Filter?.Limit ?? 1000, - fromTimestamp ?? request.Filter?.StartTime, - request.Filter?.EndTime, + request.Limit ?? 1000, + fromTimestamp ?? request.StartTime, + request.EndTime, ct: ct ).ConfigureAwait(false); if (!result) @@ -668,10 +668,10 @@ async Task>> IIndexPriceKlineRest // Get next token DateTimeToken? nextToken = null; - if (request.Filter?.StartTime != null && result.Data.Any()) + if (request.StartTime != null && result.Data.Any()) { var maxOpenTime = result.Data.Max(x => x.OpenTime); - if (maxOpenTime < request.Filter.EndTime!.Value.AddSeconds(-(int)request.Interval)) + if (maxOpenTime < request.EndTime!.Value.AddSeconds(-(int)request.Interval)) nextToken = new DateTimeToken(maxOpenTime.AddSeconds((int)interval)); } @@ -747,5 +747,37 @@ async Task>> IBalanceRestClient.Get } #endregion + + #region Position Mode client + + GetPositionModeOptions IPositionModeRestClient.GetPositionModeOptions { get; } = new GetPositionModeOptions(false); + async Task> IPositionModeRestClient.GetPositionModeAsync(GetPositionModeRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IPositionModeRestClient)this).GetPositionModeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + + var result = await Account.GetPositionModeAsync(ct: ct).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult(Exchange, default); + + return result.AsExchangeResult(Exchange, new SharedPositionModeResult(result.Data.IsHedgeMode ? SharedPositionMode.LongShort : SharedPositionMode.OneWay)); + } + + SetPositionModeOptions IPositionModeRestClient.SetPositionModeOptions { get; } = new SetPositionModeOptions(true, true, false); + async Task> IPositionModeRestClient.SetPositionModeAsync(SetPositionModeRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IPositionModeRestClient)this).SetPositionModeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + + var result = await Account.ModifyPositionModeAsync(request.Mode == SharedPositionMode.LongShort, ct: ct).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult(Exchange, default); + + return result.AsExchangeResult(Exchange, new SharedPositionModeResult(request.Mode)); + } + #endregion + } } diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index 95ff9e183..ca7e98c16 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -42,9 +42,9 @@ async Task>> IKlineRestClient.GetKlin var result = await ExchangeData.GetKlinesAsync( request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), interval, - fromTimestamp ?? request.Filter?.StartTime, - request.Filter?.EndTime?.AddSeconds(-1), - request.Filter?.Limit ?? 1000, + fromTimestamp ?? request.StartTime, + request.EndTime?.AddSeconds(-1), + request.Limit ?? 1000, ct: ct ).ConfigureAwait(false); if (!result) @@ -52,10 +52,10 @@ async Task>> IKlineRestClient.GetKlin // Get next token DateTimeToken? nextToken = null; - if (request.Filter?.StartTime != null && result.Data.Any()) + if (request.StartTime != null && result.Data.Any()) { var maxOpenTime = result.Data.Max(x => x.OpenTime); - if (maxOpenTime < request.Filter.EndTime!.Value.AddSeconds(-(int)request.Interval)) + if (maxOpenTime < request.EndTime!.Value.AddSeconds(-(int)request.Interval)) nextToken = new DateTimeToken(maxOpenTime.AddSeconds((int)interval)); } @@ -335,15 +335,15 @@ async Task>> ISpotOrderRestClient // Get data var orders = await Trading.GetOrdersAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), - startTime: fromTimestamp ?? request.Filter?.StartTime, - endTime: request.Filter?.EndTime, - limit: request.Filter?.Limit ?? 1000).ConfigureAwait(false); + startTime: fromTimestamp ?? request.StartTime, + endTime: request.EndTime, + limit: request.Limit ?? 1000).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); // Get next token DateTimeToken? nextToken = null; - if (orders.Data.Count() == (request.Filter?.Limit ?? 1000)) + if (orders.Data.Count() == (request.Limit ?? 1000)) nextToken = new DateTimeToken(orders.Data.Max(o => o.CreateTime)); return orders.AsExchangeResult(Exchange, orders.Data.Where(x => x.Status == OrderStatus.Filled || x.Status == OrderStatus.Canceled || x.Status == OrderStatus.Expired).Select(x => new SharedSpotOrder( @@ -410,9 +410,9 @@ async Task>> ISpotOrderRestClient // Get data var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), - startTime: request.Filter?.StartTime, - endTime: request.Filter?.EndTime, - limit: request.Filter?.Limit ?? 500, + startTime: request.StartTime, + endTime: request.EndTime, + limit: request.Limit ?? 500, fromId: fromId ).ConfigureAwait(false); if (!orders) @@ -420,7 +420,7 @@ async Task>> ISpotOrderRestClient // Get next token FromIdToken? nextToken = null; - if (orders.Data.Count() == (request.Filter?.Limit ?? 500)) + if (orders.Data.Count() == (request.Limit ?? 500)) nextToken = new FromIdToken(orders.Data.Max(o => o.Id).ToString()); return orders.AsExchangeResult(Exchange, orders.Data.Select(x => new SharedUserTrade( @@ -581,9 +581,9 @@ async Task>> IDepositRestClient.Get // Get data var deposits = await Account.GetDepositHistoryAsync( request.Asset, - startTime: request.Filter?.StartTime, - endTime: request.Filter?.EndTime, - limit: request.Filter?.Limit ?? 100, + startTime: request.StartTime, + endTime: request.EndTime, + limit: request.Limit ?? 100, offset: offset, ct: ct).ConfigureAwait(false); if (!deposits) @@ -591,7 +591,7 @@ async Task>> IDepositRestClient.Get // Determine next token OffsetToken? nextToken = null; - if (deposits.Data.Count() == (request.Filter?.Limit ?? 100)) + if (deposits.Data.Count() == (request.Limit ?? 100)) nextToken = new OffsetToken((offset ?? 0) + deposits.Data.Count()); return deposits.AsExchangeResult(Exchange, deposits.Data.Select(x => new SharedDeposit(x.Asset, x.Quantity, x.Status == DepositStatus.Success, x.InsertTime) @@ -622,9 +622,9 @@ async Task>> IWithdrawalRestClie // Get data var withdrawals = await Account.GetWithdrawalHistoryAsync( request.Asset, - startTime: request.Filter?.StartTime, - endTime: request.Filter?.EndTime, - limit: request.Filter?.Limit ?? 100, + startTime: request.StartTime, + endTime: request.EndTime, + limit: request.Limit ?? 100, offset: offset, ct: ct).ConfigureAwait(false); if (!withdrawals) @@ -632,7 +632,7 @@ async Task>> IWithdrawalRestClie // Determine next token OffsetToken nextToken; - if (withdrawals.Data.Count() == (request.Filter?.Limit ?? 100)) + if (withdrawals.Data.Count() == (request.Limit ?? 100)) nextToken = new OffsetToken((offset ?? 0) + withdrawals.Data.Count()); return withdrawals.AsExchangeResult(Exchange, withdrawals.Data.Select(x => new SharedWithdrawal(x.Asset, x.Address, x.Quantity, x.Status == WithdrawalStatus.Completed, x.ApplyTime) diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs index 871217efe..f1e59232a 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -47,9 +47,9 @@ async Task>> IKlineRestClient.GetKlin var result = await ExchangeData.GetKlinesAsync( request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), interval, - fromTimestamp ?? request.Filter?.StartTime, - request.Filter?.EndTime, - request.Filter?.Limit ?? 1000, + fromTimestamp ?? request.StartTime, + request.EndTime, + request.Limit ?? 1000, ct: ct ).ConfigureAwait(false); if (!result) @@ -57,10 +57,10 @@ async Task>> IKlineRestClient.GetKlin // Get next token DateTimeToken? nextToken = null; - if (request.Filter?.StartTime != null && result.Data.Any()) + if (request.StartTime != null && result.Data.Any()) { var maxOpenTime = result.Data.Max(x => x.OpenTime); - if (maxOpenTime < request.Filter.EndTime!.Value.AddSeconds(-(int)request.Interval)) + if (maxOpenTime < request.EndTime!.Value.AddSeconds(-(int)request.Interval)) nextToken = new DateTimeToken(maxOpenTime.AddSeconds((int)interval)); } @@ -94,9 +94,9 @@ async Task>> IMarkPriceKlineRestC var result = await ExchangeData.GetMarkPriceKlinesAsync( request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), interval, - request.Filter?.Limit ?? 1000, - fromTimestamp ?? request.Filter?.StartTime, - request.Filter?.EndTime, + request.Limit ?? 1000, + fromTimestamp ?? request.StartTime, + request.EndTime, ct: ct ).ConfigureAwait(false); if (!result) @@ -104,10 +104,10 @@ async Task>> IMarkPriceKlineRestC // Get next token DateTimeToken? nextToken = null; - if (request.Filter?.StartTime != null && result.Data.Any()) + if (request.StartTime != null && result.Data.Any()) { var maxOpenTime = result.Data.Max(x => x.OpenTime); - if (maxOpenTime < request.Filter.EndTime!.Value.AddSeconds(-(int)request.Interval)) + if (maxOpenTime < request.EndTime!.Value.AddSeconds(-(int)request.Interval)) nextToken = new DateTimeToken(maxOpenTime.AddSeconds((int)interval)); } @@ -253,7 +253,7 @@ async Task> IFuturesOrderRestClient.PlaceFuturesOrde request.OrderType == SharedOrderType.Limit ? Enums.FuturesOrderType.Limit : Enums.FuturesOrderType.Market, quantity: request.Quantity, price: request.Price, - positionSide: request.PositionSide == SharedPositionSide.Both ? PositionSide.Both : request.PositionSide == SharedPositionSide.Long ? PositionSide.Long : PositionSide.Short, + positionSide: request.PositionSide == null ? null : request.PositionSide == SharedPositionSide.Long ? PositionSide.Long : PositionSide.Short, reduceOnly: request.ReduceOnly, timeInForce: GetTimeInForce(request.TimeInForce), newClientOrderId: request.ClientOrderId).ConfigureAwait(false); @@ -294,7 +294,7 @@ async Task> IFuturesOrderRestClient.GetFut QuoteQuantityFilled = order.Data.QuoteQuantityFilled, TimeInForce = ParseTimeInForce(order.Data.TimeInForce), UpdateTime = order.Data.UpdateTime, - PositionSide = order.Data.PositionSide == PositionSide.Both ? SharedPositionSide.Both : order.Data.PositionSide == PositionSide.Long ? SharedPositionSide.Long : SharedPositionSide.Short, + PositionSide = order.Data.PositionSide == PositionSide.Both ? null : order.Data.PositionSide == PositionSide.Long ? SharedPositionSide.Long : SharedPositionSide.Short, ReduceOnly = order.Data.ReduceOnly }); } @@ -327,7 +327,7 @@ async Task>> IFuturesOrderRest QuoteQuantityFilled = x.QuoteQuantityFilled, TimeInForce = ParseTimeInForce(x.TimeInForce), UpdateTime = x.UpdateTime, - PositionSide = x.PositionSide == PositionSide.Both ? SharedPositionSide.Both : x.PositionSide == PositionSide.Long ? SharedPositionSide.Long : SharedPositionSide.Short, + PositionSide = x.PositionSide == PositionSide.Both ? null : x.PositionSide == PositionSide.Long ? SharedPositionSide.Long : SharedPositionSide.Short, ReduceOnly = x.ReduceOnly })); } @@ -346,15 +346,15 @@ async Task>> IFuturesOrderRest // Get data var orders = await Trading.GetOrdersAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), - startTime: fromTimestamp ?? request.Filter?.StartTime, - endTime: request.Filter?.EndTime, - limit: request.Filter?.Limit ?? 1000).ConfigureAwait(false); + startTime: fromTimestamp ?? request.StartTime, + endTime: request.EndTime, + limit: request.Limit ?? 1000).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); // Get next token DateTimeToken? nextToken = null; - if (orders.Data.Count() == (request.Filter?.Limit ?? 1000)) + if (orders.Data.Count() == (request.Limit ?? 1000)) nextToken = new DateTimeToken(orders.Data.Max(o => o.CreateTime)); return orders.AsExchangeResult(Exchange, orders.Data.Where(x => x.Status == OrderStatus.Filled || x.Status == OrderStatus.Canceled || x.Status == OrderStatus.Expired).Select(x => new SharedFuturesOrder( @@ -373,7 +373,7 @@ async Task>> IFuturesOrderRest QuoteQuantityFilled = x.QuoteQuantityFilled, TimeInForce = ParseTimeInForce(x.TimeInForce), UpdateTime = x.UpdateTime, - PositionSide = x.PositionSide == PositionSide.Both ? SharedPositionSide.Both : x.PositionSide == PositionSide.Long ? SharedPositionSide.Long : SharedPositionSide.Short, + PositionSide = x.PositionSide == PositionSide.Both ? null : x.PositionSide == PositionSide.Long ? SharedPositionSide.Long : SharedPositionSide.Short, ReduceOnly = x.ReduceOnly })); } @@ -422,9 +422,9 @@ async Task>> IFuturesOrderRestCli // Get data var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), - startTime: request.Filter?.StartTime, - endTime: request.Filter?.EndTime, - limit: request.Filter?.Limit ?? 500, + startTime: request.StartTime, + endTime: request.EndTime, + limit: request.Limit ?? 500, fromId: fromId ).ConfigureAwait(false); if (!orders) @@ -432,7 +432,7 @@ async Task>> IFuturesOrderRestCli // Get next token FromIdToken? nextToken = null; - if (orders.Data.Count() == (request.Filter?.Limit ?? 500)) + if (orders.Data.Count() == (request.Limit ?? 500)) nextToken = new FromIdToken(orders.Data.Max(o => o.Id).ToString()); return orders.AsExchangeResult(Exchange, orders.Data.Select(x => new SharedUserTrade( @@ -479,13 +479,13 @@ async Task>> IFuturesOrderRestClie if (!result) return result.AsExchangeResult>(Exchange, default); - return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedPosition(x.Symbol, x.Quantity, x.UpdateTime) + return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedPosition(x.Symbol, Math.Abs(x.Quantity), x.UpdateTime) { UnrealizedPnl = x.UnrealizedPnl, LiquidationPrice = x.LiquidationPrice, Leverage = x.Leverage, AverageEntryPrice = x.EntryPrice, - PositionSide = x.PositionSide == PositionSide.Both ? SharedPositionSide.Both : x.PositionSide == PositionSide.Short ? SharedPositionSide.Short : SharedPositionSide.Long + PositionSide = x.PositionSide == PositionSide.Both ? (x.Quantity > 0 ? SharedPositionSide.Long : SharedPositionSide.Short) : x.PositionSide == PositionSide.Short ? SharedPositionSide.Short : SharedPositionSide.Long }).ToList()); } @@ -499,10 +499,10 @@ async Task> IFuturesOrderRestClient.ClosePositionAsy var result = await Trading.PlaceOrderAsync( request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), request.PositionSide == SharedPositionSide.Long ? OrderSide.Sell : OrderSide.Buy, -#warning check if works correctly. If side is both, what to do..? FuturesOrderType.Market, - null, - closePosition: true, + request.Quantity, + positionSide: request.PositionSide == null ? null : request.PositionSide == SharedPositionSide.Short ? PositionSide.Short : PositionSide.Long, + reduceOnly: true, ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -669,9 +669,9 @@ async Task>> IIndexPriceKlineRest var result = await ExchangeData.GetMarkPriceKlinesAsync( request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), interval, - request.Filter?.Limit ?? 1000, - fromTimestamp ?? request.Filter?.StartTime, - request.Filter?.EndTime, + request.Limit ?? 1000, + fromTimestamp ?? request.StartTime, + request.EndTime, ct: ct ).ConfigureAwait(false); if (!result) @@ -679,10 +679,10 @@ async Task>> IIndexPriceKlineRest // Get next token DateTimeToken? nextToken = null; - if (request.Filter?.StartTime != null && result.Data.Any()) + if (request.StartTime != null && result.Data.Any()) { var maxOpenTime = result.Data.Max(x => x.OpenTime); - if (maxOpenTime < request.Filter.EndTime!.Value.AddSeconds(-(int)request.Interval)) + if (maxOpenTime < request.EndTime!.Value.AddSeconds(-(int)request.Interval)) nextToken = new DateTimeToken(maxOpenTime.AddSeconds((int)interval)); } @@ -758,5 +758,36 @@ async Task>> IBalanceRestClient.Get } #endregion + + #region Position Mode client + + GetPositionModeOptions IPositionModeRestClient.GetPositionModeOptions { get; } = new GetPositionModeOptions(false); + async Task> IPositionModeRestClient.GetPositionModeAsync(GetPositionModeRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IPositionModeRestClient)this).GetPositionModeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + + var result = await Account.GetPositionModeAsync(ct: ct).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult(Exchange, default); + + return result.AsExchangeResult(Exchange, new SharedPositionModeResult(result.Data.IsHedgeMode ? SharedPositionMode.LongShort : SharedPositionMode.OneWay)); + } + + SetPositionModeOptions IPositionModeRestClient.SetPositionModeOptions { get; } = new SetPositionModeOptions(true, true, false); + async Task> IPositionModeRestClient.SetPositionModeAsync(SetPositionModeRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IPositionModeRestClient)this).SetPositionModeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + + var result = await Account.ModifyPositionModeAsync(request.Mode == SharedPositionMode.LongShort, ct: ct).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult(Exchange, default); + + return result.AsExchangeResult(Exchange, new SharedPositionModeResult(request.Mode)); + } + #endregion } } diff --git a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs index 116a5acc6..ae3a6ef11 100644 --- a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs @@ -20,7 +20,8 @@ public interface IBinanceRestClientCoinFuturesApiShared : IOrderBookRestClient, IOpenInterestRestClient, IFundingRateRestClient, - IBalanceRestClient + IBalanceRestClient, + IPositionModeRestClient { } } diff --git a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs index 1aa699ac2..fbe3d9502 100644 --- a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs @@ -20,7 +20,8 @@ public interface IBinanceRestClientUsdFuturesApiShared : IIndexPriceKlineRestClient, IOrderBookRestClient, IOpenInterestRestClient, - IFundingRateRestClient + IFundingRateRestClient, + IPositionModeRestClient { } } From 3d29b0a7f76290187a42e34c5358e81810f96132 Mon Sep 17 00:00:00 2001 From: Jkorf Date: Fri, 6 Sep 2024 15:17:57 +0200 Subject: [PATCH 26/54] wip --- .../BinanceSocketClientCoinFuturesApi.cs | 3 +- ...BinanceSocketClientCoinFuturesApiShared.cs | 152 ++++++++++++++ .../BinanceSocketClientSpotApiShared.cs | 111 +++++++++-- .../BinanceSocketClientUsdFuturesApi.cs | 6 +- .../BinanceSocketClientUsdFuturesApiShared.cs | 185 ++++++++++++++++++ .../IBinanceSocketClientCoinFuturesApi.cs | 2 + ...BinanceSocketClientCoinFuturesApiShared.cs | 15 ++ .../IBinanceSocketClientSpotApiShared.cs | 4 +- .../IBinanceSocketClientUsdFuturesApi.cs | 2 + ...IBinanceSocketClientUsdFuturesApiShared.cs | 17 ++ 10 files changed, 476 insertions(+), 21 deletions(-) create mode 100644 Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs create mode 100644 Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs create mode 100644 Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceSocketClientCoinFuturesApiShared.cs create mode 100644 Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceSocketClientUsdFuturesApiShared.cs diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs index aeb81f51a..9e01d2122 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs @@ -17,7 +17,7 @@ namespace Binance.Net.Clients.CoinFuturesApi { /// - internal class BinanceSocketClientCoinFuturesApi : SocketApiClient, IBinanceSocketClientCoinFuturesApi + internal partial class BinanceSocketClientCoinFuturesApi : SocketApiClient, IBinanceSocketClientCoinFuturesApi { #region fields private const string _klineStreamEndpoint = "@kline"; @@ -66,6 +66,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(); protected override IByteMessageAccessor CreateAccessor() => new SystemTextJsonByteMessageAccessor(); + public IBinanceSocketClientCoinFuturesApiShared SharedClient => this; /// public override string FormatSymbol(string baseAsset, string quoteAsset, ApiType? futuresType = null) diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs new file mode 100644 index 000000000..300396dae --- /dev/null +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs @@ -0,0 +1,152 @@ +using Binance.Net.Interfaces.Clients.CoinFuturesApi; +using Binance.Net.Interfaces.Clients.SpotApi; +using CryptoExchange.Net.Objects.Sockets; +using CryptoExchange.Net.SharedApis.Enums; +using CryptoExchange.Net.SharedApis.Interfaces.Socket; +using CryptoExchange.Net.SharedApis.Models; +using CryptoExchange.Net.SharedApis.Models.FilterOptions; +using CryptoExchange.Net.SharedApis.Models.Socket; +using CryptoExchange.Net.SharedApis.RequestModels; +using CryptoExchange.Net.SharedApis.ResponseModels; +using CryptoExchange.Net.SharedApis.SubscribeModels; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Binance.Net.Clients.CoinFuturesApi +{ + internal partial class BinanceSocketClientCoinFuturesApi : IBinanceSocketClientCoinFuturesApiShared + { + public string Exchange => BinanceExchange.ExchangeName; + public ApiType[] SupportedApiTypes => new[] { ApiType.DeliveryInverse, ApiType.PerpetualInverse }; + + #region Trade client + + SubscriptionOptions ITradeSocketClient.SubscribeTradeOptions { get; } = new SubscriptionOptions(false); + async Task> ITradeSocketClient.SubscribeToTradeUpdatesAsync(SubscribeTradeRequest request, Action>> handler, CancellationToken ct) + { + var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeResult(Exchange, validationError); + + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)); + var result = await SubscribeToAggregatedTradeUpdatesAsync(symbol, update => handler(update.AsExchangeEvent>(Exchange, new[] { new SharedTrade(update.Data.Price, update.Data.Quantity, update.Data.TradeTime) })), ct:ct).ConfigureAwait(false); + + return new ExchangeResult(Exchange, result); + } + + #endregion + + #region Book Ticker client + + SubscriptionOptions IBookTickerSocketClient.SubscribeBookTickerOptions { get; } = new SubscriptionOptions(false); + async Task> IBookTickerSocketClient.SubscribeToBookTickerUpdatesAsync(SubscribeBookTickerRequest request, Action> handler, CancellationToken ct) + { + var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeResult(Exchange, validationError); + + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)); + var result = await SubscribeToBookTickerUpdatesAsync(symbol, update => handler(update.AsExchangeEvent(Exchange, new SharedBookTicker(update.Data.BestAskPrice, update.Data.BestAskQuantity, update.Data.BestBidPrice, update.Data.BestBidQuantity))), ct).ConfigureAwait(false); + + return new ExchangeResult(Exchange, result); + } + + #endregion + + //#region Balance client + //SubscriptionOptions IBalanceSocketClient.SubscribeBalanceOptions { get; } = new SubscriptionOptions("SubscribeBalanceRequest", false); + //async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(ApiType apiType, Action>> handler, CancellationToken ct) + //{ + // var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, apiType, SupportedApiTypes); + // if (validationError != null) + // return new ExchangeResult(Exchange, validationError); + + // var listenKey = await Account.StartUserStreamAsync().ConfigureAwait(false); + // if (!listenKey) + // return new ExchangeResult(Exchange, listenKey.As(default)); + + // var result = await Account.SubscribeToUserDataUpdatesAsync(listenKey.Data.Result, + // onAccountPositionMessage: update => handler(update.As(update.Data.Balances.Select(x => new SharedBalance(x.Asset, x.Available, x.Total)))), + // ct: ct).ConfigureAwait(false); + + // return new ExchangeResult(Exchange, result); + //} + + //#endregion + + //#region Spot Order client + + //async Task> ISpotOrderSocketClient.SubscribeToSpotOrderUpdatesAsync(Action>> handler, CancellationToken ct) + //{ + // var listenKey = await Account.StartUserStreamAsync().ConfigureAwait(false); + // if (!listenKey) + // return new ExchangeResult(Exchange, listenKey.As(default)); + + // var result = await Account.SubscribeToUserDataUpdatesAsync(listenKey.Data.Result, + // onOrderUpdateMessage: update => handler(update.As>(new[] { + // new SharedSpotOrder( + // update.Data.Symbol, + // update.Data.Id.ToString(), + // update.Data.Type == Enums.SpotOrderType.Limit ? SharedOrderType.Limit : update.Data.Type == Enums.SpotOrderType.Market ? SharedOrderType.Market : update.Data.Type == Enums.SpotOrderType.LimitMaker ? SharedOrderType.LimitMaker : SharedOrderType.Other, + // update.Data.Side == Enums.OrderSide.Buy ? SharedOrderSide.Buy : SharedOrderSide.Sell, + // update.Data.Status == Enums.OrderStatus.Canceled ? SharedOrderStatus.Canceled : (update.Data.Status == Enums.OrderStatus.New || update.Data.Status == Enums.OrderStatus.PartiallyFilled) ? SharedOrderStatus.Open : SharedOrderStatus.Filled, + // update.Data.CreateTime) + // { + // ClientOrderId = update.Data.ClientOrderId, + // Price = update.Data.Price, + // Quantity = update.Data.Quantity, + // QuantityFilled = update.Data.QuantityFilled, + // QuoteQuantity = update.Data.QuoteQuantity, + // QuoteQuantityFilled = update.Data.QuoteQuantityFilled, + // UpdateTime = update.Data.UpdateTime, + // Fee = update.Data.Fee, + // FeeAsset = update.Data.FeeAsset, + // TimeInForce = update.Data.TimeInForce == Enums.TimeInForce.ImmediateOrCancel ? SharedTimeInForce.ImmediateOrCancel : update.Data.TimeInForce == Enums.TimeInForce.FillOrKill ? SharedTimeInForce.FillOrKill : update.Data.TimeInForce == Enums.TimeInForce.GoodTillDate ? SharedTimeInForce.GoodTillDate : SharedTimeInForce.GoodTillCanceled, + // LastTrade = update.Data.LastQuantityFilled == 0 ? null : new SharedUserTrade(update.Data.Symbol, update.Data.Id.ToString(), update.Data.TradeId.ToString(), update.Data.LastQuantityFilled, update.Data.LastPriceFilled, update.Data.UpdateTime) + // { + // Role = update.Data.BuyerIsMaker ? SharedRole.Maker : SharedRole.Taker + // } + // } + // })), + // ct: ct).ConfigureAwait(false); + + // return new ExchangeResult(Exchange, result); + //} + //#endregion + + #region Kline client + SubscribeKlineOptions IKlineSocketClient.SubscribeKlineOptions { get; } = new SubscribeKlineOptions(false); + async Task> IKlineSocketClient.SubscribeToKlineUpdatesAsync(SubscribeKlineRequest request, Action> handler, CancellationToken ct) + { + var interval = (Enums.KlineInterval)request.Interval; + if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) + return new ExchangeResult(Exchange, new ArgumentError("Interval not supported")); + + var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeResult(Exchange, validationError); + + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)); + var result = await SubscribeToKlineUpdatesAsync(symbol, interval, update => handler(update.AsExchangeEvent(Exchange, new SharedKline(update.Data.Data.OpenTime, update.Data.Data.ClosePrice, update.Data.Data.HighPrice, update.Data.Data.LowPrice, update.Data.Data.OpenPrice, update.Data.Data.Volume))), ct).ConfigureAwait(false); + + return new ExchangeResult(Exchange, result); + } + #endregion + + #region Order Book client + SubscribeOrderBookOptions IOrderBookSocketClient.SubscribeOrderBookOptions { get; } = new SubscribeOrderBookOptions(false, new[] { 5, 10, 20 }); + async Task> IOrderBookSocketClient.SubscribeToOrderBookUpdatesAsync(SubscribeOrderBookRequest request, Action> handler, CancellationToken ct) + { + var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeResult(Exchange, validationError); + + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)); + var result = await SubscribeToPartialOrderBookUpdatesAsync(symbol, request.Limit ?? 20, 100, update => handler(update.AsExchangeEvent(Exchange, new SharedOrderBook(update.Data.Asks, update.Data.Bids))), ct).ConfigureAwait(false); + + return new ExchangeResult(Exchange, result); + } + #endregion + } +} diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs index d70758c26..584f4a2ba 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs @@ -3,6 +3,7 @@ using CryptoExchange.Net.SharedApis.Enums; using CryptoExchange.Net.SharedApis.Interfaces.Socket; using CryptoExchange.Net.SharedApis.Models; +using CryptoExchange.Net.SharedApis.Models.FilterOptions; using CryptoExchange.Net.SharedApis.Models.Socket; using CryptoExchange.Net.SharedApis.RequestModels; using CryptoExchange.Net.SharedApis.ResponseModels; @@ -16,60 +17,103 @@ namespace Binance.Net.Clients.SpotApi internal partial class BinanceSocketClientSpotApi : IBinanceSocketClientSpotApiShared { public string Exchange => BinanceExchange.ExchangeName; - public ApiType[] SupportedApiTypes => new[] { ApiType.DeliveryInverse, ApiType.Spot }; + public ApiType[] SupportedApiTypes => new[] { ApiType.Spot }; - async Task> ITickersSocketClient.SubscribeToAllTickerUpdatesAsync(ApiType? apiType, Action>> handler, CancellationToken ct) + #region Tickers client + SubscriptionOptions ITickersSocketClient.SubscribeAllTickersOptions { get; } = new SubscriptionOptions("SubscribeTickersRequest", false); + async Task> ITickersSocketClient.SubscribeToAllTickersUpdatesAsync(ApiType apiType, Action>> handler, CancellationToken ct) { - var result = await ExchangeData.SubscribeToAllMiniTickerUpdatesAsync(update => handler(update.As(update.Data.Select(x => new SharedSpotTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume)))), ct).ConfigureAwait(false); + var validationError = ((ITickersSocketClient)this).SubscribeAllTickersOptions.ValidateRequest(Exchange, apiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeResult(Exchange, validationError); + + var result = await ExchangeData.SubscribeToAllMiniTickerUpdatesAsync(update => handler(update.AsExchangeEvent(Exchange, update.Data.Select(x => new SharedSpotTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume)))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); } - async Task> ITickerSocketClient.SubscribeToTickerUpdatesAsync(TickerSubscribeRequest request, Action> handler, CancellationToken ct) + #endregion + + #region Ticker client + SubscriptionOptions ITickerSocketClient.SubscribeTickerOptions { get; } = new SubscriptionOptions(false); + async Task> ITickerSocketClient.SubscribeToTickerUpdatesAsync(SubscribeTickerRequest request, Action> handler, CancellationToken ct) { - var symbol = FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType); - var result = await ExchangeData.SubscribeToMiniTickerUpdatesAsync(symbol, update => handler(update.As(new SharedSpotTicker(update.Data.Symbol, update.Data.LastPrice, update.Data.HighPrice, update.Data.LowPrice, update.Data.Volume))), ct).ConfigureAwait(false); + var validationError = ((ITickerSocketClient)this).SubscribeTickerOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeResult(Exchange, validationError); + + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)); + var result = await ExchangeData.SubscribeToMiniTickerUpdatesAsync(symbol, update => handler(update.AsExchangeEvent(Exchange, new SharedSpotTicker(update.Data.Symbol, update.Data.LastPrice, update.Data.HighPrice, update.Data.LowPrice, update.Data.Volume))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); } + #endregion + + #region Trade client - async Task> ITradeSocketClient.SubscribeToTradeUpdatesAsync(TradeSubscribeRequest request, Action>> handler, CancellationToken ct) + SubscriptionOptions ITradeSocketClient.SubscribeTradeOptions { get; } = new SubscriptionOptions(false); + async Task> ITradeSocketClient.SubscribeToTradeUpdatesAsync(SubscribeTradeRequest request, Action>> handler, CancellationToken ct) { - var symbol = FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType); - var result = await ExchangeData.SubscribeToTradeUpdatesAsync(symbol, update => handler(update.As>(new[] { new SharedTrade(update.Data.Price, update.Data.Quantity, update.Data.TradeTime) })), ct).ConfigureAwait(false); + var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeResult(Exchange, validationError); + + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)); + var result = await ExchangeData.SubscribeToTradeUpdatesAsync(symbol, update => handler(update.AsExchangeEvent>(Exchange, new[] { new SharedTrade(update.Data.Price, update.Data.Quantity, update.Data.TradeTime) })), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); } - async Task> IBookTickerSocketClient.SubscribeToBookTickerUpdatesAsync(BookTickerSubscribeRequest request, Action> handler, CancellationToken ct) + #endregion + + #region Book Ticker client + + SubscriptionOptions IBookTickerSocketClient.SubscribeBookTickerOptions { get; } = new SubscriptionOptions(false); + async Task> IBookTickerSocketClient.SubscribeToBookTickerUpdatesAsync(SubscribeBookTickerRequest request, Action> handler, CancellationToken ct) { - var symbol = FormatSymbol(request.BaseAsset, request.QuoteAsset, request.ApiType); - var result = await ExchangeData.SubscribeToBookTickerUpdatesAsync(symbol, update => handler(update.As(new SharedBookTicker(update.Data.BestAskPrice, update.Data.BestAskQuantity, update.Data.BestBidPrice, update.Data.BestBidQuantity))), ct).ConfigureAwait(false); + var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeResult(Exchange, validationError); + + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)); + var result = await ExchangeData.SubscribeToBookTickerUpdatesAsync(symbol, update => handler(update.AsExchangeEvent(Exchange, new SharedBookTicker(update.Data.BestAskPrice, update.Data.BestAskQuantity, update.Data.BestBidPrice, update.Data.BestBidQuantity))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); } - async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(ApiType? apiType, Action>> handler, CancellationToken ct) + #endregion + + #region Balance client + SubscriptionOptions IBalanceSocketClient.SubscribeBalanceOptions { get; } = new SubscriptionOptions("SubscribeBalanceRequest", false); + async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(ApiType apiType, Action>> handler, CancellationToken ct) { + var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, apiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeResult(Exchange, validationError); + var listenKey = await Account.StartUserStreamAsync().ConfigureAwait(false); if (!listenKey) return new ExchangeResult(Exchange, listenKey.As(default)); var result = await Account.SubscribeToUserDataUpdatesAsync(listenKey.Data.Result, - onAccountPositionMessage: update => handler(update.As(update.Data.Balances.Select(x => new SharedBalance(x.Asset, x.Available, x.Total)))), + onAccountPositionMessage: update => handler(update.AsExchangeEvent(Exchange, update.Data.Balances.Select(x => new SharedBalance(x.Asset, x.Available, x.Total)))), ct: ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); } - async Task> ISpotOrderSocketClient.SubscribeToSpotOrderUpdatesAsync(Action>> handler, CancellationToken ct) + #endregion + + #region Spot Order client + + async Task> ISpotOrderSocketClient.SubscribeToSpotOrderUpdatesAsync(Action>> handler, CancellationToken ct) { var listenKey = await Account.StartUserStreamAsync().ConfigureAwait(false); if (!listenKey) return new ExchangeResult(Exchange, listenKey.As(default)); var result = await Account.SubscribeToUserDataUpdatesAsync(listenKey.Data.Result, - onOrderUpdateMessage: update => handler(update.As>(new[] { + onOrderUpdateMessage: update => handler(update.AsExchangeEvent>(Exchange, new[] { new SharedSpotOrder( update.Data.Symbol, update.Data.Id.ToString(), @@ -98,5 +142,40 @@ async Task> ISpotOrderSocketClient.SubscribeT return new ExchangeResult(Exchange, result); } + #endregion + + #region Kline client + SubscribeKlineOptions IKlineSocketClient.SubscribeKlineOptions { get; } = new SubscribeKlineOptions(false); + async Task> IKlineSocketClient.SubscribeToKlineUpdatesAsync(SubscribeKlineRequest request, Action> handler, CancellationToken ct) + { + var interval = (Enums.KlineInterval)request.Interval; + if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) + return new ExchangeResult(Exchange, new ArgumentError("Interval not supported")); + + var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeResult(Exchange, validationError); + + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)); + var result = await ExchangeData.SubscribeToKlineUpdatesAsync(symbol, interval, update => handler(update.AsExchangeEvent(Exchange, new SharedKline(update.Data.Data.OpenTime, update.Data.Data.ClosePrice, update.Data.Data.HighPrice, update.Data.Data.LowPrice, update.Data.Data.OpenPrice, update.Data.Data.Volume))), ct).ConfigureAwait(false); + + return new ExchangeResult(Exchange, result); + } + #endregion + + #region Order Book client + SubscribeOrderBookOptions IOrderBookSocketClient.SubscribeOrderBookOptions { get; } = new SubscribeOrderBookOptions(false, new[] { 5, 10, 20 }); + async Task> IOrderBookSocketClient.SubscribeToOrderBookUpdatesAsync(SubscribeOrderBookRequest request, Action> handler, CancellationToken ct) + { + var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeResult(Exchange, validationError); + + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)); + var result = await ExchangeData.SubscribeToPartialOrderBookUpdatesAsync(symbol, request.Limit ?? 20, 100, update => handler(update.AsExchangeEvent(Exchange, new SharedOrderBook(update.Data.Asks, update.Data.Bids))), ct).ConfigureAwait(false); + + return new ExchangeResult(Exchange, result); + } + #endregion } } diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs index 9f7cec765..434194d38 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs @@ -18,7 +18,7 @@ namespace Binance.Net.Clients.UsdFuturesApi /// /// Client providing access to the Binance Usd futures websocket Api /// - internal class BinanceSocketClientUsdFuturesApi : SocketApiClient, IBinanceSocketClientUsdFuturesApi + internal partial class BinanceSocketClientUsdFuturesApi : SocketApiClient, IBinanceSocketClientUsdFuturesApi { #region fields private const string _klineStreamEndpoint = "@kline"; @@ -66,11 +66,11 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden => new BinanceAuthenticationProvider(credentials); /// - public override string FormatSymbol(string baseAsset, string quoteAsset, ApiType? futuresType = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + "_PERP"; + public override string FormatSymbol(string baseAsset, string quoteAsset, ApiType? futuresType = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(); - protected override IByteMessageAccessor CreateAccessor() => new SystemTextJsonByteMessageAccessor(); + public IBinanceSocketClientUsdFuturesApiShared SharedClient => this; #region Mark Price Stream diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs new file mode 100644 index 000000000..e20a5f3bb --- /dev/null +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs @@ -0,0 +1,185 @@ +using Binance.Net.Interfaces.Clients.SpotApi; +using Binance.Net.Interfaces.Clients.UsdFuturesApi; +using CryptoExchange.Net.Objects.Sockets; +using CryptoExchange.Net.SharedApis.Enums; +using CryptoExchange.Net.SharedApis.Interfaces.Socket; +using CryptoExchange.Net.SharedApis.Models; +using CryptoExchange.Net.SharedApis.Models.FilterOptions; +using CryptoExchange.Net.SharedApis.Models.Socket; +using CryptoExchange.Net.SharedApis.RequestModels; +using CryptoExchange.Net.SharedApis.ResponseModels; +using CryptoExchange.Net.SharedApis.SubscribeModels; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Binance.Net.Clients.UsdFuturesApi +{ + internal partial class BinanceSocketClientUsdFuturesApi : IBinanceSocketClientUsdFuturesApiShared + { + public string Exchange => BinanceExchange.ExchangeName; + public ApiType[] SupportedApiTypes => new[] { ApiType.DeliveryLinear, ApiType.PerpetualLinear }; + + #region Ticker client + + SubscriptionOptions ITickerSocketClient.SubscribeTickerOptions { get; } = new SubscriptionOptions(false); + async Task> ITickerSocketClient.SubscribeToTickerUpdatesAsync(SubscribeTickerRequest request, Action> handler, CancellationToken ct) + { + var validationError = ((ITickerSocketClient)this).SubscribeTickerOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeResult(Exchange, validationError); + + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)); + var result = await SubscribeToTickerUpdatesAsync(symbol, update => handler(update.AsExchangeEvent(Exchange, new SharedSpotTicker(symbol, update.Data.LastPrice, update.Data.LowPrice, update.Data.HighPrice, update.Data.Volume))), ct: ct).ConfigureAwait(false); + + return new ExchangeResult(Exchange, result); + } + + #endregion + + #region Tickers client + + SubscriptionOptions ITickersSocketClient.SubscribeAllTickersOptions { get; } = new SubscriptionOptions("SubscribeTickersRequest", false); + async Task> ITickersSocketClient.SubscribeToAllTickersUpdatesAsync(ApiType apiType, Action>> handler, CancellationToken ct) + { + var validationError = ((ITickersSocketClient)this).SubscribeAllTickersOptions.ValidateRequest(Exchange, apiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeResult(Exchange, validationError); + + var result = await SubscribeToAllTickerUpdatesAsync(update => handler(update.AsExchangeEvent(Exchange, update.Data.Select(x => new SharedSpotTicker(x.Symbol, x.LastPrice, x.LowPrice, x.HighPrice, x.Volume)))), ct: ct).ConfigureAwait(false); + + return new ExchangeResult(Exchange, result); + } + + #endregion + + #region Trade client + + SubscriptionOptions ITradeSocketClient.SubscribeTradeOptions { get; } = new SubscriptionOptions(false); + async Task> ITradeSocketClient.SubscribeToTradeUpdatesAsync(SubscribeTradeRequest request, Action>> handler, CancellationToken ct) + { + var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeResult(Exchange, validationError); + + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)); + var result = await SubscribeToAggregatedTradeUpdatesAsync(symbol, update => handler(update.AsExchangeEvent>(Exchange, new[] { new SharedTrade(update.Data.Price, update.Data.Quantity, update.Data.TradeTime) })), ct:ct).ConfigureAwait(false); + + return new ExchangeResult(Exchange, result); + } + + #endregion + + #region Book Ticker client + + SubscriptionOptions IBookTickerSocketClient.SubscribeBookTickerOptions { get; } = new SubscriptionOptions(false); + async Task> IBookTickerSocketClient.SubscribeToBookTickerUpdatesAsync(SubscribeBookTickerRequest request, Action> handler, CancellationToken ct) + { + var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeResult(Exchange, validationError); + + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)); + var result = await SubscribeToBookTickerUpdatesAsync(symbol, update => handler(update.AsExchangeEvent(Exchange, new SharedBookTicker(update.Data.BestAskPrice, update.Data.BestAskQuantity, update.Data.BestBidPrice, update.Data.BestBidQuantity))), ct).ConfigureAwait(false); + + return new ExchangeResult(Exchange, result); + } + + #endregion + + //#region Balance client + //SubscriptionOptions IBalanceSocketClient.SubscribeBalanceOptions { get; } = new SubscriptionOptions("SubscribeBalanceRequest", false); + //async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(ApiType apiType, Action>> handler, CancellationToken ct) + //{ + // var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, apiType, SupportedApiTypes); + // if (validationError != null) + // return new ExchangeResult(Exchange, validationError); + + // var listenKey = await Account.StartUserStreamAsync().ConfigureAwait(false); + // if (!listenKey) + // return new ExchangeResult(Exchange, listenKey.As(default)); + + // var result = await Account.SubscribeToUserDataUpdatesAsync(listenKey.Data.Result, + // onAccountPositionMessage: update => handler(update.As(update.Data.Balances.Select(x => new SharedBalance(x.Asset, x.Available, x.Total)))), + // ct: ct).ConfigureAwait(false); + + // return new ExchangeResult(Exchange, result); + //} + + //#endregion + + //#region Spot Order client + + //async Task> ISpotOrderSocketClient.SubscribeToSpotOrderUpdatesAsync(Action>> handler, CancellationToken ct) + //{ + // var listenKey = await Account.StartUserStreamAsync().ConfigureAwait(false); + // if (!listenKey) + // return new ExchangeResult(Exchange, listenKey.As(default)); + + // var result = await Account.SubscribeToUserDataUpdatesAsync(listenKey.Data.Result, + // onOrderUpdateMessage: update => handler(update.As>(new[] { + // new SharedSpotOrder( + // update.Data.Symbol, + // update.Data.Id.ToString(), + // update.Data.Type == Enums.SpotOrderType.Limit ? SharedOrderType.Limit : update.Data.Type == Enums.SpotOrderType.Market ? SharedOrderType.Market : update.Data.Type == Enums.SpotOrderType.LimitMaker ? SharedOrderType.LimitMaker : SharedOrderType.Other, + // update.Data.Side == Enums.OrderSide.Buy ? SharedOrderSide.Buy : SharedOrderSide.Sell, + // update.Data.Status == Enums.OrderStatus.Canceled ? SharedOrderStatus.Canceled : (update.Data.Status == Enums.OrderStatus.New || update.Data.Status == Enums.OrderStatus.PartiallyFilled) ? SharedOrderStatus.Open : SharedOrderStatus.Filled, + // update.Data.CreateTime) + // { + // ClientOrderId = update.Data.ClientOrderId, + // Price = update.Data.Price, + // Quantity = update.Data.Quantity, + // QuantityFilled = update.Data.QuantityFilled, + // QuoteQuantity = update.Data.QuoteQuantity, + // QuoteQuantityFilled = update.Data.QuoteQuantityFilled, + // UpdateTime = update.Data.UpdateTime, + // Fee = update.Data.Fee, + // FeeAsset = update.Data.FeeAsset, + // TimeInForce = update.Data.TimeInForce == Enums.TimeInForce.ImmediateOrCancel ? SharedTimeInForce.ImmediateOrCancel : update.Data.TimeInForce == Enums.TimeInForce.FillOrKill ? SharedTimeInForce.FillOrKill : update.Data.TimeInForce == Enums.TimeInForce.GoodTillDate ? SharedTimeInForce.GoodTillDate : SharedTimeInForce.GoodTillCanceled, + // LastTrade = update.Data.LastQuantityFilled == 0 ? null : new SharedUserTrade(update.Data.Symbol, update.Data.Id.ToString(), update.Data.TradeId.ToString(), update.Data.LastQuantityFilled, update.Data.LastPriceFilled, update.Data.UpdateTime) + // { + // Role = update.Data.BuyerIsMaker ? SharedRole.Maker : SharedRole.Taker + // } + // } + // })), + // ct: ct).ConfigureAwait(false); + + // return new ExchangeResult(Exchange, result); + //} + //#endregion + + #region Kline client + SubscribeKlineOptions IKlineSocketClient.SubscribeKlineOptions { get; } = new SubscribeKlineOptions(false); + async Task> IKlineSocketClient.SubscribeToKlineUpdatesAsync(SubscribeKlineRequest request, Action> handler, CancellationToken ct) + { + var interval = (Enums.KlineInterval)request.Interval; + if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) + return new ExchangeResult(Exchange, new ArgumentError("Interval not supported")); + + var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeResult(Exchange, validationError); + + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)); + var result = await SubscribeToKlineUpdatesAsync(symbol, interval, update => handler(update.AsExchangeEvent(Exchange, new SharedKline(update.Data.Data.OpenTime, update.Data.Data.ClosePrice, update.Data.Data.HighPrice, update.Data.Data.LowPrice, update.Data.Data.OpenPrice, update.Data.Data.Volume))), ct).ConfigureAwait(false); + + return new ExchangeResult(Exchange, result); + } + #endregion + + #region Order Book client + SubscribeOrderBookOptions IOrderBookSocketClient.SubscribeOrderBookOptions { get; } = new SubscribeOrderBookOptions(false, new[] { 5, 10, 20 }); + async Task> IOrderBookSocketClient.SubscribeToOrderBookUpdatesAsync(SubscribeOrderBookRequest request, Action> handler, CancellationToken ct) + { + var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeResult(Exchange, validationError); + + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)); + var result = await SubscribeToPartialOrderBookUpdatesAsync(symbol, request.Limit ?? 20, 100, update => handler(update.AsExchangeEvent(Exchange, new SharedOrderBook(update.Data.Asks, update.Data.Bids))), ct).ConfigureAwait(false); + + return new ExchangeResult(Exchange, result); + } + #endregion + } +} diff --git a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceSocketClientCoinFuturesApi.cs b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceSocketClientCoinFuturesApi.cs index c6141f449..6fb9333cb 100644 --- a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceSocketClientCoinFuturesApi.cs +++ b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceSocketClientCoinFuturesApi.cs @@ -11,6 +11,8 @@ namespace Binance.Net.Interfaces.Clients.CoinFuturesApi /// public interface IBinanceSocketClientCoinFuturesApi : ISocketApiClient, IDisposable { + IBinanceSocketClientCoinFuturesApiShared SharedClient { get; } + /// /// Subscribes to the aggregated trades update stream for the provided symbol /// diff --git a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceSocketClientCoinFuturesApiShared.cs b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceSocketClientCoinFuturesApiShared.cs new file mode 100644 index 000000000..9433638a4 --- /dev/null +++ b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceSocketClientCoinFuturesApiShared.cs @@ -0,0 +1,15 @@ +using CryptoExchange.Net.SharedApis.Interfaces.Socket; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Binance.Net.Interfaces.Clients.CoinFuturesApi +{ + public interface IBinanceSocketClientCoinFuturesApiShared : + ITradeSocketClient, + IBookTickerSocketClient, + IOrderBookSocketClient, + IKlineSocketClient + { + } +} diff --git a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApiShared.cs b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApiShared.cs index 504e86616..9c196a209 100644 --- a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApiShared.cs +++ b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApiShared.cs @@ -8,10 +8,12 @@ namespace Binance.Net.Interfaces.Clients.SpotApi public interface IBinanceSocketClientSpotApiShared : ITickerSocketClient, ITickersSocketClient, + ISpotOrderSocketClient, ITradeSocketClient, IBookTickerSocketClient, IBalanceSocketClient, - ISpotOrderSocketClient + IKlineSocketClient, + IOrderBookSocketClient { } } diff --git a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceSocketClientUsdFuturesApi.cs b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceSocketClientUsdFuturesApi.cs index 7beb20a7b..59fd373b3 100644 --- a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceSocketClientUsdFuturesApi.cs +++ b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceSocketClientUsdFuturesApi.cs @@ -11,6 +11,8 @@ namespace Binance.Net.Interfaces.Clients.UsdFuturesApi /// public interface IBinanceSocketClientUsdFuturesApi : ISocketApiClient, IDisposable { + IBinanceSocketClientUsdFuturesApiShared SharedClient { get; } + /// /// Subscribes to the aggregated trades update stream for the provided symbol /// diff --git a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceSocketClientUsdFuturesApiShared.cs b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceSocketClientUsdFuturesApiShared.cs new file mode 100644 index 000000000..527d1f1ba --- /dev/null +++ b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceSocketClientUsdFuturesApiShared.cs @@ -0,0 +1,17 @@ +using CryptoExchange.Net.SharedApis.Interfaces.Socket; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Binance.Net.Interfaces.Clients.UsdFuturesApi +{ + public interface IBinanceSocketClientUsdFuturesApiShared: + ITickerSocketClient, + ITickersSocketClient, + ITradeSocketClient, + IBookTickerSocketClient, + IOrderBookSocketClient, + IKlineSocketClient + { + } +} From 00d675703371d62694085643b4a74e38dc91ab58 Mon Sep 17 00:00:00 2001 From: JKorf Date: Sun, 8 Sep 2024 22:27:40 +0200 Subject: [PATCH 27/54] wip --- ...BinanceSocketClientCoinFuturesApiShared.cs | 184 +++++++++++------- .../BinanceSocketClientSpotApiShared.cs | 35 ++-- .../BinanceSocketClientUsdFuturesApiShared.cs | 157 ++++++++------- ...BinanceSocketClientCoinFuturesApiShared.cs | 6 +- ...IBinanceSocketClientUsdFuturesApiShared.cs | 4 +- 5 files changed, 228 insertions(+), 158 deletions(-) diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs index 300396dae..0de068943 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs @@ -20,12 +20,45 @@ internal partial class BinanceSocketClientCoinFuturesApi : IBinanceSocketClientC public string Exchange => BinanceExchange.ExchangeName; public ApiType[] SupportedApiTypes => new[] { ApiType.DeliveryInverse, ApiType.PerpetualInverse }; + #region Ticker client + + SubscriptionOptions ITickerSocketClient.SubscribeTickerOptions { get; } = new SubscriptionOptions(false); + async Task> ITickerSocketClient.SubscribeToTickerUpdatesAsync(SubscribeTickerRequest request, Action> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((ITickerSocketClient)this).SubscribeTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeResult(Exchange, validationError); + + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)); + var result = await SubscribeToTickerUpdatesAsync(symbol, update => handler(update.AsExchangeEvent(Exchange, new SharedSpotTicker(symbol, update.Data.LastPrice, update.Data.LowPrice, update.Data.HighPrice, update.Data.Volume))), ct: ct).ConfigureAwait(false); + + return new ExchangeResult(Exchange, result); + } + + #endregion + + #region Tickers client + + SubscriptionOptions ITickersSocketClient.SubscribeAllTickersOptions { get; } = new SubscriptionOptions("SubscribeTickersRequest", false); + async Task> ITickersSocketClient.SubscribeToAllTickersUpdatesAsync(ApiType apiType, Action>> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((ITickersSocketClient)this).SubscribeAllTickersOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeResult(Exchange, validationError); + + var result = await SubscribeToAllTickerUpdatesAsync(update => handler(update.AsExchangeEvent(Exchange, update.Data.Select(x => new SharedSpotTicker(x.Symbol, x.LastPrice, x.LowPrice, x.HighPrice, x.Volume)))), ct: ct).ConfigureAwait(false); + + return new ExchangeResult(Exchange, result); + } + + #endregion + #region Trade client SubscriptionOptions ITradeSocketClient.SubscribeTradeOptions { get; } = new SubscriptionOptions(false); - async Task> ITradeSocketClient.SubscribeToTradeUpdatesAsync(SubscribeTradeRequest request, Action>> handler, CancellationToken ct) + async Task> ITradeSocketClient.SubscribeToTradeUpdatesAsync(SubscribeTradeRequest request, Action>> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -40,9 +73,9 @@ async Task> ITradeSocketClient.SubscribeToTra #region Book Ticker client SubscriptionOptions IBookTickerSocketClient.SubscribeBookTickerOptions { get; } = new SubscriptionOptions(false); - async Task> IBookTickerSocketClient.SubscribeToBookTickerUpdatesAsync(SubscribeBookTickerRequest request, Action> handler, CancellationToken ct) + async Task> IBookTickerSocketClient.SubscribeToBookTickerUpdatesAsync(SubscribeBookTickerRequest request, Action> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -54,76 +87,15 @@ async Task> IBookTickerSocketClient.Subscribe #endregion - //#region Balance client - //SubscriptionOptions IBalanceSocketClient.SubscribeBalanceOptions { get; } = new SubscriptionOptions("SubscribeBalanceRequest", false); - //async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(ApiType apiType, Action>> handler, CancellationToken ct) - //{ - // var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, apiType, SupportedApiTypes); - // if (validationError != null) - // return new ExchangeResult(Exchange, validationError); - - // var listenKey = await Account.StartUserStreamAsync().ConfigureAwait(false); - // if (!listenKey) - // return new ExchangeResult(Exchange, listenKey.As(default)); - - // var result = await Account.SubscribeToUserDataUpdatesAsync(listenKey.Data.Result, - // onAccountPositionMessage: update => handler(update.As(update.Data.Balances.Select(x => new SharedBalance(x.Asset, x.Available, x.Total)))), - // ct: ct).ConfigureAwait(false); - - // return new ExchangeResult(Exchange, result); - //} - - //#endregion - - //#region Spot Order client - - //async Task> ISpotOrderSocketClient.SubscribeToSpotOrderUpdatesAsync(Action>> handler, CancellationToken ct) - //{ - // var listenKey = await Account.StartUserStreamAsync().ConfigureAwait(false); - // if (!listenKey) - // return new ExchangeResult(Exchange, listenKey.As(default)); - - // var result = await Account.SubscribeToUserDataUpdatesAsync(listenKey.Data.Result, - // onOrderUpdateMessage: update => handler(update.As>(new[] { - // new SharedSpotOrder( - // update.Data.Symbol, - // update.Data.Id.ToString(), - // update.Data.Type == Enums.SpotOrderType.Limit ? SharedOrderType.Limit : update.Data.Type == Enums.SpotOrderType.Market ? SharedOrderType.Market : update.Data.Type == Enums.SpotOrderType.LimitMaker ? SharedOrderType.LimitMaker : SharedOrderType.Other, - // update.Data.Side == Enums.OrderSide.Buy ? SharedOrderSide.Buy : SharedOrderSide.Sell, - // update.Data.Status == Enums.OrderStatus.Canceled ? SharedOrderStatus.Canceled : (update.Data.Status == Enums.OrderStatus.New || update.Data.Status == Enums.OrderStatus.PartiallyFilled) ? SharedOrderStatus.Open : SharedOrderStatus.Filled, - // update.Data.CreateTime) - // { - // ClientOrderId = update.Data.ClientOrderId, - // Price = update.Data.Price, - // Quantity = update.Data.Quantity, - // QuantityFilled = update.Data.QuantityFilled, - // QuoteQuantity = update.Data.QuoteQuantity, - // QuoteQuantityFilled = update.Data.QuoteQuantityFilled, - // UpdateTime = update.Data.UpdateTime, - // Fee = update.Data.Fee, - // FeeAsset = update.Data.FeeAsset, - // TimeInForce = update.Data.TimeInForce == Enums.TimeInForce.ImmediateOrCancel ? SharedTimeInForce.ImmediateOrCancel : update.Data.TimeInForce == Enums.TimeInForce.FillOrKill ? SharedTimeInForce.FillOrKill : update.Data.TimeInForce == Enums.TimeInForce.GoodTillDate ? SharedTimeInForce.GoodTillDate : SharedTimeInForce.GoodTillCanceled, - // LastTrade = update.Data.LastQuantityFilled == 0 ? null : new SharedUserTrade(update.Data.Symbol, update.Data.Id.ToString(), update.Data.TradeId.ToString(), update.Data.LastQuantityFilled, update.Data.LastPriceFilled, update.Data.UpdateTime) - // { - // Role = update.Data.BuyerIsMaker ? SharedRole.Maker : SharedRole.Taker - // } - // } - // })), - // ct: ct).ConfigureAwait(false); - - // return new ExchangeResult(Exchange, result); - //} - //#endregion - #region Kline client SubscribeKlineOptions IKlineSocketClient.SubscribeKlineOptions { get; } = new SubscribeKlineOptions(false); - async Task> IKlineSocketClient.SubscribeToKlineUpdatesAsync(SubscribeKlineRequest request, Action> handler, CancellationToken ct) + async Task> IKlineSocketClient.SubscribeToKlineUpdatesAsync(SubscribeKlineRequest request, Action> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) { var interval = (Enums.KlineInterval)request.Interval; if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeResult(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -136,9 +108,9 @@ async Task> IKlineSocketClient.SubscribeToKli #region Order Book client SubscribeOrderBookOptions IOrderBookSocketClient.SubscribeOrderBookOptions { get; } = new SubscribeOrderBookOptions(false, new[] { 5, 10, 20 }); - async Task> IOrderBookSocketClient.SubscribeToOrderBookUpdatesAsync(SubscribeOrderBookRequest request, Action> handler, CancellationToken ct) + async Task> IOrderBookSocketClient.SubscribeToOrderBookUpdatesAsync(SubscribeOrderBookRequest request, Action> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -148,5 +120,79 @@ async Task> IOrderBookSocketClient.SubscribeT return new ExchangeResult(Exchange, result); } #endregion + + #region Balance client + SubscriptionOptions IBalanceSocketClient.SubscribeBalanceOptions { get; } = new SubscriptionOptions("SubscribeBalanceRequest", false) + { + RequiredExchangeParameters = new List + { + new ParameterDescription("ListenKey", typeof(string), "The listenkey for starting the user stream", "123123123") + } + }; + async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(ApiType apiType, Action>> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeResult(Exchange, validationError); + + var listenKey = exchangeParameters.GetValue(Exchange, "ListenKey"); + var result = await SubscribeToUserDataUpdatesAsync(listenKey!, +#warning correct? + onAccountUpdate: update => handler(update.AsExchangeEvent(Exchange, update.Data.UpdateData.Balances.Select(x => new SharedBalance(x.Asset, x.WalletBalance, x.WalletBalance + x.CrossWalletBalance)))), + ct: ct).ConfigureAwait(false); + + return new ExchangeResult(Exchange, result); + } + + #endregion + + #region Futures Order client + + SubscriptionOptions IFuturesOrderSocketClient.SubscribeFuturesOrderOptions { get; } = new SubscriptionOptions("SubscribeFuturesOrderRequest", false) + { + RequiredExchangeParameters = new List + { + new ParameterDescription("ListenKey", typeof(string), "The listenkey for starting the user stream", "123123123") + } + }; + async Task> IFuturesOrderSocketClient.SubscribeToFuturesOrderUpdatesAsync(ApiType apiType, Action>> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeResult(Exchange, validationError); + + var listenKey = exchangeParameters.GetValue(Exchange, "ListenKey"); + var result = await SubscribeToUserDataUpdatesAsync(listenKey, + onOrderUpdate: update => handler(update.AsExchangeEvent>(Exchange, new[] { + new SharedFuturesOrder( + update.Data.UpdateData.Symbol, + update.Data.UpdateData.OrderId.ToString(), + update.Data.UpdateData.Type == Enums.FuturesOrderType.Limit ? SharedOrderType.Limit : update.Data.UpdateData.Type == Enums.FuturesOrderType.Market ? SharedOrderType.Market : SharedOrderType.Other, + update.Data.UpdateData.Side == Enums.OrderSide.Buy ? SharedOrderSide.Buy : SharedOrderSide.Sell, + update.Data.UpdateData.Status == Enums.OrderStatus.Canceled ? SharedOrderStatus.Canceled : (update.Data.UpdateData.Status == Enums.OrderStatus.New || update.Data.UpdateData.Status == Enums.OrderStatus.PartiallyFilled) ? SharedOrderStatus.Open : SharedOrderStatus.Filled, + update.Data.UpdateData.UpdateTime) + { + ClientOrderId = update.Data.UpdateData.ClientOrderId, + Price = update.Data.UpdateData.Price, + Quantity = update.Data.UpdateData.Quantity, + QuantityFilled = update.Data.UpdateData.AccumulatedQuantityOfFilledTrades, + UpdateTime = update.Data.UpdateData.UpdateTime, + Fee = update.Data.UpdateData.Fee, + FeeAsset = update.Data.UpdateData.FeeAsset, + AveragePrice = update.Data.UpdateData.AveragePrice, + PositionSide = update.Data.UpdateData.PositionSide == Enums.PositionSide.Long ? SharedPositionSide.Long : update.Data.UpdateData.PositionSide == Enums.PositionSide.Short ? SharedPositionSide.Short : null, + ReduceOnly = update.Data.UpdateData.IsReduce, + TimeInForce = update.Data.UpdateData.TimeInForce == Enums.TimeInForce.ImmediateOrCancel ? SharedTimeInForce.ImmediateOrCancel : update.Data.UpdateData.TimeInForce == Enums.TimeInForce.FillOrKill ? SharedTimeInForce.FillOrKill : update.Data.UpdateData.TimeInForce == Enums.TimeInForce.GoodTillDate ? SharedTimeInForce.GoodTillDate : SharedTimeInForce.GoodTillCanceled, + LastTrade = update.Data.UpdateData.QuantityOfLastFilledTrade == 0 ? null : new SharedUserTrade(update.Data.UpdateData.Symbol, update.Data.UpdateData.OrderId.ToString(), update.Data.UpdateData.TradeId.ToString(), update.Data.UpdateData.QuantityOfLastFilledTrade, update.Data.UpdateData.PriceLastFilledTrade, update.Data.UpdateData.UpdateTime) + { + Role = update.Data.UpdateData.BuyerIsMaker ? SharedRole.Maker : SharedRole.Taker + } + } + })), + ct: ct).ConfigureAwait(false); + + return new ExchangeResult(Exchange, result); + } + #endregion } } diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs index 584f4a2ba..8709950ad 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs @@ -21,9 +21,9 @@ internal partial class BinanceSocketClientSpotApi : IBinanceSocketClientSpotApiS #region Tickers client SubscriptionOptions ITickersSocketClient.SubscribeAllTickersOptions { get; } = new SubscriptionOptions("SubscribeTickersRequest", false); - async Task> ITickersSocketClient.SubscribeToAllTickersUpdatesAsync(ApiType apiType, Action>> handler, CancellationToken ct) + async Task> ITickersSocketClient.SubscribeToAllTickersUpdatesAsync(ApiType apiType, Action>> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ITickersSocketClient)this).SubscribeAllTickersOptions.ValidateRequest(Exchange, apiType, SupportedApiTypes); + var validationError = ((ITickersSocketClient)this).SubscribeAllTickersOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -36,9 +36,9 @@ async Task> ITickersSocketClient.SubscribeToA #region Ticker client SubscriptionOptions ITickerSocketClient.SubscribeTickerOptions { get; } = new SubscriptionOptions(false); - async Task> ITickerSocketClient.SubscribeToTickerUpdatesAsync(SubscribeTickerRequest request, Action> handler, CancellationToken ct) + async Task> ITickerSocketClient.SubscribeToTickerUpdatesAsync(SubscribeTickerRequest request, Action> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ITickerSocketClient)this).SubscribeTickerOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((ITickerSocketClient)this).SubscribeTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -52,9 +52,9 @@ async Task> ITickerSocketClient.SubscribeToTi #region Trade client SubscriptionOptions ITradeSocketClient.SubscribeTradeOptions { get; } = new SubscriptionOptions(false); - async Task> ITradeSocketClient.SubscribeToTradeUpdatesAsync(SubscribeTradeRequest request, Action>> handler, CancellationToken ct) + async Task> ITradeSocketClient.SubscribeToTradeUpdatesAsync(SubscribeTradeRequest request, Action>> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -69,9 +69,9 @@ async Task> ITradeSocketClient.SubscribeToTra #region Book Ticker client SubscriptionOptions IBookTickerSocketClient.SubscribeBookTickerOptions { get; } = new SubscriptionOptions(false); - async Task> IBookTickerSocketClient.SubscribeToBookTickerUpdatesAsync(SubscribeBookTickerRequest request, Action> handler, CancellationToken ct) + async Task> IBookTickerSocketClient.SubscribeToBookTickerUpdatesAsync(SubscribeBookTickerRequest request, Action> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -85,9 +85,9 @@ async Task> IBookTickerSocketClient.Subscribe #region Balance client SubscriptionOptions IBalanceSocketClient.SubscribeBalanceOptions { get; } = new SubscriptionOptions("SubscribeBalanceRequest", false); - async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(ApiType apiType, Action>> handler, CancellationToken ct) + async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(ApiType apiType, Action>> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, apiType, SupportedApiTypes); + var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -106,8 +106,13 @@ async Task> IBalanceSocketClient.SubscribeToB #region Spot Order client - async Task> ISpotOrderSocketClient.SubscribeToSpotOrderUpdatesAsync(Action>> handler, CancellationToken ct) + SubscriptionOptions ISpotOrderSocketClient.SubscribeSpotOrderOptions { get; } = new SubscriptionOptions("SubscribeSpotOrderRequest", false); + async Task> ISpotOrderSocketClient.SubscribeToSpotOrderUpdatesAsync(Action>> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) { + var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, exchangeParameters, ApiType.Spot, SupportedApiTypes); + if (validationError != null) + return new ExchangeResult(Exchange, validationError); + var listenKey = await Account.StartUserStreamAsync().ConfigureAwait(false); if (!listenKey) return new ExchangeResult(Exchange, listenKey.As(default)); @@ -146,13 +151,13 @@ async Task> ISpotOrderSocketClient.SubscribeT #region Kline client SubscribeKlineOptions IKlineSocketClient.SubscribeKlineOptions { get; } = new SubscribeKlineOptions(false); - async Task> IKlineSocketClient.SubscribeToKlineUpdatesAsync(SubscribeKlineRequest request, Action> handler, CancellationToken ct) + async Task> IKlineSocketClient.SubscribeToKlineUpdatesAsync(SubscribeKlineRequest request, Action> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) { var interval = (Enums.KlineInterval)request.Interval; if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeResult(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -165,9 +170,9 @@ async Task> IKlineSocketClient.SubscribeToKli #region Order Book client SubscribeOrderBookOptions IOrderBookSocketClient.SubscribeOrderBookOptions { get; } = new SubscribeOrderBookOptions(false, new[] { 5, 10, 20 }); - async Task> IOrderBookSocketClient.SubscribeToOrderBookUpdatesAsync(SubscribeOrderBookRequest request, Action> handler, CancellationToken ct) + async Task> IOrderBookSocketClient.SubscribeToOrderBookUpdatesAsync(SubscribeOrderBookRequest request, Action> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs index e20a5f3bb..bbdb8cf29 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs @@ -23,9 +23,9 @@ internal partial class BinanceSocketClientUsdFuturesApi : IBinanceSocketClientUs #region Ticker client SubscriptionOptions ITickerSocketClient.SubscribeTickerOptions { get; } = new SubscriptionOptions(false); - async Task> ITickerSocketClient.SubscribeToTickerUpdatesAsync(SubscribeTickerRequest request, Action> handler, CancellationToken ct) + async Task> ITickerSocketClient.SubscribeToTickerUpdatesAsync(SubscribeTickerRequest request, Action> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ITickerSocketClient)this).SubscribeTickerOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((ITickerSocketClient)this).SubscribeTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -40,9 +40,9 @@ async Task> ITickerSocketClient.SubscribeToTi #region Tickers client SubscriptionOptions ITickersSocketClient.SubscribeAllTickersOptions { get; } = new SubscriptionOptions("SubscribeTickersRequest", false); - async Task> ITickersSocketClient.SubscribeToAllTickersUpdatesAsync(ApiType apiType, Action>> handler, CancellationToken ct) + async Task> ITickersSocketClient.SubscribeToAllTickersUpdatesAsync(ApiType apiType, Action>> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ITickersSocketClient)this).SubscribeAllTickersOptions.ValidateRequest(Exchange, apiType, SupportedApiTypes); + var validationError = ((ITickersSocketClient)this).SubscribeAllTickersOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -56,9 +56,9 @@ async Task> ITickersSocketClient.SubscribeToA #region Trade client SubscriptionOptions ITradeSocketClient.SubscribeTradeOptions { get; } = new SubscriptionOptions(false); - async Task> ITradeSocketClient.SubscribeToTradeUpdatesAsync(SubscribeTradeRequest request, Action>> handler, CancellationToken ct) + async Task> ITradeSocketClient.SubscribeToTradeUpdatesAsync(SubscribeTradeRequest request, Action>> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -73,9 +73,9 @@ async Task> ITradeSocketClient.SubscribeToTra #region Book Ticker client SubscriptionOptions IBookTickerSocketClient.SubscribeBookTickerOptions { get; } = new SubscriptionOptions(false); - async Task> IBookTickerSocketClient.SubscribeToBookTickerUpdatesAsync(SubscribeBookTickerRequest request, Action> handler, CancellationToken ct) + async Task> IBookTickerSocketClient.SubscribeToBookTickerUpdatesAsync(SubscribeBookTickerRequest request, Action> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -87,76 +87,89 @@ async Task> IBookTickerSocketClient.Subscribe #endregion - //#region Balance client - //SubscriptionOptions IBalanceSocketClient.SubscribeBalanceOptions { get; } = new SubscriptionOptions("SubscribeBalanceRequest", false); - //async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(ApiType apiType, Action>> handler, CancellationToken ct) - //{ - // var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, apiType, SupportedApiTypes); - // if (validationError != null) - // return new ExchangeResult(Exchange, validationError); - - // var listenKey = await Account.StartUserStreamAsync().ConfigureAwait(false); - // if (!listenKey) - // return new ExchangeResult(Exchange, listenKey.As(default)); - - // var result = await Account.SubscribeToUserDataUpdatesAsync(listenKey.Data.Result, - // onAccountPositionMessage: update => handler(update.As(update.Data.Balances.Select(x => new SharedBalance(x.Asset, x.Available, x.Total)))), - // ct: ct).ConfigureAwait(false); - - // return new ExchangeResult(Exchange, result); - //} - - //#endregion - - //#region Spot Order client - - //async Task> ISpotOrderSocketClient.SubscribeToSpotOrderUpdatesAsync(Action>> handler, CancellationToken ct) - //{ - // var listenKey = await Account.StartUserStreamAsync().ConfigureAwait(false); - // if (!listenKey) - // return new ExchangeResult(Exchange, listenKey.As(default)); - - // var result = await Account.SubscribeToUserDataUpdatesAsync(listenKey.Data.Result, - // onOrderUpdateMessage: update => handler(update.As>(new[] { - // new SharedSpotOrder( - // update.Data.Symbol, - // update.Data.Id.ToString(), - // update.Data.Type == Enums.SpotOrderType.Limit ? SharedOrderType.Limit : update.Data.Type == Enums.SpotOrderType.Market ? SharedOrderType.Market : update.Data.Type == Enums.SpotOrderType.LimitMaker ? SharedOrderType.LimitMaker : SharedOrderType.Other, - // update.Data.Side == Enums.OrderSide.Buy ? SharedOrderSide.Buy : SharedOrderSide.Sell, - // update.Data.Status == Enums.OrderStatus.Canceled ? SharedOrderStatus.Canceled : (update.Data.Status == Enums.OrderStatus.New || update.Data.Status == Enums.OrderStatus.PartiallyFilled) ? SharedOrderStatus.Open : SharedOrderStatus.Filled, - // update.Data.CreateTime) - // { - // ClientOrderId = update.Data.ClientOrderId, - // Price = update.Data.Price, - // Quantity = update.Data.Quantity, - // QuantityFilled = update.Data.QuantityFilled, - // QuoteQuantity = update.Data.QuoteQuantity, - // QuoteQuantityFilled = update.Data.QuoteQuantityFilled, - // UpdateTime = update.Data.UpdateTime, - // Fee = update.Data.Fee, - // FeeAsset = update.Data.FeeAsset, - // TimeInForce = update.Data.TimeInForce == Enums.TimeInForce.ImmediateOrCancel ? SharedTimeInForce.ImmediateOrCancel : update.Data.TimeInForce == Enums.TimeInForce.FillOrKill ? SharedTimeInForce.FillOrKill : update.Data.TimeInForce == Enums.TimeInForce.GoodTillDate ? SharedTimeInForce.GoodTillDate : SharedTimeInForce.GoodTillCanceled, - // LastTrade = update.Data.LastQuantityFilled == 0 ? null : new SharedUserTrade(update.Data.Symbol, update.Data.Id.ToString(), update.Data.TradeId.ToString(), update.Data.LastQuantityFilled, update.Data.LastPriceFilled, update.Data.UpdateTime) - // { - // Role = update.Data.BuyerIsMaker ? SharedRole.Maker : SharedRole.Taker - // } - // } - // })), - // ct: ct).ConfigureAwait(false); - - // return new ExchangeResult(Exchange, result); - //} - //#endregion + #region Balance client + SubscriptionOptions IBalanceSocketClient.SubscribeBalanceOptions { get; } = new SubscriptionOptions("SubscribeBalanceRequest", false) + { + RequiredExchangeParameters = new List + { + new ParameterDescription("ListenKey", typeof(string), "The listenkey for starting the user stream", "123123123") + } + }; + async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(ApiType apiType, Action>> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeResult(Exchange, validationError); + + var listenKey = exchangeParameters.GetValue(Exchange, "ListenKey"); + var result = await SubscribeToUserDataUpdatesAsync(listenKey!, +#warning correct? + onAccountUpdate: update => handler(update.AsExchangeEvent(Exchange, update.Data.UpdateData.Balances.Select(x => new SharedBalance(x.Asset, x.WalletBalance, x.WalletBalance + x.CrossWalletBalance)))), + ct: ct).ConfigureAwait(false); + + return new ExchangeResult(Exchange, result); + } + + #endregion + + #region Futures Order client + + SubscriptionOptions IFuturesOrderSocketClient.SubscribeFuturesOrderOptions { get; } = new SubscriptionOptions("SubscribeFuturesOrderRequest", false) + { + RequiredExchangeParameters = new List + { + new ParameterDescription("ListenKey", typeof(string), "The listenkey for starting the user stream", "123123123") + } + }; + async Task> IFuturesOrderSocketClient.SubscribeToFuturesOrderUpdatesAsync(ApiType apiType, Action>> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeResult(Exchange, validationError); + + var listenKey = exchangeParameters.GetValue(Exchange, "ListenKey"); + var result = await SubscribeToUserDataUpdatesAsync(listenKey, + onOrderUpdate: update => handler(update.AsExchangeEvent>(Exchange, new[] { + new SharedFuturesOrder( + update.Data.UpdateData.Symbol, + update.Data.UpdateData.OrderId.ToString(), + update.Data.UpdateData.Type == Enums.FuturesOrderType.Limit ? SharedOrderType.Limit : update.Data.UpdateData.Type == Enums.FuturesOrderType.Market ? SharedOrderType.Market : SharedOrderType.Other, + update.Data.UpdateData.Side == Enums.OrderSide.Buy ? SharedOrderSide.Buy : SharedOrderSide.Sell, + update.Data.UpdateData.Status == Enums.OrderStatus.Canceled ? SharedOrderStatus.Canceled : (update.Data.UpdateData.Status == Enums.OrderStatus.New || update.Data.UpdateData.Status == Enums.OrderStatus.PartiallyFilled) ? SharedOrderStatus.Open : SharedOrderStatus.Filled, + update.Data.UpdateData.UpdateTime) + { + ClientOrderId = update.Data.UpdateData.ClientOrderId, + Price = update.Data.UpdateData.Price, + Quantity = update.Data.UpdateData.Quantity, + QuantityFilled = update.Data.UpdateData.AccumulatedQuantityOfFilledTrades, + UpdateTime = update.Data.UpdateData.UpdateTime, + Fee = update.Data.UpdateData.Fee, + FeeAsset = update.Data.UpdateData.FeeAsset, + AveragePrice = update.Data.UpdateData.AveragePrice, + PositionSide = update.Data.UpdateData.PositionSide == Enums.PositionSide.Long ? SharedPositionSide.Long : update.Data.UpdateData.PositionSide == Enums.PositionSide.Short ? SharedPositionSide.Short : null, + ReduceOnly = update.Data.UpdateData.IsReduce, + TimeInForce = update.Data.UpdateData.TimeInForce == Enums.TimeInForce.ImmediateOrCancel ? SharedTimeInForce.ImmediateOrCancel : update.Data.UpdateData.TimeInForce == Enums.TimeInForce.FillOrKill ? SharedTimeInForce.FillOrKill : update.Data.UpdateData.TimeInForce == Enums.TimeInForce.GoodTillDate ? SharedTimeInForce.GoodTillDate : SharedTimeInForce.GoodTillCanceled, + LastTrade = update.Data.UpdateData.QuantityOfLastFilledTrade == 0 ? null : new SharedUserTrade(update.Data.UpdateData.Symbol, update.Data.UpdateData.OrderId.ToString(), update.Data.UpdateData.TradeId.ToString(), update.Data.UpdateData.QuantityOfLastFilledTrade, update.Data.UpdateData.PriceLastFilledTrade, update.Data.UpdateData.UpdateTime) + { + Role = update.Data.UpdateData.BuyerIsMaker ? SharedRole.Maker : SharedRole.Taker + } + } + })), + ct: ct).ConfigureAwait(false); + + return new ExchangeResult(Exchange, result); + } + #endregion #region Kline client SubscribeKlineOptions IKlineSocketClient.SubscribeKlineOptions { get; } = new SubscribeKlineOptions(false); - async Task> IKlineSocketClient.SubscribeToKlineUpdatesAsync(SubscribeKlineRequest request, Action> handler, CancellationToken ct) + async Task> IKlineSocketClient.SubscribeToKlineUpdatesAsync(SubscribeKlineRequest request, Action> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) { var interval = (Enums.KlineInterval)request.Interval; if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeResult(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -169,9 +182,9 @@ async Task> IKlineSocketClient.SubscribeToKli #region Order Book client SubscribeOrderBookOptions IOrderBookSocketClient.SubscribeOrderBookOptions { get; } = new SubscribeOrderBookOptions(false, new[] { 5, 10, 20 }); - async Task> IOrderBookSocketClient.SubscribeToOrderBookUpdatesAsync(SubscribeOrderBookRequest request, Action> handler, CancellationToken ct) + async Task> IOrderBookSocketClient.SubscribeToOrderBookUpdatesAsync(SubscribeOrderBookRequest request, Action> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); diff --git a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceSocketClientCoinFuturesApiShared.cs b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceSocketClientCoinFuturesApiShared.cs index 9433638a4..4f6cf22c1 100644 --- a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceSocketClientCoinFuturesApiShared.cs +++ b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceSocketClientCoinFuturesApiShared.cs @@ -6,10 +6,14 @@ namespace Binance.Net.Interfaces.Clients.CoinFuturesApi { public interface IBinanceSocketClientCoinFuturesApiShared : + ITickerSocketClient, + ITickersSocketClient, ITradeSocketClient, IBookTickerSocketClient, IOrderBookSocketClient, - IKlineSocketClient + IKlineSocketClient, + IFuturesOrderSocketClient, + IBalanceSocketClient { } } diff --git a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceSocketClientUsdFuturesApiShared.cs b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceSocketClientUsdFuturesApiShared.cs index 527d1f1ba..95833abc3 100644 --- a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceSocketClientUsdFuturesApiShared.cs +++ b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceSocketClientUsdFuturesApiShared.cs @@ -11,7 +11,9 @@ public interface IBinanceSocketClientUsdFuturesApiShared: ITradeSocketClient, IBookTickerSocketClient, IOrderBookSocketClient, - IKlineSocketClient + IKlineSocketClient, + IBalanceSocketClient, + IFuturesOrderSocketClient { } } From abb309e085eb2a4287ed4b9581811e27762977ad Mon Sep 17 00:00:00 2001 From: Jkorf Date: Mon, 9 Sep 2024 15:35:56 +0200 Subject: [PATCH 28/54] wip --- Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs index 8709950ad..fd1bcc612 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs @@ -109,7 +109,7 @@ async Task> IBalanceSocketClient.SubscribeToB SubscriptionOptions ISpotOrderSocketClient.SubscribeSpotOrderOptions { get; } = new SubscriptionOptions("SubscribeSpotOrderRequest", false); async Task> ISpotOrderSocketClient.SubscribeToSpotOrderUpdatesAsync(Action>> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, exchangeParameters, ApiType.Spot, SupportedApiTypes); + var validationError = ((ISpotOrderSocketClient)this).SubscribeSpotOrderOptions.ValidateRequest(Exchange, exchangeParameters, ApiType.Spot, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); From 0de250bc1fed81d04888734a3129df7778022edf Mon Sep 17 00:00:00 2001 From: JKorf Date: Mon, 9 Sep 2024 21:30:31 +0200 Subject: [PATCH 29/54] wip --- .../BinanceSocketClientCoinFuturesApiShared.cs | 8 +++++++- .../BinanceSocketClientUsdFuturesApiShared.cs | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs index 0de068943..223b21184 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs @@ -46,7 +46,13 @@ async Task> ITickersSocketClient.SubscribeToA if (validationError != null) return new ExchangeResult(Exchange, validationError); - var result = await SubscribeToAllTickerUpdatesAsync(update => handler(update.AsExchangeEvent(Exchange, update.Data.Select(x => new SharedSpotTicker(x.Symbol, x.LastPrice, x.LowPrice, x.HighPrice, x.Volume)))), ct: ct).ConfigureAwait(false); + var result = await SubscribeToAllTickerUpdatesAsync(update => + { + var data = update.Data.Where(x => apiType == ApiType.PerpetualInverse ? x.Symbol.EndsWith("_PERP") : !x.Symbol.Contains("_PERP")); + if (!data.Any()) + return; + handler(update.AsExchangeEvent(Exchange, data.Select(x => new SharedSpotTicker(x.Symbol, x.LastPrice, x.LowPrice, x.HighPrice, x.Volume)))); + }, ct: ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); } diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs index bbdb8cf29..f19d2868f 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs @@ -46,7 +46,13 @@ async Task> ITickersSocketClient.SubscribeToA if (validationError != null) return new ExchangeResult(Exchange, validationError); - var result = await SubscribeToAllTickerUpdatesAsync(update => handler(update.AsExchangeEvent(Exchange, update.Data.Select(x => new SharedSpotTicker(x.Symbol, x.LastPrice, x.LowPrice, x.HighPrice, x.Volume)))), ct: ct).ConfigureAwait(false); + var result = await SubscribeToAllTickerUpdatesAsync(update => + { + var data = update.Data.Where(x => apiType == ApiType.PerpetualLinear ? x.Symbol.Contains("_") : !x.Symbol.Contains("_")); + if (!data.Any()) + return; + handler(update.AsExchangeEvent(Exchange, data.Select(x => new SharedSpotTicker(x.Symbol, x.LastPrice, x.LowPrice, x.HighPrice, x.Volume)))); + }, ct: ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); } From fe2f186ada15865c5cd53260101703ba10570907 Mon Sep 17 00:00:00 2001 From: JKorf Date: Mon, 9 Sep 2024 21:58:58 +0200 Subject: [PATCH 30/54] wip --- Binance.Net/Binance.Net.xml | 14 +++---- .../BinanceRestClientCoinFuturesApi.cs | 5 +-- .../BinanceRestClientCoinFuturesApiShared.cs | 42 +++++++++---------- .../BinanceSocketClientCoinFuturesApi.cs | 6 ++- ...BinanceSocketClientCoinFuturesApiShared.cs | 10 ++--- .../GeneralApi/BinanceRestClientGeneralApi.cs | 2 +- .../SpotApi/BinanceRestClientSpotApi.cs | 2 +- .../SpotApi/BinanceRestClientSpotApiShared.cs | 24 +++++------ .../SpotApi/BinanceSocketClientSpotApi.cs | 2 +- .../BinanceSocketClientSpotApiShared.cs | 10 ++--- .../BinanceRestClientUsdFuturesApi.cs | 4 +- .../BinanceRestClientUsdFuturesApiShared.cs | 42 +++++++++---------- .../BinanceSocketClientUsdFuturesApi.cs | 5 ++- .../BinanceSocketClientUsdFuturesApiShared.cs | 10 ++--- 14 files changed, 91 insertions(+), 87 deletions(-) diff --git a/Binance.Net/Binance.Net.xml b/Binance.Net/Binance.Net.xml index 674dbfc3a..3766cea5d 100644 --- a/Binance.Net/Binance.Net.xml +++ b/Binance.Net/Binance.Net.xml @@ -265,7 +265,7 @@ - + @@ -466,7 +466,7 @@ - + @@ -625,7 +625,7 @@ - + @@ -1130,7 +1130,7 @@ - + @@ -1670,7 +1670,7 @@ - + @@ -1905,7 +1905,7 @@ Event triggered when an order is canceled via this client. Note that this does not trigger when using CancelAllOrdersAsync. Only available for Spot orders - + @@ -2218,7 +2218,7 @@ - + diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs index 982d6e4d8..29e0fb48b 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs @@ -75,10 +75,9 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(); /// - public override string FormatSymbol(string baseAsset, string quoteAsset, ApiType? futuresType = null) + public override string FormatSymbol(string baseAsset, string quoteAsset, DateTime? deliverTime, ApiType? futuresType = null) { - var suffix = futuresType == null ? string.Empty : "_PERP"; - return baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + suffix; + return baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + (deliverTime == null ? "_PERP" : "_" + deliverTime.Value.ToString("yyMMdd")); } 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 2c4705447..4fee3670e 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -42,7 +42,7 @@ async Task>> IKlineRestClient.GetKlin fromTimestamp = dateTimeToken.LastTime; var result = await ExchangeData.GetKlinesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), interval, fromTimestamp ?? request.StartTime, request.EndTime, @@ -102,8 +102,8 @@ async Task> IFuturesTickerRestClient.GetF if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var resultTicker = ExchangeData.GetTickersAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), ct: ct); - var resultMarkPrice = ExchangeData.GetMarkPricesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), ct: ct); + var resultTicker = ExchangeData.GetTickersAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), ct: ct); + var resultMarkPrice = ExchangeData.GetMarkPricesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), ct: ct); await Task.WhenAll(resultTicker, resultMarkPrice).ConfigureAwait(false); if (!resultTicker.Result) return resultTicker.Result.AsExchangeResult(Exchange, default); @@ -165,7 +165,7 @@ async Task>> IRecentTradeRestClient.G return new ExchangeWebResult>(Exchange, validationError); var result = await ExchangeData.GetRecentTradesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) @@ -203,7 +203,7 @@ async Task> IFuturesOrderRestClient.PlaceFuturesOrde return new ExchangeWebResult(Exchange, validationError); var result = await Trading.PlaceOrderAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), request.Side == SharedOrderSide.Buy ? Enums.OrderSide.Buy : Enums.OrderSide.Sell, request.OrderType == SharedOrderType.Limit ? Enums.FuturesOrderType.Limit : Enums.FuturesOrderType.Market, quantity: request.Quantity, @@ -228,7 +228,7 @@ async Task> IFuturesOrderRestClient.GetFut if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); - var order = await Trading.GetOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), orderId).ConfigureAwait(false); + var order = await Trading.GetOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), orderId).ConfigureAwait(false); if (!order) return order.AsExchangeResult(Exchange, default); @@ -260,7 +260,7 @@ async Task>> IFuturesOrderRest if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); - var symbol = request.Symbol?.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)); + var symbol = request.Symbol?.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)); var orders = await Trading.GetOpenOrdersAsync(symbol).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); @@ -299,7 +299,7 @@ async Task>> IFuturesOrderRest fromTimestamp = dateTimeToken.LastTime; // Get data - var orders = await Trading.GetOrdersAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), + var orders = await Trading.GetOrdersAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), startTime: fromTimestamp ?? request.StartTime, endTime: request.EndTime, limit: request.Limit ?? 1000).ConfigureAwait(false); @@ -342,7 +342,7 @@ async Task>> IFuturesOrderRestCli if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult>(Exchange, new ArgumentError("Invalid order id")); - var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), orderId: orderId).ConfigureAwait(false); + var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), orderId: orderId).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); @@ -375,7 +375,7 @@ async Task>> IFuturesOrderRestCli fromId = long.Parse(fromIdToken.FromToken); // Get data - var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), + var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), startTime: request.StartTime, endTime: request.EndTime, limit: request.Limit ?? 500, @@ -415,7 +415,7 @@ async Task> IFuturesOrderRestClient.CancelFuturesOrd if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); - var order = await Trading.CancelOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), orderId).ConfigureAwait(false); + var order = await Trading.CancelOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), orderId).ConfigureAwait(false); if (!order) return order.AsExchangeResult(Exchange, default); @@ -429,7 +429,7 @@ async Task>> IFuturesOrderRestClie if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); - var result = await Account.GetPositionInformationAsync(pair: request.Symbol?.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), ct: ct).ConfigureAwait(false); + var result = await Account.GetPositionInformationAsync(pair: request.Symbol?.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate)), ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult>(Exchange, default); @@ -451,7 +451,7 @@ async Task> IFuturesOrderRestClient.ClosePositionAsy return new ExchangeWebResult(Exchange, validationError); var result = await Trading.PlaceOrderAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate)), request.PositionSide == SharedPositionSide.Long ? OrderSide.Sell : OrderSide.Buy, FuturesOrderType.Market, request.Quantity, @@ -500,7 +500,7 @@ async Task> ILeverageRestClient.GetLeverageAsy if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var result = await Account.GetPositionInformationAsync(pair: request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), ct: ct).ConfigureAwait(false); + var result = await Account.GetPositionInformationAsync(pair: request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate)), ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -525,7 +525,7 @@ async Task> ILeverageRestClient.SetLeverageAsy if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var result = await Account.ChangeInitialLeverageAsync(symbol: request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), (int)request.Leverage ,ct: ct).ConfigureAwait(false); + var result = await Account.ChangeInitialLeverageAsync(symbol: request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), (int)request.Leverage ,ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -556,7 +556,7 @@ async Task>> IMarkPriceKlineRestC fromTimestamp = dateTimeToken.LastTime; var result = await ExchangeData.GetMarkPriceKlinesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), interval, request.Limit ?? 1000, fromTimestamp ?? request.StartTime, @@ -589,7 +589,7 @@ async Task> IOrderBookRestClient.GetOrderBook return new ExchangeWebResult(Exchange, validationError); var result = await ExchangeData.GetOrderBookAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate)), limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) @@ -615,7 +615,7 @@ async Task>> ITradeHistoryRestClient. // Get data var result = await ExchangeData.GetAggregatedTradeHistoryAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), startTime: fromId != null ? null : request.StartTime, endTime: fromId != null ? null : request.EndTime, limit: 1000, @@ -656,7 +656,7 @@ async Task>> IIndexPriceKlineRest fromTimestamp = dateTimeToken.LastTime; var result = await ExchangeData.GetMarkPriceKlinesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), interval, request.Limit ?? 1000, fromTimestamp ?? request.StartTime, @@ -689,7 +689,7 @@ async Task> IOpenInterestRestClient.GetOpe if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var result = await ExchangeData.GetOpenInterestAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), ct: ct).ConfigureAwait(false); + var result = await ExchangeData.GetOpenInterestAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -713,7 +713,7 @@ async Task>> IFundingRateRestCl // Get data var result = await ExchangeData.GetFundingRatesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), startTime: fromTime ?? request.StartTime, endTime: request.EndTime, limit: 1000, diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs index 9e01d2122..8084fd15e 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs @@ -69,8 +69,10 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden public IBinanceSocketClientCoinFuturesApiShared SharedClient => this; /// - public override string FormatSymbol(string baseAsset, string quoteAsset, ApiType? futuresType = null) - => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + "_PERP"; + public override string FormatSymbol(string baseAsset, string quoteAsset, DateTime? deliverTime, ApiType? futuresType = null) + { + return baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + (deliverTime == null ? "_PERP" : "_" + deliverTime.Value.ToString("yyMMdd")); + } #region methods diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs index 223b21184..553c7aec1 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs @@ -29,7 +29,7 @@ async Task> ITickerSocketClient.SubscribeToTi if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)); + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)); var result = await SubscribeToTickerUpdatesAsync(symbol, update => handler(update.AsExchangeEvent(Exchange, new SharedSpotTicker(symbol, update.Data.LastPrice, update.Data.LowPrice, update.Data.HighPrice, update.Data.Volume))), ct: ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -68,7 +68,7 @@ async Task> ITradeSocketClient.SubscribeToTra if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)); + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)); var result = await SubscribeToAggregatedTradeUpdatesAsync(symbol, update => handler(update.AsExchangeEvent>(Exchange, new[] { new SharedTrade(update.Data.Price, update.Data.Quantity, update.Data.TradeTime) })), ct:ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -85,7 +85,7 @@ async Task> IBookTickerSocketClient.Subscribe if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)); + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)); var result = await SubscribeToBookTickerUpdatesAsync(symbol, update => handler(update.AsExchangeEvent(Exchange, new SharedBookTicker(update.Data.BestAskPrice, update.Data.BestAskQuantity, update.Data.BestBidPrice, update.Data.BestBidQuantity))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -105,7 +105,7 @@ async Task> IKlineSocketClient.SubscribeToKli if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)); + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)); var result = await SubscribeToKlineUpdatesAsync(symbol, interval, update => handler(update.AsExchangeEvent(Exchange, new SharedKline(update.Data.Data.OpenTime, update.Data.Data.ClosePrice, update.Data.Data.HighPrice, update.Data.Data.LowPrice, update.Data.Data.OpenPrice, update.Data.Data.Volume))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -120,7 +120,7 @@ async Task> IOrderBookSocketClient.SubscribeT if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)); + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)); var result = await SubscribeToPartialOrderBookUpdatesAsync(symbol, request.Limit ?? 20, 100, update => handler(update.AsExchangeEvent(Exchange, new SharedOrderBook(update.Data.Asks, update.Data.Bids))), 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 b37c43326..571a141ce 100644 --- a/Binance.Net/Clients/GeneralApi/BinanceRestClientGeneralApi.cs +++ b/Binance.Net/Clients/GeneralApi/BinanceRestClientGeneralApi.cs @@ -74,7 +74,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(); /// - public override string FormatSymbol(string baseAsset, string quoteAsset, ApiType? futuresType = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); + public override string FormatSymbol(string baseAsset, string quoteAsset, DateTime? deliverDate = null, ApiType? futuresType = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); 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 b5787c33b..74a48dd4c 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApi.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApi.cs @@ -76,7 +76,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(); /// - public override string FormatSymbol(string baseAsset, string quoteAsset, ApiType? futuresType = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); + public override string FormatSymbol(string baseAsset, string quoteAsset, DateTime? deliverTime, ApiType? futuresType = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); #region helpers diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index ca7e98c16..1c839e9ff 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -40,7 +40,7 @@ async Task>> IKlineRestClient.GetKlin // Get data var result = await ExchangeData.GetKlinesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), interval, fromTimestamp ?? request.StartTime, request.EndTime?.AddSeconds(-1), @@ -97,7 +97,7 @@ async Task> ISpotTickerRestClient.GetSpotTic if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var result = await ExchangeData.GetTickerAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), ct).ConfigureAwait(false); + var result = await ExchangeData.GetTickerAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -131,7 +131,7 @@ async Task>> IRecentTradeRestClient.G // Get data var result = await ExchangeData.GetRecentTradesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) @@ -157,7 +157,7 @@ async Task>> ITradeHistoryRestClient. // Get data var result = await ExchangeData.GetAggregatedTradeHistoryAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), startTime: fromId != null ? null : request.StartTime, endTime: fromId != null ? null : request.EndTime, limit: 1000, @@ -184,7 +184,7 @@ async Task> IOrderBookRestClient.GetOrderBook return new ExchangeWebResult(Exchange, validationError); var result = await ExchangeData.GetOrderBookAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) @@ -241,7 +241,7 @@ async Task> ISpotOrderRestClient.PlaceSpotOrderAsync return new ExchangeWebResult(Exchange, validationError); var result = await Trading.PlaceOrderAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), request.Side == SharedOrderSide.Buy ? Enums.OrderSide.Buy : Enums.OrderSide.Sell, request.OrderType == SharedOrderType.Limit ? Enums.SpotOrderType.Limit : request.OrderType == SharedOrderType.Market ? Enums.SpotOrderType.Market: Enums.SpotOrderType.LimitMaker, quantity: request.Quantity, @@ -265,7 +265,7 @@ async Task> ISpotOrderRestClient.GetSpotOrder if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); - var order = await Trading.GetOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), orderId).ConfigureAwait(false); + var order = await Trading.GetOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), orderId).ConfigureAwait(false); if (!order) return order.AsExchangeResult(Exchange, default); @@ -296,7 +296,7 @@ async Task>> ISpotOrderRestClient if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); - var symbol = request.Symbol?.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, ApiType.Spot)); + var symbol = request.Symbol?.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, ApiType.Spot)); var orders = await Trading.GetOpenOrdersAsync(symbol).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); @@ -334,7 +334,7 @@ async Task>> ISpotOrderRestClient fromTimestamp = dateTimeToken.LastTime; // Get data - var orders = await Trading.GetOrdersAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), + var orders = await Trading.GetOrdersAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), startTime: fromTimestamp ?? request.StartTime, endTime: request.EndTime, limit: request.Limit ?? 1000).ConfigureAwait(false); @@ -376,7 +376,7 @@ async Task>> ISpotOrderRestClient if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult>(Exchange, new ArgumentError("Invalid order id")); - var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), orderId: orderId).ConfigureAwait(false); + var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), orderId: orderId).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); @@ -409,7 +409,7 @@ async Task>> ISpotOrderRestClient fromId = long.Parse(fromIdToken.FromToken); // Get data - var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), + var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), startTime: request.StartTime, endTime: request.EndTime, limit: request.Limit ?? 500, @@ -449,7 +449,7 @@ async Task> ISpotOrderRestClient.CancelSpotOrderAsyn if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); - var order = await Trading.CancelOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), orderId).ConfigureAwait(false); + var order = await Trading.CancelOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), orderId).ConfigureAwait(false); if (!order) return order.AsExchangeResult(Exchange, default); diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs index e715956e8..d07d43d08 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs @@ -63,7 +63,7 @@ internal BinanceSocketClientSpotApi(ILogger logger, BinanceSocketOptions options public IBinanceSocketClientSpotApiShared SharedClient => this; /// - public override string FormatSymbol(string baseAsset, string quoteAsset, ApiType? futuresType = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); + public override string FormatSymbol(string baseAsset, string quoteAsset, DateTime? deliverTime, ApiType? futuresType = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); /// protected override AuthenticationProvider CreateAuthenticationProvider(ApiCredentials credentials) diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs index fd1bcc612..4bfedbe78 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs @@ -42,7 +42,7 @@ async Task> ITickerSocketClient.SubscribeToTi if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)); + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)); var result = await ExchangeData.SubscribeToMiniTickerUpdatesAsync(symbol, update => handler(update.AsExchangeEvent(Exchange, new SharedSpotTicker(update.Data.Symbol, update.Data.LastPrice, update.Data.HighPrice, update.Data.LowPrice, update.Data.Volume))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -58,7 +58,7 @@ async Task> ITradeSocketClient.SubscribeToTra if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)); + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)); var result = await ExchangeData.SubscribeToTradeUpdatesAsync(symbol, update => handler(update.AsExchangeEvent>(Exchange, new[] { new SharedTrade(update.Data.Price, update.Data.Quantity, update.Data.TradeTime) })), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -75,7 +75,7 @@ async Task> IBookTickerSocketClient.Subscribe if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)); + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)); var result = await ExchangeData.SubscribeToBookTickerUpdatesAsync(symbol, update => handler(update.AsExchangeEvent(Exchange, new SharedBookTicker(update.Data.BestAskPrice, update.Data.BestAskQuantity, update.Data.BestBidPrice, update.Data.BestBidQuantity))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -161,7 +161,7 @@ async Task> IKlineSocketClient.SubscribeToKli if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)); + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)); var result = await ExchangeData.SubscribeToKlineUpdatesAsync(symbol, interval, update => handler(update.AsExchangeEvent(Exchange, new SharedKline(update.Data.Data.OpenTime, update.Data.Data.ClosePrice, update.Data.Data.HighPrice, update.Data.Data.LowPrice, update.Data.Data.OpenPrice, update.Data.Data.Volume))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -176,7 +176,7 @@ async Task> IOrderBookSocketClient.SubscribeT if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)); + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)); var result = await ExchangeData.SubscribeToPartialOrderBookUpdatesAsync(symbol, request.Limit ?? 20, 100, update => handler(update.AsExchangeEvent(Exchange, new SharedOrderBook(update.Data.Asks, update.Data.Bids))), 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 67a855443..c464a0130 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs @@ -49,9 +49,9 @@ internal partial class BinanceRestClientUsdFuturesApi : RestApiClient, IBinanceR public event Action? OnOrderCanceled; /// - public override string FormatSymbol(string baseAsset, string quoteAsset, ApiType? futuresType = null) + public override string FormatSymbol(string baseAsset, string quoteAsset, DateTime? deliverTime, ApiType? futuresType = null) { - return baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); + return baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + (deliverTime == null ? string.Empty : "_" + deliverTime.Value.ToString("yyMMdd")); } #region constructor/destructor diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs index f1e59232a..58fbc4794 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -45,7 +45,7 @@ async Task>> IKlineRestClient.GetKlin fromTimestamp = dateTimeToken.LastTime; var result = await ExchangeData.GetKlinesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), interval, fromTimestamp ?? request.StartTime, request.EndTime, @@ -92,7 +92,7 @@ async Task>> IMarkPriceKlineRestC fromTimestamp = dateTimeToken.LastTime; var result = await ExchangeData.GetMarkPriceKlinesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate)), interval, request.Limit ?? 1000, fromTimestamp ?? request.StartTime, @@ -152,8 +152,8 @@ async Task> IFuturesTickerRestClient.GetF if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var resultTicker = ExchangeData.GetTickerAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), ct); - var resultMarkPrice = ExchangeData.GetMarkPriceAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), ct); + var resultTicker = ExchangeData.GetTickerAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), ct); + var resultMarkPrice = ExchangeData.GetMarkPriceAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), ct); await Task.WhenAll(resultTicker, resultMarkPrice).ConfigureAwait(false); if (!resultTicker.Result) @@ -210,7 +210,7 @@ async Task>> IRecentTradeRestClient.G return new ExchangeWebResult>(Exchange, validationError); var result = await ExchangeData.GetRecentTradesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), // Don't pass api type; need only the pair + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate)), // Don't pass api type; need only the pair limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) @@ -248,7 +248,7 @@ async Task> IFuturesOrderRestClient.PlaceFuturesOrde return new ExchangeWebResult(Exchange, validationError); var result = await Trading.PlaceOrderAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), request.Side == SharedOrderSide.Buy ? Enums.OrderSide.Buy : Enums.OrderSide.Sell, request.OrderType == SharedOrderType.Limit ? Enums.FuturesOrderType.Limit : Enums.FuturesOrderType.Market, quantity: request.Quantity, @@ -274,7 +274,7 @@ async Task> IFuturesOrderRestClient.GetFut if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); - var order = await Trading.GetOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), orderId).ConfigureAwait(false); + var order = await Trading.GetOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), orderId).ConfigureAwait(false); if (!order) return order.AsExchangeResult(Exchange, default); @@ -306,7 +306,7 @@ async Task>> IFuturesOrderRest if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); - var symbol = request.Symbol?.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)); + var symbol = request.Symbol?.GetSymbol((baseAsset, quoteAsset, deliveryDate) => FormatSymbol(baseAsset, quoteAsset, deliveryDate, request.ApiType)); var orders = await Trading.GetOpenOrdersAsync(symbol).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); @@ -345,7 +345,7 @@ async Task>> IFuturesOrderRest fromTimestamp = dateTimeToken.LastTime; // Get data - var orders = await Trading.GetOrdersAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), + var orders = await Trading.GetOrdersAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), startTime: fromTimestamp ?? request.StartTime, endTime: request.EndTime, limit: request.Limit ?? 1000).ConfigureAwait(false); @@ -388,7 +388,7 @@ async Task>> IFuturesOrderRestCli if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult>(Exchange, new ArgumentError("Invalid order id")); - var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), orderId: orderId).ConfigureAwait(false); + var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), orderId: orderId).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); @@ -421,7 +421,7 @@ async Task>> IFuturesOrderRestCli fromId = long.Parse(fromIdToken.FromToken); // Get data - var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), + var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), startTime: request.StartTime, endTime: request.EndTime, limit: request.Limit ?? 500, @@ -461,7 +461,7 @@ async Task> IFuturesOrderRestClient.CancelFuturesOrd if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); - var order = await Trading.CancelOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)), orderId).ConfigureAwait(false); + var order = await Trading.CancelOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), orderId).ConfigureAwait(false); if (!order) return order.AsExchangeResult(Exchange, default); @@ -475,7 +475,7 @@ async Task>> IFuturesOrderRestClie if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); - var result = await Account.GetPositionInformationAsync(symbol: request.Symbol?.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), ct: ct).ConfigureAwait(false); + var result = await Account.GetPositionInformationAsync(symbol: request.Symbol?.GetSymbol((baseAsset, quoteAsset, deliveryDate) => FormatSymbol(baseAsset, quoteAsset, deliveryDate)), ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult>(Exchange, default); @@ -497,7 +497,7 @@ async Task> IFuturesOrderRestClient.ClosePositionAsy return new ExchangeWebResult(Exchange, validationError); var result = await Trading.PlaceOrderAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliveryDate) => FormatSymbol(baseAsset, quoteAsset, deliveryDate)), request.PositionSide == SharedPositionSide.Long ? OrderSide.Sell : OrderSide.Buy, FuturesOrderType.Market, request.Quantity, @@ -558,7 +558,7 @@ async Task> ILeverageRestClient.GetLeverageAsy if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var result = await Account.GetPositionInformationAsync(symbol: request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), ct: ct).ConfigureAwait(false); + var result = await Account.GetPositionInformationAsync(symbol: request.Symbol.GetSymbol((baseAsset, quoteAsset, deliveryDate) => FormatSymbol(baseAsset, quoteAsset, deliveryDate )), ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -583,7 +583,7 @@ async Task> ILeverageRestClient.SetLeverageAsy if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var result = await Account.ChangeInitialLeverageAsync(symbol: request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), (int)request.Leverage, ct: ct).ConfigureAwait(false); + var result = await Account.ChangeInitialLeverageAsync(symbol: request.Symbol.GetSymbol((baseAsset, quoteAsset, deliveryDate) => FormatSymbol(baseAsset, quoteAsset, deliveryDate)), (int)request.Leverage, ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -600,7 +600,7 @@ async Task> IOrderBookRestClient.GetOrderBook return new ExchangeWebResult(Exchange, validationError); var result = await ExchangeData.GetOrderBookAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate)), limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) @@ -626,7 +626,7 @@ async Task>> ITradeHistoryRestClient. // Get data var result = await ExchangeData.GetAggregatedTradeHistoryAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliveryDate) => FormatSymbol(baseAsset, quoteAsset, deliveryDate)), startTime: fromId != null ? null : request.StartTime, endTime: fromId != null ? null : request.EndTime, limit: 1000, @@ -667,7 +667,7 @@ async Task>> IIndexPriceKlineRest fromTimestamp = dateTimeToken.LastTime; var result = await ExchangeData.GetMarkPriceKlinesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliveryDate) => FormatSymbol(baseAsset, quoteAsset, deliveryDate)), interval, request.Limit ?? 1000, fromTimestamp ?? request.StartTime, @@ -700,7 +700,7 @@ async Task> IOpenInterestRestClient.GetOpe if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var result = await ExchangeData.GetOpenInterestAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), ct: ct).ConfigureAwait(false); + var result = await ExchangeData.GetOpenInterestAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliveryDate) => FormatSymbol(baseAsset, quoteAsset, deliveryDate)), ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -724,7 +724,7 @@ async Task>> IFundingRateRestCl // Get data var result = await ExchangeData.GetFundingRatesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliveryDate) => FormatSymbol(baseAsset, quoteAsset, deliveryDate)), startTime: fromTime ?? request.StartTime, endTime: request.EndTime, limit: 1000, diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs index 434194d38..2d28becc6 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs @@ -66,7 +66,10 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden => new BinanceAuthenticationProvider(credentials); /// - public override string FormatSymbol(string baseAsset, string quoteAsset, ApiType? futuresType = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); + public override string FormatSymbol(string baseAsset, string quoteAsset, DateTime? deliverTime, ApiType? futuresType = null) + { + return baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + (deliverTime == null ? string.Empty: "_" + deliverTime.Value.ToString("yyMMdd")); + } 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 f19d2868f..ac47b7599 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs @@ -29,7 +29,7 @@ async Task> ITickerSocketClient.SubscribeToTi if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)); + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)); var result = await SubscribeToTickerUpdatesAsync(symbol, update => handler(update.AsExchangeEvent(Exchange, new SharedSpotTicker(symbol, update.Data.LastPrice, update.Data.LowPrice, update.Data.HighPrice, update.Data.Volume))), ct: ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -68,7 +68,7 @@ async Task> ITradeSocketClient.SubscribeToTra if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)); + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)); var result = await SubscribeToAggregatedTradeUpdatesAsync(symbol, update => handler(update.AsExchangeEvent>(Exchange, new[] { new SharedTrade(update.Data.Price, update.Data.Quantity, update.Data.TradeTime) })), ct:ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -85,7 +85,7 @@ async Task> IBookTickerSocketClient.Subscribe if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)); + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)); var result = await SubscribeToBookTickerUpdatesAsync(symbol, update => handler(update.AsExchangeEvent(Exchange, new SharedBookTicker(update.Data.BestAskPrice, update.Data.BestAskQuantity, update.Data.BestBidPrice, update.Data.BestBidQuantity))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -179,7 +179,7 @@ async Task> IKlineSocketClient.SubscribeToKli if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)); + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)); var result = await SubscribeToKlineUpdatesAsync(symbol, interval, update => handler(update.AsExchangeEvent(Exchange, new SharedKline(update.Data.Data.OpenTime, update.Data.Data.ClosePrice, update.Data.Data.HighPrice, update.Data.Data.LowPrice, update.Data.Data.OpenPrice, update.Data.Data.Volume))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -194,7 +194,7 @@ async Task> IOrderBookSocketClient.SubscribeT if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset) => FormatSymbol(baseAsset, quoteAsset, request.ApiType)); + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)); var result = await SubscribeToPartialOrderBookUpdatesAsync(symbol, request.Limit ?? 20, 100, update => handler(update.AsExchangeEvent(Exchange, new SharedOrderBook(update.Data.Asks, update.Data.Bids))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); From 69c46d285f6a7c3a56368dda23e0f9c4d9755c06 Mon Sep 17 00:00:00 2001 From: Jkorf Date: Tue, 10 Sep 2024 12:49:13 +0200 Subject: [PATCH 31/54] wip --- Binance.Net/Binance.Net.xml | 14 +++---- .../BinanceRestClientCoinFuturesApi.cs | 2 +- .../BinanceRestClientCoinFuturesApiShared.cs | 42 +++++++++---------- .../BinanceSocketClientCoinFuturesApi.cs | 2 +- ...BinanceSocketClientCoinFuturesApiShared.cs | 40 +++++++++++++++--- .../GeneralApi/BinanceRestClientGeneralApi.cs | 2 +- .../SpotApi/BinanceRestClientSpotApi.cs | 2 +- .../SpotApi/BinanceRestClientSpotApiShared.cs | 24 +++++------ .../SpotApi/BinanceSocketClientSpotApi.cs | 2 +- .../BinanceSocketClientSpotApiShared.cs | 10 ++--- .../BinanceRestClientUsdFuturesApi.cs | 2 +- .../BinanceRestClientUsdFuturesApiShared.cs | 42 +++++++++---------- .../BinanceSocketClientUsdFuturesApi.cs | 2 +- .../BinanceSocketClientUsdFuturesApiShared.cs | 35 +++++++++++++--- ...BinanceSocketClientCoinFuturesApiShared.cs | 4 +- ...IBinanceSocketClientUsdFuturesApiShared.cs | 2 + 16 files changed, 143 insertions(+), 84 deletions(-) diff --git a/Binance.Net/Binance.Net.xml b/Binance.Net/Binance.Net.xml index 3766cea5d..598c19554 100644 --- a/Binance.Net/Binance.Net.xml +++ b/Binance.Net/Binance.Net.xml @@ -265,7 +265,7 @@ - + @@ -466,7 +466,7 @@ - + @@ -625,7 +625,7 @@ - + @@ -1130,7 +1130,7 @@ - + @@ -1670,7 +1670,7 @@ - + @@ -1905,7 +1905,7 @@ Event triggered when an order is canceled via this client. Note that this does not trigger when using CancelAllOrdersAsync. Only available for Spot orders - + @@ -2218,7 +2218,7 @@ - + diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs index 29e0fb48b..d54fe6be5 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs @@ -75,7 +75,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(); /// - public override string FormatSymbol(string baseAsset, string quoteAsset, DateTime? deliverTime, ApiType? futuresType = null) + public override string FormatSymbol(string baseAsset, string quoteAsset, ApiType apiType, DateTime? deliverTime = null) { return baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + (deliverTime == null ? "_PERP" : "_" + deliverTime.Value.ToString("yyMMdd")); } diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs index 4fee3670e..e56e49536 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -42,7 +42,7 @@ async Task>> IKlineRestClient.GetKlin fromTimestamp = dateTimeToken.LastTime; var result = await ExchangeData.GetKlinesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), interval, fromTimestamp ?? request.StartTime, request.EndTime, @@ -102,8 +102,8 @@ async Task> IFuturesTickerRestClient.GetF if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var resultTicker = ExchangeData.GetTickersAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), ct: ct); - var resultMarkPrice = ExchangeData.GetMarkPricesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), ct: ct); + var resultTicker = ExchangeData.GetTickersAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), ct: ct); + var resultMarkPrice = ExchangeData.GetMarkPricesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), ct: ct); await Task.WhenAll(resultTicker, resultMarkPrice).ConfigureAwait(false); if (!resultTicker.Result) return resultTicker.Result.AsExchangeResult(Exchange, default); @@ -165,7 +165,7 @@ async Task>> IRecentTradeRestClient.G return new ExchangeWebResult>(Exchange, validationError); var result = await ExchangeData.GetRecentTradesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) @@ -203,7 +203,7 @@ async Task> IFuturesOrderRestClient.PlaceFuturesOrde return new ExchangeWebResult(Exchange, validationError); var result = await Trading.PlaceOrderAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), request.Side == SharedOrderSide.Buy ? Enums.OrderSide.Buy : Enums.OrderSide.Sell, request.OrderType == SharedOrderType.Limit ? Enums.FuturesOrderType.Limit : Enums.FuturesOrderType.Market, quantity: request.Quantity, @@ -228,7 +228,7 @@ async Task> IFuturesOrderRestClient.GetFut if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); - var order = await Trading.GetOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), orderId).ConfigureAwait(false); + var order = await Trading.GetOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), orderId).ConfigureAwait(false); if (!order) return order.AsExchangeResult(Exchange, default); @@ -260,7 +260,7 @@ async Task>> IFuturesOrderRest if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); - var symbol = request.Symbol?.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)); + var symbol = request.Symbol?.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)); var orders = await Trading.GetOpenOrdersAsync(symbol).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); @@ -299,7 +299,7 @@ async Task>> IFuturesOrderRest fromTimestamp = dateTimeToken.LastTime; // Get data - var orders = await Trading.GetOrdersAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), + var orders = await Trading.GetOrdersAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), startTime: fromTimestamp ?? request.StartTime, endTime: request.EndTime, limit: request.Limit ?? 1000).ConfigureAwait(false); @@ -342,7 +342,7 @@ async Task>> IFuturesOrderRestCli if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult>(Exchange, new ArgumentError("Invalid order id")); - var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), orderId: orderId).ConfigureAwait(false); + var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), orderId: orderId).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); @@ -375,7 +375,7 @@ async Task>> IFuturesOrderRestCli fromId = long.Parse(fromIdToken.FromToken); // Get data - var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), + var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), startTime: request.StartTime, endTime: request.EndTime, limit: request.Limit ?? 500, @@ -415,7 +415,7 @@ async Task> IFuturesOrderRestClient.CancelFuturesOrd if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); - var order = await Trading.CancelOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), orderId).ConfigureAwait(false); + var order = await Trading.CancelOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), orderId).ConfigureAwait(false); if (!order) return order.AsExchangeResult(Exchange, default); @@ -429,7 +429,7 @@ async Task>> IFuturesOrderRestClie if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); - var result = await Account.GetPositionInformationAsync(pair: request.Symbol?.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate)), ct: ct).ConfigureAwait(false); + var result = await Account.GetPositionInformationAsync(pair: request.Symbol?.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult>(Exchange, default); @@ -451,7 +451,7 @@ async Task> IFuturesOrderRestClient.ClosePositionAsy return new ExchangeWebResult(Exchange, validationError); var result = await Trading.PlaceOrderAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), request.PositionSide == SharedPositionSide.Long ? OrderSide.Sell : OrderSide.Buy, FuturesOrderType.Market, request.Quantity, @@ -500,7 +500,7 @@ async Task> ILeverageRestClient.GetLeverageAsy if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var result = await Account.GetPositionInformationAsync(pair: request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate)), ct: ct).ConfigureAwait(false); + var result = await Account.GetPositionInformationAsync(pair: request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -525,7 +525,7 @@ async Task> ILeverageRestClient.SetLeverageAsy if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var result = await Account.ChangeInitialLeverageAsync(symbol: request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), (int)request.Leverage ,ct: ct).ConfigureAwait(false); + var result = await Account.ChangeInitialLeverageAsync(symbol: request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), (int)request.Leverage ,ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -556,7 +556,7 @@ async Task>> IMarkPriceKlineRestC fromTimestamp = dateTimeToken.LastTime; var result = await ExchangeData.GetMarkPriceKlinesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), interval, request.Limit ?? 1000, fromTimestamp ?? request.StartTime, @@ -589,7 +589,7 @@ async Task> IOrderBookRestClient.GetOrderBook return new ExchangeWebResult(Exchange, validationError); var result = await ExchangeData.GetOrderBookAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) @@ -615,7 +615,7 @@ async Task>> ITradeHistoryRestClient. // Get data var result = await ExchangeData.GetAggregatedTradeHistoryAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), startTime: fromId != null ? null : request.StartTime, endTime: fromId != null ? null : request.EndTime, limit: 1000, @@ -656,7 +656,7 @@ async Task>> IIndexPriceKlineRest fromTimestamp = dateTimeToken.LastTime; var result = await ExchangeData.GetMarkPriceKlinesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), interval, request.Limit ?? 1000, fromTimestamp ?? request.StartTime, @@ -689,7 +689,7 @@ async Task> IOpenInterestRestClient.GetOpe if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var result = await ExchangeData.GetOpenInterestAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), ct: ct).ConfigureAwait(false); + var result = await ExchangeData.GetOpenInterestAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -713,7 +713,7 @@ async Task>> IFundingRateRestCl // Get data var result = await ExchangeData.GetFundingRatesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), startTime: fromTime ?? request.StartTime, endTime: request.EndTime, limit: 1000, diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs index 8084fd15e..e42ddf547 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs @@ -69,7 +69,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden public IBinanceSocketClientCoinFuturesApiShared SharedClient => this; /// - public override string FormatSymbol(string baseAsset, string quoteAsset, DateTime? deliverTime, ApiType? futuresType = null) + public override string FormatSymbol(string baseAsset, string quoteAsset, ApiType apiType, DateTime? deliverTime = null) { return baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + (deliverTime == null ? "_PERP" : "_" + deliverTime.Value.ToString("yyMMdd")); } diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs index 553c7aec1..e8b0cdba0 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs @@ -3,6 +3,7 @@ using CryptoExchange.Net.Objects.Sockets; using CryptoExchange.Net.SharedApis.Enums; using CryptoExchange.Net.SharedApis.Interfaces.Socket; +using CryptoExchange.Net.SharedApis.Interfaces.Socket.Futures; using CryptoExchange.Net.SharedApis.Models; using CryptoExchange.Net.SharedApis.Models.FilterOptions; using CryptoExchange.Net.SharedApis.Models.Socket; @@ -29,7 +30,7 @@ async Task> ITickerSocketClient.SubscribeToTi if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)); + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)); var result = await SubscribeToTickerUpdatesAsync(symbol, update => handler(update.AsExchangeEvent(Exchange, new SharedSpotTicker(symbol, update.Data.LastPrice, update.Data.LowPrice, update.Data.HighPrice, update.Data.Volume))), ct: ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -68,7 +69,7 @@ async Task> ITradeSocketClient.SubscribeToTra if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)); + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)); var result = await SubscribeToAggregatedTradeUpdatesAsync(symbol, update => handler(update.AsExchangeEvent>(Exchange, new[] { new SharedTrade(update.Data.Price, update.Data.Quantity, update.Data.TradeTime) })), ct:ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -85,7 +86,7 @@ async Task> IBookTickerSocketClient.Subscribe if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)); + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)); var result = await SubscribeToBookTickerUpdatesAsync(symbol, update => handler(update.AsExchangeEvent(Exchange, new SharedBookTicker(update.Data.BestAskPrice, update.Data.BestAskQuantity, update.Data.BestBidPrice, update.Data.BestBidQuantity))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -105,7 +106,7 @@ async Task> IKlineSocketClient.SubscribeToKli if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)); + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)); var result = await SubscribeToKlineUpdatesAsync(symbol, interval, update => handler(update.AsExchangeEvent(Exchange, new SharedKline(update.Data.Data.OpenTime, update.Data.Data.ClosePrice, update.Data.Data.HighPrice, update.Data.Data.LowPrice, update.Data.Data.OpenPrice, update.Data.Data.Volume))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -120,7 +121,7 @@ async Task> IOrderBookSocketClient.SubscribeT if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)); + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)); var result = await SubscribeToPartialOrderBookUpdatesAsync(symbol, request.Limit ?? 20, 100, update => handler(update.AsExchangeEvent(Exchange, new SharedOrderBook(update.Data.Asks, update.Data.Bids))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -152,6 +153,35 @@ async Task> IBalanceSocketClient.SubscribeToB #endregion + #region Position client + SubscriptionOptions IPositionSocketClient.SubscribePositionOptions { get; } = new SubscriptionOptions("SubscribePositionRequest", false) + { + RequiredExchangeParameters = new List + { + new ParameterDescription("ListenKey", typeof(string), "The listenkey for starting the user stream", "123123123") + } + }; + async Task> IPositionSocketClient.SubscribeToPositionUpdatesAsync(ApiType apiType, Action>> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IPositionSocketClient)this).SubscribePositionOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeResult(Exchange, validationError); + + var listenKey = exchangeParameters.GetValue(Exchange, "ListenKey"); + var result = await SubscribeToUserDataUpdatesAsync(listenKey!, + onAccountUpdate: update => handler(update.AsExchangeEvent(Exchange, update.Data.UpdateData.Positions.Select(x => new SharedPosition(x.Symbol, x.Quantity, update.Data.EventTime) + { + AverageEntryPrice = x.EntryPrice, + PositionSide = x.PositionSide == Enums.PositionSide.Both ? (x.Quantity > 0 ? SharedPositionSide.Long : SharedPositionSide.Short) : x.PositionSide == Enums.PositionSide.Short ? SharedPositionSide.Short : SharedPositionSide.Long, + UnrealizedPnl = x.UnrealizedPnl + }))), + ct: ct).ConfigureAwait(false); + + return new ExchangeResult(Exchange, result); + } + + #endregion + #region Futures Order client SubscriptionOptions IFuturesOrderSocketClient.SubscribeFuturesOrderOptions { get; } = new SubscriptionOptions("SubscribeFuturesOrderRequest", false) diff --git a/Binance.Net/Clients/GeneralApi/BinanceRestClientGeneralApi.cs b/Binance.Net/Clients/GeneralApi/BinanceRestClientGeneralApi.cs index 571a141ce..435a2942f 100644 --- a/Binance.Net/Clients/GeneralApi/BinanceRestClientGeneralApi.cs +++ b/Binance.Net/Clients/GeneralApi/BinanceRestClientGeneralApi.cs @@ -74,7 +74,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(); /// - public override string FormatSymbol(string baseAsset, string quoteAsset, DateTime? deliverDate = null, ApiType? futuresType = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); + public override string FormatSymbol(string baseAsset, string quoteAsset, ApiType apiType, DateTime? deliverTime = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); 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 74a48dd4c..bdf368c8e 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApi.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApi.cs @@ -76,7 +76,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(); /// - public override string FormatSymbol(string baseAsset, string quoteAsset, DateTime? deliverTime, ApiType? futuresType = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); + public override string FormatSymbol(string baseAsset, string quoteAsset, ApiType apiType, DateTime? deliverTime) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); #region helpers diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index 1c839e9ff..ce86920d6 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -40,7 +40,7 @@ async Task>> IKlineRestClient.GetKlin // Get data var result = await ExchangeData.GetKlinesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), interval, fromTimestamp ?? request.StartTime, request.EndTime?.AddSeconds(-1), @@ -97,7 +97,7 @@ async Task> ISpotTickerRestClient.GetSpotTic if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var result = await ExchangeData.GetTickerAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), ct).ConfigureAwait(false); + var result = await ExchangeData.GetTickerAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -131,7 +131,7 @@ async Task>> IRecentTradeRestClient.G // Get data var result = await ExchangeData.GetRecentTradesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) @@ -157,7 +157,7 @@ async Task>> ITradeHistoryRestClient. // Get data var result = await ExchangeData.GetAggregatedTradeHistoryAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), startTime: fromId != null ? null : request.StartTime, endTime: fromId != null ? null : request.EndTime, limit: 1000, @@ -184,7 +184,7 @@ async Task> IOrderBookRestClient.GetOrderBook return new ExchangeWebResult(Exchange, validationError); var result = await ExchangeData.GetOrderBookAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) @@ -241,7 +241,7 @@ async Task> ISpotOrderRestClient.PlaceSpotOrderAsync return new ExchangeWebResult(Exchange, validationError); var result = await Trading.PlaceOrderAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), request.Side == SharedOrderSide.Buy ? Enums.OrderSide.Buy : Enums.OrderSide.Sell, request.OrderType == SharedOrderType.Limit ? Enums.SpotOrderType.Limit : request.OrderType == SharedOrderType.Market ? Enums.SpotOrderType.Market: Enums.SpotOrderType.LimitMaker, quantity: request.Quantity, @@ -265,7 +265,7 @@ async Task> ISpotOrderRestClient.GetSpotOrder if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); - var order = await Trading.GetOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), orderId).ConfigureAwait(false); + var order = await Trading.GetOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), orderId).ConfigureAwait(false); if (!order) return order.AsExchangeResult(Exchange, default); @@ -296,7 +296,7 @@ async Task>> ISpotOrderRestClient if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); - var symbol = request.Symbol?.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, ApiType.Spot)); + var symbol = request.Symbol?.GetSymbol((baseAsset, quoteAsset, deliveryDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliveryDate)); var orders = await Trading.GetOpenOrdersAsync(symbol).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); @@ -334,7 +334,7 @@ async Task>> ISpotOrderRestClient fromTimestamp = dateTimeToken.LastTime; // Get data - var orders = await Trading.GetOrdersAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), + var orders = await Trading.GetOrdersAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), startTime: fromTimestamp ?? request.StartTime, endTime: request.EndTime, limit: request.Limit ?? 1000).ConfigureAwait(false); @@ -376,7 +376,7 @@ async Task>> ISpotOrderRestClient if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult>(Exchange, new ArgumentError("Invalid order id")); - var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), orderId: orderId).ConfigureAwait(false); + var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), orderId: orderId).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); @@ -409,7 +409,7 @@ async Task>> ISpotOrderRestClient fromId = long.Parse(fromIdToken.FromToken); // Get data - var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), + var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), startTime: request.StartTime, endTime: request.EndTime, limit: request.Limit ?? 500, @@ -449,7 +449,7 @@ async Task> ISpotOrderRestClient.CancelSpotOrderAsyn if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); - var order = await Trading.CancelOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), orderId).ConfigureAwait(false); + var order = await Trading.CancelOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), orderId).ConfigureAwait(false); if (!order) return order.AsExchangeResult(Exchange, default); diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs index d07d43d08..7867e2f81 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs @@ -63,7 +63,7 @@ internal BinanceSocketClientSpotApi(ILogger logger, BinanceSocketOptions options public IBinanceSocketClientSpotApiShared SharedClient => this; /// - public override string FormatSymbol(string baseAsset, string quoteAsset, DateTime? deliverTime, ApiType? futuresType = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); + public override string FormatSymbol(string baseAsset, string quoteAsset, ApiType apiType, DateTime? deliverTime = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); /// protected override AuthenticationProvider CreateAuthenticationProvider(ApiCredentials credentials) diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs index 4bfedbe78..cd8b8d5b5 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs @@ -42,7 +42,7 @@ async Task> ITickerSocketClient.SubscribeToTi if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)); + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)); var result = await ExchangeData.SubscribeToMiniTickerUpdatesAsync(symbol, update => handler(update.AsExchangeEvent(Exchange, new SharedSpotTicker(update.Data.Symbol, update.Data.LastPrice, update.Data.HighPrice, update.Data.LowPrice, update.Data.Volume))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -58,7 +58,7 @@ async Task> ITradeSocketClient.SubscribeToTra if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)); + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)); var result = await ExchangeData.SubscribeToTradeUpdatesAsync(symbol, update => handler(update.AsExchangeEvent>(Exchange, new[] { new SharedTrade(update.Data.Price, update.Data.Quantity, update.Data.TradeTime) })), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -75,7 +75,7 @@ async Task> IBookTickerSocketClient.Subscribe if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)); + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)); var result = await ExchangeData.SubscribeToBookTickerUpdatesAsync(symbol, update => handler(update.AsExchangeEvent(Exchange, new SharedBookTicker(update.Data.BestAskPrice, update.Data.BestAskQuantity, update.Data.BestBidPrice, update.Data.BestBidQuantity))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -161,7 +161,7 @@ async Task> IKlineSocketClient.SubscribeToKli if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)); + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)); var result = await ExchangeData.SubscribeToKlineUpdatesAsync(symbol, interval, update => handler(update.AsExchangeEvent(Exchange, new SharedKline(update.Data.Data.OpenTime, update.Data.Data.ClosePrice, update.Data.Data.HighPrice, update.Data.Data.LowPrice, update.Data.Data.OpenPrice, update.Data.Data.Volume))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -176,7 +176,7 @@ async Task> IOrderBookSocketClient.SubscribeT if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)); + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)); var result = await ExchangeData.SubscribeToPartialOrderBookUpdatesAsync(symbol, request.Limit ?? 20, 100, update => handler(update.AsExchangeEvent(Exchange, new SharedOrderBook(update.Data.Asks, update.Data.Bids))), 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 c464a0130..474f70032 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs @@ -49,7 +49,7 @@ internal partial class BinanceRestClientUsdFuturesApi : RestApiClient, IBinanceR public event Action? OnOrderCanceled; /// - public override string FormatSymbol(string baseAsset, string quoteAsset, DateTime? deliverTime, ApiType? futuresType = null) + public override string FormatSymbol(string baseAsset, string quoteAsset, ApiType apiType, DateTime? deliverTime = null) { return baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + (deliverTime == null ? string.Empty : "_" + deliverTime.Value.ToString("yyMMdd")); } diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs index 58fbc4794..0064b5657 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -45,7 +45,7 @@ async Task>> IKlineRestClient.GetKlin fromTimestamp = dateTimeToken.LastTime; var result = await ExchangeData.GetKlinesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), interval, fromTimestamp ?? request.StartTime, request.EndTime, @@ -92,7 +92,7 @@ async Task>> IMarkPriceKlineRestC fromTimestamp = dateTimeToken.LastTime; var result = await ExchangeData.GetMarkPriceKlinesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), interval, request.Limit ?? 1000, fromTimestamp ?? request.StartTime, @@ -152,8 +152,8 @@ async Task> IFuturesTickerRestClient.GetF if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var resultTicker = ExchangeData.GetTickerAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), ct); - var resultMarkPrice = ExchangeData.GetMarkPriceAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), ct); + var resultTicker = ExchangeData.GetTickerAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), ct); + var resultMarkPrice = ExchangeData.GetMarkPriceAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), ct); await Task.WhenAll(resultTicker, resultMarkPrice).ConfigureAwait(false); if (!resultTicker.Result) @@ -210,7 +210,7 @@ async Task>> IRecentTradeRestClient.G return new ExchangeWebResult>(Exchange, validationError); var result = await ExchangeData.GetRecentTradesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate)), // Don't pass api type; need only the pair + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), // Don't pass api type; need only the pair limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) @@ -248,7 +248,7 @@ async Task> IFuturesOrderRestClient.PlaceFuturesOrde return new ExchangeWebResult(Exchange, validationError); var result = await Trading.PlaceOrderAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), request.Side == SharedOrderSide.Buy ? Enums.OrderSide.Buy : Enums.OrderSide.Sell, request.OrderType == SharedOrderType.Limit ? Enums.FuturesOrderType.Limit : Enums.FuturesOrderType.Market, quantity: request.Quantity, @@ -274,7 +274,7 @@ async Task> IFuturesOrderRestClient.GetFut if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); - var order = await Trading.GetOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), orderId).ConfigureAwait(false); + var order = await Trading.GetOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), orderId).ConfigureAwait(false); if (!order) return order.AsExchangeResult(Exchange, default); @@ -306,7 +306,7 @@ async Task>> IFuturesOrderRest if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); - var symbol = request.Symbol?.GetSymbol((baseAsset, quoteAsset, deliveryDate) => FormatSymbol(baseAsset, quoteAsset, deliveryDate, request.ApiType)); + var symbol = request.Symbol?.GetSymbol((baseAsset, quoteAsset, deliveryDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliveryDate)); var orders = await Trading.GetOpenOrdersAsync(symbol).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); @@ -345,7 +345,7 @@ async Task>> IFuturesOrderRest fromTimestamp = dateTimeToken.LastTime; // Get data - var orders = await Trading.GetOrdersAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), + var orders = await Trading.GetOrdersAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), startTime: fromTimestamp ?? request.StartTime, endTime: request.EndTime, limit: request.Limit ?? 1000).ConfigureAwait(false); @@ -388,7 +388,7 @@ async Task>> IFuturesOrderRestCli if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult>(Exchange, new ArgumentError("Invalid order id")); - var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), orderId: orderId).ConfigureAwait(false); + var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), orderId: orderId).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); @@ -421,7 +421,7 @@ async Task>> IFuturesOrderRestCli fromId = long.Parse(fromIdToken.FromToken); // Get data - var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), + var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), startTime: request.StartTime, endTime: request.EndTime, limit: request.Limit ?? 500, @@ -461,7 +461,7 @@ async Task> IFuturesOrderRestClient.CancelFuturesOrd if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); - var order = await Trading.CancelOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)), orderId).ConfigureAwait(false); + var order = await Trading.CancelOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), orderId).ConfigureAwait(false); if (!order) return order.AsExchangeResult(Exchange, default); @@ -475,7 +475,7 @@ async Task>> IFuturesOrderRestClie if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); - var result = await Account.GetPositionInformationAsync(symbol: request.Symbol?.GetSymbol((baseAsset, quoteAsset, deliveryDate) => FormatSymbol(baseAsset, quoteAsset, deliveryDate)), ct: ct).ConfigureAwait(false); + var result = await Account.GetPositionInformationAsync(symbol: request.Symbol?.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult>(Exchange, default); @@ -497,7 +497,7 @@ async Task> IFuturesOrderRestClient.ClosePositionAsy return new ExchangeWebResult(Exchange, validationError); var result = await Trading.PlaceOrderAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliveryDate) => FormatSymbol(baseAsset, quoteAsset, deliveryDate)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), request.PositionSide == SharedPositionSide.Long ? OrderSide.Sell : OrderSide.Buy, FuturesOrderType.Market, request.Quantity, @@ -558,7 +558,7 @@ async Task> ILeverageRestClient.GetLeverageAsy if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var result = await Account.GetPositionInformationAsync(symbol: request.Symbol.GetSymbol((baseAsset, quoteAsset, deliveryDate) => FormatSymbol(baseAsset, quoteAsset, deliveryDate )), ct: ct).ConfigureAwait(false); + var result = await Account.GetPositionInformationAsync(symbol: request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -583,7 +583,7 @@ async Task> ILeverageRestClient.SetLeverageAsy if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var result = await Account.ChangeInitialLeverageAsync(symbol: request.Symbol.GetSymbol((baseAsset, quoteAsset, deliveryDate) => FormatSymbol(baseAsset, quoteAsset, deliveryDate)), (int)request.Leverage, ct: ct).ConfigureAwait(false); + var result = await Account.ChangeInitialLeverageAsync(symbol: request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), (int)request.Leverage, ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -600,7 +600,7 @@ async Task> IOrderBookRestClient.GetOrderBook return new ExchangeWebResult(Exchange, validationError); var result = await ExchangeData.GetOrderBookAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) @@ -626,7 +626,7 @@ async Task>> ITradeHistoryRestClient. // Get data var result = await ExchangeData.GetAggregatedTradeHistoryAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliveryDate) => FormatSymbol(baseAsset, quoteAsset, deliveryDate)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), startTime: fromId != null ? null : request.StartTime, endTime: fromId != null ? null : request.EndTime, limit: 1000, @@ -667,7 +667,7 @@ async Task>> IIndexPriceKlineRest fromTimestamp = dateTimeToken.LastTime; var result = await ExchangeData.GetMarkPriceKlinesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliveryDate) => FormatSymbol(baseAsset, quoteAsset, deliveryDate)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), interval, request.Limit ?? 1000, fromTimestamp ?? request.StartTime, @@ -700,7 +700,7 @@ async Task> IOpenInterestRestClient.GetOpe if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var result = await ExchangeData.GetOpenInterestAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliveryDate) => FormatSymbol(baseAsset, quoteAsset, deliveryDate)), ct: ct).ConfigureAwait(false); + var result = await ExchangeData.GetOpenInterestAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -724,7 +724,7 @@ async Task>> IFundingRateRestCl // Get data var result = await ExchangeData.GetFundingRatesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliveryDate) => FormatSymbol(baseAsset, quoteAsset, deliveryDate)), + request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), startTime: fromTime ?? request.StartTime, endTime: request.EndTime, limit: 1000, diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs index 2d28becc6..b60fd6d8a 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs @@ -66,7 +66,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden => new BinanceAuthenticationProvider(credentials); /// - public override string FormatSymbol(string baseAsset, string quoteAsset, DateTime? deliverTime, ApiType? futuresType = null) + public override string FormatSymbol(string baseAsset, string quoteAsset, ApiType apiType, DateTime? deliverTime = null) { return baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + (deliverTime == null ? string.Empty: "_" + deliverTime.Value.ToString("yyMMdd")); } diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs index ac47b7599..2c9a03d82 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs @@ -3,6 +3,7 @@ using CryptoExchange.Net.Objects.Sockets; using CryptoExchange.Net.SharedApis.Enums; using CryptoExchange.Net.SharedApis.Interfaces.Socket; +using CryptoExchange.Net.SharedApis.Interfaces.Socket.Futures; using CryptoExchange.Net.SharedApis.Models; using CryptoExchange.Net.SharedApis.Models.FilterOptions; using CryptoExchange.Net.SharedApis.Models.Socket; @@ -29,7 +30,7 @@ async Task> ITickerSocketClient.SubscribeToTi if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)); + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)); var result = await SubscribeToTickerUpdatesAsync(symbol, update => handler(update.AsExchangeEvent(Exchange, new SharedSpotTicker(symbol, update.Data.LastPrice, update.Data.LowPrice, update.Data.HighPrice, update.Data.Volume))), ct: ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -68,7 +69,7 @@ async Task> ITradeSocketClient.SubscribeToTra if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)); + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)); var result = await SubscribeToAggregatedTradeUpdatesAsync(symbol, update => handler(update.AsExchangeEvent>(Exchange, new[] { new SharedTrade(update.Data.Price, update.Data.Quantity, update.Data.TradeTime) })), ct:ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -85,7 +86,7 @@ async Task> IBookTickerSocketClient.Subscribe if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)); + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)); var result = await SubscribeToBookTickerUpdatesAsync(symbol, update => handler(update.AsExchangeEvent(Exchange, new SharedBookTicker(update.Data.BestAskPrice, update.Data.BestAskQuantity, update.Data.BestBidPrice, update.Data.BestBidQuantity))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -179,7 +180,7 @@ async Task> IKlineSocketClient.SubscribeToKli if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)); + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)); var result = await SubscribeToKlineUpdatesAsync(symbol, interval, update => handler(update.AsExchangeEvent(Exchange, new SharedKline(update.Data.Data.OpenTime, update.Data.Data.ClosePrice, update.Data.Data.HighPrice, update.Data.Data.LowPrice, update.Data.Data.OpenPrice, update.Data.Data.Volume))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -194,11 +195,35 @@ async Task> IOrderBookSocketClient.SubscribeT if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, deliverDate, request.ApiType)); + var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)); var result = await SubscribeToPartialOrderBookUpdatesAsync(symbol, request.Limit ?? 20, 100, update => handler(update.AsExchangeEvent(Exchange, new SharedOrderBook(update.Data.Asks, update.Data.Bids))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); } #endregion + + #region Position client + SubscriptionOptions IPositionSocketClient.SubscribePositionOptions { get; } = new SubscriptionOptions("SubscribePositionRequest", false) + { + RequiredExchangeParameters = new List + { + new ParameterDescription("ListenKey", typeof(string), "The listenkey for starting the user stream", "123123123") + } + }; + async Task> IPositionSocketClient.SubscribeToPositionUpdatesAsync(ApiType apiType, Action>> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IPositionSocketClient)this).SubscribePositionOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeResult(Exchange, validationError); + + var listenKey = exchangeParameters.GetValue(Exchange, "ListenKey"); + var result = await SubscribeToUserDataUpdatesAsync(listenKey!, + onAccountUpdate: update => handler(update.AsExchangeEvent(Exchange, update.Data.UpdateData.Positions.Select(x => new SharedPosition(x.Symbol, x.Quantity, update.Data.EventTime)))), + ct: ct).ConfigureAwait(false); + + return new ExchangeResult(Exchange, result); + } + + #endregion } } diff --git a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceSocketClientCoinFuturesApiShared.cs b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceSocketClientCoinFuturesApiShared.cs index 4f6cf22c1..423e50746 100644 --- a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceSocketClientCoinFuturesApiShared.cs +++ b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceSocketClientCoinFuturesApiShared.cs @@ -1,4 +1,5 @@ using CryptoExchange.Net.SharedApis.Interfaces.Socket; +using CryptoExchange.Net.SharedApis.Interfaces.Socket.Futures; using System; using System.Collections.Generic; using System.Text; @@ -13,7 +14,8 @@ public interface IBinanceSocketClientCoinFuturesApiShared : IOrderBookSocketClient, IKlineSocketClient, IFuturesOrderSocketClient, - IBalanceSocketClient + IBalanceSocketClient, + IPositionSocketClient { } } diff --git a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceSocketClientUsdFuturesApiShared.cs b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceSocketClientUsdFuturesApiShared.cs index 95833abc3..1c4ad4afe 100644 --- a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceSocketClientUsdFuturesApiShared.cs +++ b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceSocketClientUsdFuturesApiShared.cs @@ -1,4 +1,5 @@ using CryptoExchange.Net.SharedApis.Interfaces.Socket; +using CryptoExchange.Net.SharedApis.Interfaces.Socket.Futures; using System; using System.Collections.Generic; using System.Text; @@ -13,6 +14,7 @@ public interface IBinanceSocketClientUsdFuturesApiShared: IOrderBookSocketClient, IKlineSocketClient, IBalanceSocketClient, + IPositionSocketClient, IFuturesOrderSocketClient { } From ea4b8af0d205aa6e37726a84a3bb286142154d31 Mon Sep 17 00:00:00 2001 From: Jkorf Date: Tue, 10 Sep 2024 16:06:31 +0200 Subject: [PATCH 32/54] wip --- .../BinanceRestClientCoinFuturesApiShared.cs | 100 +++++++++--------- ...BinanceSocketClientCoinFuturesApiShared.cs | 34 +++--- .../SpotApi/BinanceRestClientSpotApiShared.cs | 50 ++++----- .../BinanceSocketClientSpotApiShared.cs | 24 ++--- .../BinanceRestClientUsdFuturesApiShared.cs | 100 +++++++++--------- .../BinanceSocketClientUsdFuturesApiShared.cs | 41 ++++--- 6 files changed, 183 insertions(+), 166 deletions(-) diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs index e56e49536..7672e25f0 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -32,7 +32,7 @@ async Task>> IKlineRestClient.GetKlin if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -42,7 +42,7 @@ async Task>> IKlineRestClient.GetKlin fromTimestamp = dateTimeToken.LastTime; var result = await ExchangeData.GetKlinesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), + request.Symbol.GetSymbol(FormatSymbol), interval, fromTimestamp ?? request.StartTime, request.EndTime, @@ -69,7 +69,7 @@ async Task>> IKlineRestClient.GetKlin #region Futures Symbol client EndpointOptions IFuturesSymbolRestClient.GetFuturesSymbolsOptions { get; } = new EndpointOptions("GetFuturesSymbolsRequest", false); - async Task>> IFuturesSymbolRestClient.GetFuturesSymbolsAsync(ApiType apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IFuturesSymbolRestClient.GetFuturesSymbolsAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((IFuturesSymbolRestClient)this).GetFuturesSymbolsOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); if (validationError != null) @@ -79,8 +79,10 @@ async Task>> IFuturesSymbolRe if (!result) return result.AsExchangeResult>(Exchange, default); - var data = result.Data.Symbols.Where(x => apiType == ApiType.PerpetualInverse ? x.ContractType == ContractType.Perpetual : x.ContractType != ContractType.Perpetual); - return result.AsExchangeResult(Exchange, data.Select(s => new SharedFuturesSymbol(s.ContractType == ContractType.Perpetual ? SharedSymbolType.PerpetualInverse : SharedSymbolType.DeliveryInverse, s.BaseAsset, s.QuoteAsset, s.Name, s.Status == SymbolStatus.Trading) + var data = result.Data.Symbols.Where(x => x.ContractType != null); + if (apiType != null) + data = data.Where(x => apiType == ApiType.PerpetualInverse ? x.ContractType == ContractType.Perpetual : (x.ContractType != ContractType.Perpetual && x.ContractType != ContractType.PerpetualDelivering)); + return result.AsExchangeResult>(Exchange, data.Select(s => new SharedFuturesSymbol(s.ContractType == ContractType.Perpetual ? SharedSymbolType.PerpetualInverse : SharedSymbolType.DeliveryInverse, s.BaseAsset, s.QuoteAsset, s.Name, s.Status == SymbolStatus.Trading) { MinTradeQuantity = s.LotSizeFilter?.MinQuantity, MaxTradeQuantity = s.LotSizeFilter?.MaxQuantity, @@ -88,7 +90,7 @@ async Task>> IFuturesSymbolRe PriceStep = s.PriceFilter?.TickSize, ContractSize = 1, DeliveryTime = s.DeliveryDate - })); + }).ToArray()); } #endregion @@ -98,12 +100,12 @@ async Task>> IFuturesSymbolRe EndpointOptions IFuturesTickerRestClient.GetFuturesTickerOptions { get; } = new EndpointOptions(false); async Task> IFuturesTickerRestClient.GetFuturesTickerAsync(GetTickerRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var resultTicker = ExchangeData.GetTickersAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), ct: ct); - var resultMarkPrice = ExchangeData.GetMarkPricesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), ct: ct); + var resultTicker = ExchangeData.GetTickersAsync(request.Symbol.GetSymbol(FormatSymbol), ct: ct); + var resultMarkPrice = ExchangeData.GetMarkPricesAsync(request.Symbol.GetSymbol(FormatSymbol), ct: ct); await Task.WhenAll(resultTicker, resultMarkPrice).ConfigureAwait(false); if (!resultTicker.Result) return resultTicker.Result.AsExchangeResult(Exchange, default); @@ -126,7 +128,7 @@ async Task> IFuturesTickerRestClient.GetF } EndpointOptions IFuturesTickerRestClient.GetFuturesTickersOptions { get; } = new EndpointOptions("GetTickersRequest", false); - async Task>> IFuturesTickerRestClient.GetFuturesTickersAsync(ApiType apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IFuturesTickerRestClient.GetFuturesTickersAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickerOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); if (validationError != null) @@ -160,12 +162,12 @@ async Task>> IFuturesTickerRe GetRecentTradesOptions IRecentTradeRestClient.GetRecentTradesOptions { get; } = new GetRecentTradesOptions(1000, false); async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IRecentTradeRestClient)this).GetRecentTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IRecentTradeRestClient)this).GetRecentTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); var result = await ExchangeData.GetRecentTradesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), + request.Symbol.GetSymbol(FormatSymbol), limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) @@ -198,12 +200,12 @@ async Task>> IRecentTradeRestClient.G async Task> IFuturesOrderRestClient.PlaceFuturesOrderAsync(PlaceFuturesOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).PlaceFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).PlaceFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); var result = await Trading.PlaceOrderAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), + request.Symbol.GetSymbol(FormatSymbol), request.Side == SharedOrderSide.Buy ? Enums.OrderSide.Buy : Enums.OrderSide.Sell, request.OrderType == SharedOrderType.Limit ? Enums.FuturesOrderType.Limit : Enums.FuturesOrderType.Market, quantity: request.Quantity, @@ -221,14 +223,14 @@ async Task> IFuturesOrderRestClient.PlaceFuturesOrde EndpointOptions IFuturesOrderRestClient.GetFuturesOrderOptions { get; } = new EndpointOptions(true); async Task> IFuturesOrderRestClient.GetFuturesOrderAsync(GetOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); - var order = await Trading.GetOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), orderId).ConfigureAwait(false); + var order = await Trading.GetOrderAsync(request.Symbol.GetSymbol(FormatSymbol), orderId).ConfigureAwait(false); if (!order) return order.AsExchangeResult(Exchange, default); @@ -256,11 +258,11 @@ async Task> IFuturesOrderRestClient.GetFut EndpointOptions IFuturesOrderRestClient.GetOpenFuturesOrdersOptions { get; } = new EndpointOptions(true); async Task>> IFuturesOrderRestClient.GetOpenFuturesOrdersAsync(GetOpenOrdersRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetOpenFuturesOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetOpenFuturesOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); - var symbol = request.Symbol?.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)); + var symbol = request.Symbol?.GetSymbol(FormatSymbol); var orders = await Trading.GetOpenOrdersAsync(symbol).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); @@ -289,7 +291,7 @@ async Task>> IFuturesOrderRest PaginatedEndpointOptions IFuturesOrderRestClient.GetClosedFuturesOrdersOptions { get; } = new PaginatedEndpointOptions(true, true); async Task>> IFuturesOrderRestClient.GetClosedFuturesOrdersAsync(GetClosedOrdersRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetClosedFuturesOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetClosedFuturesOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -299,7 +301,7 @@ async Task>> IFuturesOrderRest fromTimestamp = dateTimeToken.LastTime; // Get data - var orders = await Trading.GetOrdersAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), + var orders = await Trading.GetOrdersAsync(request.Symbol.GetSymbol(FormatSymbol), startTime: fromTimestamp ?? request.StartTime, endTime: request.EndTime, limit: request.Limit ?? 1000).ConfigureAwait(false); @@ -335,14 +337,14 @@ async Task>> IFuturesOrderRest EndpointOptions IFuturesOrderRestClient.GetFuturesOrderTradesOptions { get; } = new EndpointOptions(true); async Task>> IFuturesOrderRestClient.GetFuturesOrderTradesAsync(GetOrderTradesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult>(Exchange, new ArgumentError("Invalid order id")); - var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), orderId: orderId).ConfigureAwait(false); + var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol(FormatSymbol), orderId: orderId).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); @@ -365,7 +367,7 @@ async Task>> IFuturesOrderRestCli PaginatedEndpointOptions IFuturesOrderRestClient.GetFuturesUserTradesOptions { get; } = new PaginatedEndpointOptions(true, true); async Task>> IFuturesOrderRestClient.GetFuturesUserTradesAsync(GetUserTradesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetFuturesUserTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetFuturesUserTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -375,7 +377,7 @@ async Task>> IFuturesOrderRestCli fromId = long.Parse(fromIdToken.FromToken); // Get data - var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), + var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol(FormatSymbol), startTime: request.StartTime, endTime: request.EndTime, limit: request.Limit ?? 500, @@ -408,14 +410,14 @@ async Task>> IFuturesOrderRestCli EndpointOptions IFuturesOrderRestClient.CancelFuturesOrderOptions { get; } = new EndpointOptions(true); async Task> IFuturesOrderRestClient.CancelFuturesOrderAsync(CancelOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).CancelFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).CancelFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); - var order = await Trading.CancelOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), orderId).ConfigureAwait(false); + var order = await Trading.CancelOrderAsync(request.Symbol.GetSymbol(FormatSymbol), orderId).ConfigureAwait(false); if (!order) return order.AsExchangeResult(Exchange, default); @@ -425,11 +427,11 @@ async Task> IFuturesOrderRestClient.CancelFuturesOrd EndpointOptions IFuturesOrderRestClient.GetPositionsOptions { get; } = new EndpointOptions(true); async Task>> IFuturesOrderRestClient.GetPositionsAsync(GetPositionsRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetPositionsOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetPositionsOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); - var result = await Account.GetPositionInformationAsync(pair: request.Symbol?.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), ct: ct).ConfigureAwait(false); + var result = await Account.GetPositionInformationAsync(pair: request.Symbol?.GetSymbol(FormatSymbol), ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult>(Exchange, default); @@ -446,12 +448,12 @@ async Task>> IFuturesOrderRestClie EndpointOptions IFuturesOrderRestClient.ClosePositionOptions { get; } = new EndpointOptions(true); async Task> IFuturesOrderRestClient.ClosePositionAsync(ClosePositionRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).ClosePositionOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).ClosePositionOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); var result = await Trading.PlaceOrderAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), + request.Symbol.GetSymbol(FormatSymbol), request.PositionSide == SharedPositionSide.Long ? OrderSide.Sell : OrderSide.Buy, FuturesOrderType.Market, request.Quantity, @@ -496,11 +498,11 @@ private SharedOrderType ParseOrderType(FuturesOrderType type) EndpointOptions ILeverageRestClient.GetLeverageOptions { get; } = new EndpointOptions(true); async Task> ILeverageRestClient.GetLeverageAsync(GetLeverageRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ILeverageRestClient)this).GetLeverageOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((ILeverageRestClient)this).GetLeverageOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var result = await Account.GetPositionInformationAsync(pair: request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), ct: ct).ConfigureAwait(false); + var result = await Account.GetPositionInformationAsync(pair: request.Symbol.GetSymbol(FormatSymbol), ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -521,11 +523,11 @@ async Task> ILeverageRestClient.GetLeverageAsy SetLeverageOptions ILeverageRestClient.SetLeverageOptions { get; } = new SetLeverageOptions(false); async Task> ILeverageRestClient.SetLeverageAsync(SetLeverageRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ILeverageRestClient)this).SetLeverageOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((ILeverageRestClient)this).SetLeverageOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var result = await Account.ChangeInitialLeverageAsync(symbol: request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), (int)request.Leverage ,ct: ct).ConfigureAwait(false); + var result = await Account.ChangeInitialLeverageAsync(symbol: request.Symbol.GetSymbol(FormatSymbol), (int)request.Leverage ,ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -546,7 +548,7 @@ async Task>> IMarkPriceKlineRestC if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IMarkPriceKlineRestClient)this).GetMarkPriceKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IMarkPriceKlineRestClient)this).GetMarkPriceKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -556,7 +558,7 @@ async Task>> IMarkPriceKlineRestC fromTimestamp = dateTimeToken.LastTime; var result = await ExchangeData.GetMarkPriceKlinesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), + request.Symbol.GetSymbol(FormatSymbol), interval, request.Limit ?? 1000, fromTimestamp ?? request.StartTime, @@ -584,12 +586,12 @@ async Task>> IMarkPriceKlineRestC GetOrderBookOptions IOrderBookRestClient.GetOrderBookOptions { get; } = new GetOrderBookOptions(new[] { 5, 10, 20, 50, 100, 500, 1000 }, false); async Task> IOrderBookRestClient.GetOrderBookAsync(GetOrderBookRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); var result = await ExchangeData.GetOrderBookAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), + request.Symbol.GetSymbol(FormatSymbol), limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) @@ -605,7 +607,7 @@ async Task> IOrderBookRestClient.GetOrderBook async Task>> ITradeHistoryRestClient.GetTradeHistoryAsync(GetTradeHistoryRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ITradeHistoryRestClient)this).GetTradeHistoryOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((ITradeHistoryRestClient)this).GetTradeHistoryOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -615,7 +617,7 @@ async Task>> ITradeHistoryRestClient. // Get data var result = await ExchangeData.GetAggregatedTradeHistoryAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), + request.Symbol.GetSymbol(FormatSymbol), startTime: fromId != null ? null : request.StartTime, endTime: fromId != null ? null : request.EndTime, limit: 1000, @@ -646,7 +648,7 @@ async Task>> IIndexPriceKlineRest if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IIndexPriceKlineRestClient)this).GetIndexPriceKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IIndexPriceKlineRestClient)this).GetIndexPriceKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -656,7 +658,7 @@ async Task>> IIndexPriceKlineRest fromTimestamp = dateTimeToken.LastTime; var result = await ExchangeData.GetMarkPriceKlinesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), + request.Symbol.GetSymbol(FormatSymbol), interval, request.Limit ?? 1000, fromTimestamp ?? request.StartTime, @@ -685,11 +687,11 @@ async Task>> IIndexPriceKlineRest EndpointOptions IOpenInterestRestClient.GetOpenInterestOptions { get; } = new EndpointOptions(true); async Task> IOpenInterestRestClient.GetOpenInterestAsync(GetOpenInterestRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IOpenInterestRestClient)this).GetOpenInterestOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IOpenInterestRestClient)this).GetOpenInterestOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var result = await ExchangeData.GetOpenInterestAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), ct: ct).ConfigureAwait(false); + var result = await ExchangeData.GetOpenInterestAsync(request.Symbol.GetSymbol(FormatSymbol), ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -703,7 +705,7 @@ async Task> IOpenInterestRestClient.GetOpe async Task>> IFundingRateRestClient.GetFundingRateHistoryAsync(GetFundingRateHistoryRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFundingRateRestClient)this).GetFundingRateHistoryOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IFundingRateRestClient)this).GetFundingRateHistoryOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -713,7 +715,7 @@ async Task>> IFundingRateRestCl // Get data var result = await ExchangeData.GetFundingRatesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), + request.Symbol.GetSymbol(FormatSymbol), startTime: fromTime ?? request.StartTime, endTime: request.EndTime, limit: 1000, @@ -733,7 +735,7 @@ async Task>> IFundingRateRestCl #region Balance Client EndpointOptions IBalanceRestClient.GetBalancesOptions { get; } = new EndpointOptions("GetBalancesRequest", true); - async Task>> IBalanceRestClient.GetBalancesAsync(ApiType apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IBalanceRestClient.GetBalancesAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((IBalanceRestClient)this).GetBalancesOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); if (validationError != null) @@ -753,7 +755,7 @@ async Task>> IBalanceRestClient.Get GetPositionModeOptions IPositionModeRestClient.GetPositionModeOptions { get; } = new GetPositionModeOptions(false); async Task> IPositionModeRestClient.GetPositionModeAsync(GetPositionModeRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IPositionModeRestClient)this).GetPositionModeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IPositionModeRestClient)this).GetPositionModeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -767,7 +769,7 @@ async Task> IPositionModeRestClient. SetPositionModeOptions IPositionModeRestClient.SetPositionModeOptions { get; } = new SetPositionModeOptions(true, true, false); async Task> IPositionModeRestClient.SetPositionModeAsync(SetPositionModeRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IPositionModeRestClient)this).SetPositionModeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IPositionModeRestClient)this).SetPositionModeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs index e8b0cdba0..e32693543 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs @@ -26,11 +26,11 @@ internal partial class BinanceSocketClientCoinFuturesApi : IBinanceSocketClientC SubscriptionOptions ITickerSocketClient.SubscribeTickerOptions { get; } = new SubscriptionOptions(false); async Task> ITickerSocketClient.SubscribeToTickerUpdatesAsync(SubscribeTickerRequest request, Action> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ITickerSocketClient)this).SubscribeTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((ITickerSocketClient)this).SubscribeTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)); + var symbol = request.Symbol.GetSymbol(FormatSymbol); var result = await SubscribeToTickerUpdatesAsync(symbol, update => handler(update.AsExchangeEvent(Exchange, new SharedSpotTicker(symbol, update.Data.LastPrice, update.Data.LowPrice, update.Data.HighPrice, update.Data.Volume))), ct: ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -41,7 +41,7 @@ async Task> ITickerSocketClient.SubscribeToTi #region Tickers client SubscriptionOptions ITickersSocketClient.SubscribeAllTickersOptions { get; } = new SubscriptionOptions("SubscribeTickersRequest", false); - async Task> ITickersSocketClient.SubscribeToAllTickersUpdatesAsync(ApiType apiType, Action>> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> ITickersSocketClient.SubscribeToAllTickersUpdatesAsync(Action>> handler, ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((ITickersSocketClient)this).SubscribeAllTickersOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); if (validationError != null) @@ -49,9 +49,13 @@ async Task> ITickersSocketClient.SubscribeToA var result = await SubscribeToAllTickerUpdatesAsync(update => { - var data = update.Data.Where(x => apiType == ApiType.PerpetualInverse ? x.Symbol.EndsWith("_PERP") : !x.Symbol.Contains("_PERP")); + var data = update.Data; + if (apiType != null) + data = update.Data.Where(x => apiType == ApiType.PerpetualInverse ? x.Symbol.EndsWith("_PERP") : !x.Symbol.Contains("_PERP")); + if (!data.Any()) return; + handler(update.AsExchangeEvent(Exchange, data.Select(x => new SharedSpotTicker(x.Symbol, x.LastPrice, x.LowPrice, x.HighPrice, x.Volume)))); }, ct: ct).ConfigureAwait(false); @@ -65,11 +69,11 @@ async Task> ITickersSocketClient.SubscribeToA SubscriptionOptions ITradeSocketClient.SubscribeTradeOptions { get; } = new SubscriptionOptions(false); async Task> ITradeSocketClient.SubscribeToTradeUpdatesAsync(SubscribeTradeRequest request, Action>> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)); + var symbol = request.Symbol.GetSymbol(FormatSymbol); var result = await SubscribeToAggregatedTradeUpdatesAsync(symbol, update => handler(update.AsExchangeEvent>(Exchange, new[] { new SharedTrade(update.Data.Price, update.Data.Quantity, update.Data.TradeTime) })), ct:ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -82,11 +86,11 @@ async Task> ITradeSocketClient.SubscribeToTra SubscriptionOptions IBookTickerSocketClient.SubscribeBookTickerOptions { get; } = new SubscriptionOptions(false); async Task> IBookTickerSocketClient.SubscribeToBookTickerUpdatesAsync(SubscribeBookTickerRequest request, Action> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)); + var symbol = request.Symbol.GetSymbol(FormatSymbol); var result = await SubscribeToBookTickerUpdatesAsync(symbol, update => handler(update.AsExchangeEvent(Exchange, new SharedBookTicker(update.Data.BestAskPrice, update.Data.BestAskQuantity, update.Data.BestBidPrice, update.Data.BestBidQuantity))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -102,11 +106,11 @@ async Task> IKlineSocketClient.SubscribeToKli if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeResult(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)); + var symbol = request.Symbol.GetSymbol(FormatSymbol); var result = await SubscribeToKlineUpdatesAsync(symbol, interval, update => handler(update.AsExchangeEvent(Exchange, new SharedKline(update.Data.Data.OpenTime, update.Data.Data.ClosePrice, update.Data.Data.HighPrice, update.Data.Data.LowPrice, update.Data.Data.OpenPrice, update.Data.Data.Volume))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -117,11 +121,11 @@ async Task> IKlineSocketClient.SubscribeToKli SubscribeOrderBookOptions IOrderBookSocketClient.SubscribeOrderBookOptions { get; } = new SubscribeOrderBookOptions(false, new[] { 5, 10, 20 }); async Task> IOrderBookSocketClient.SubscribeToOrderBookUpdatesAsync(SubscribeOrderBookRequest request, Action> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)); + var symbol = request.Symbol.GetSymbol(FormatSymbol); var result = await SubscribeToPartialOrderBookUpdatesAsync(symbol, request.Limit ?? 20, 100, update => handler(update.AsExchangeEvent(Exchange, new SharedOrderBook(update.Data.Asks, update.Data.Bids))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -136,7 +140,7 @@ async Task> IOrderBookSocketClient.SubscribeT new ParameterDescription("ListenKey", typeof(string), "The listenkey for starting the user stream", "123123123") } }; - async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(ApiType apiType, Action>> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(Action>> handler, ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); if (validationError != null) @@ -161,7 +165,7 @@ async Task> IBalanceSocketClient.SubscribeToB new ParameterDescription("ListenKey", typeof(string), "The listenkey for starting the user stream", "123123123") } }; - async Task> IPositionSocketClient.SubscribeToPositionUpdatesAsync(ApiType apiType, Action>> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IPositionSocketClient.SubscribeToPositionUpdatesAsync(Action>> handler, ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((IPositionSocketClient)this).SubscribePositionOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); if (validationError != null) @@ -191,7 +195,7 @@ async Task> IPositionSocketClient.SubscribeTo new ParameterDescription("ListenKey", typeof(string), "The listenkey for starting the user stream", "123123123") } }; - async Task> IFuturesOrderSocketClient.SubscribeToFuturesOrderUpdatesAsync(ApiType apiType, Action>> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IFuturesOrderSocketClient.SubscribeToFuturesOrderUpdatesAsync(Action>> handler, ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); if (validationError != null) diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index ce86920d6..9c29b6761 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -29,7 +29,7 @@ async Task>> IKlineRestClient.GetKlin if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -40,7 +40,7 @@ async Task>> IKlineRestClient.GetKlin // Get data var result = await ExchangeData.GetKlinesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), + request.Symbol.GetSymbol(FormatSymbol), interval, fromTimestamp ?? request.StartTime, request.EndTime?.AddSeconds(-1), @@ -93,11 +93,11 @@ async Task>> ISpotSymbolRestClie EndpointOptions ISpotTickerRestClient.GetSpotTickerOptions { get; } = new EndpointOptions(false); async Task> ISpotTickerRestClient.GetSpotTickerAsync(GetTickerRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ISpotTickerRestClient)this).GetSpotTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((ISpotTickerRestClient)this).GetSpotTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var result = await ExchangeData.GetTickerAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), ct).ConfigureAwait(false); + var result = await ExchangeData.GetTickerAsync(request.Symbol.GetSymbol(FormatSymbol), ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -125,13 +125,13 @@ async Task>> ISpotTickerRestClie async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IRecentTradeRestClient)this).GetRecentTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IRecentTradeRestClient)this).GetRecentTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); // Get data var result = await ExchangeData.GetRecentTradesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), + request.Symbol.GetSymbol(FormatSymbol), limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) @@ -147,7 +147,7 @@ async Task>> IRecentTradeRestClient.G async Task>> ITradeHistoryRestClient.GetTradeHistoryAsync(GetTradeHistoryRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ITradeHistoryRestClient)this).GetTradeHistoryOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((ITradeHistoryRestClient)this).GetTradeHistoryOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -157,7 +157,7 @@ async Task>> ITradeHistoryRestClient. // Get data var result = await ExchangeData.GetAggregatedTradeHistoryAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), + request.Symbol.GetSymbol(FormatSymbol), startTime: fromId != null ? null : request.StartTime, endTime: fromId != null ? null : request.EndTime, limit: 1000, @@ -179,12 +179,12 @@ async Task>> ITradeHistoryRestClient. GetOrderBookOptions IOrderBookRestClient.GetOrderBookOptions { get; } = new GetOrderBookOptions(1, 5000, false); async Task> IOrderBookRestClient.GetOrderBookAsync(GetOrderBookRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); var result = await ExchangeData.GetOrderBookAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), + request.Symbol.GetSymbol(FormatSymbol), limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) @@ -198,7 +198,7 @@ async Task> IOrderBookRestClient.GetOrderBook #region Balance Client EndpointOptions IBalanceRestClient.GetBalancesOptions { get; } = new EndpointOptions("GetBalancesRequest", true); - async Task>> IBalanceRestClient.GetBalancesAsync(ApiType apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IBalanceRestClient.GetBalancesAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((IBalanceRestClient)this).GetBalancesOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); if (validationError != null) @@ -236,12 +236,12 @@ async Task>> IBalanceRestClient.Get async Task> ISpotOrderRestClient.PlaceSpotOrderAsync(PlaceSpotOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).PlaceSpotOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((ISpotOrderRestClient)this).PlaceSpotOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); var result = await Trading.PlaceOrderAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), + request.Symbol.GetSymbol(FormatSymbol), request.Side == SharedOrderSide.Buy ? Enums.OrderSide.Buy : Enums.OrderSide.Sell, request.OrderType == SharedOrderType.Limit ? Enums.SpotOrderType.Limit : request.OrderType == SharedOrderType.Market ? Enums.SpotOrderType.Market: Enums.SpotOrderType.LimitMaker, quantity: request.Quantity, @@ -258,14 +258,14 @@ async Task> ISpotOrderRestClient.PlaceSpotOrderAsync EndpointOptions ISpotOrderRestClient.GetSpotOrderOptions { get; } = new EndpointOptions(true); async Task> ISpotOrderRestClient.GetSpotOrderAsync(GetOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetSpotOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((ISpotOrderRestClient)this).GetSpotOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); - var order = await Trading.GetOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), orderId).ConfigureAwait(false); + var order = await Trading.GetOrderAsync(request.Symbol.GetSymbol(FormatSymbol), orderId).ConfigureAwait(false); if (!order) return order.AsExchangeResult(Exchange, default); @@ -292,11 +292,11 @@ async Task> ISpotOrderRestClient.GetSpotOrder EndpointOptions ISpotOrderRestClient.GetOpenSpotOrdersOptions { get; } = new EndpointOptions(true); async Task>> ISpotOrderRestClient.GetOpenSpotOrdersAsync(GetOpenOrdersRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetOpenSpotOrdersOptions.ValidateRequest(Exchange, request,exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((ISpotOrderRestClient)this).GetOpenSpotOrdersOptions.ValidateRequest(Exchange, request,exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); - var symbol = request.Symbol?.GetSymbol((baseAsset, quoteAsset, deliveryDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliveryDate)); + var symbol = request.Symbol?.GetSymbol(FormatSymbol); var orders = await Trading.GetOpenOrdersAsync(symbol).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); @@ -324,7 +324,7 @@ async Task>> ISpotOrderRestClient PaginatedEndpointOptions ISpotOrderRestClient.GetClosedSpotOrdersOptions { get; } = new PaginatedEndpointOptions(true, true); async Task>> ISpotOrderRestClient.GetClosedSpotOrdersAsync(GetClosedOrdersRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetClosedSpotOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((ISpotOrderRestClient)this).GetClosedSpotOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -334,7 +334,7 @@ async Task>> ISpotOrderRestClient fromTimestamp = dateTimeToken.LastTime; // Get data - var orders = await Trading.GetOrdersAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), + var orders = await Trading.GetOrdersAsync(request.Symbol.GetSymbol(FormatSymbol), startTime: fromTimestamp ?? request.StartTime, endTime: request.EndTime, limit: request.Limit ?? 1000).ConfigureAwait(false); @@ -369,14 +369,14 @@ async Task>> ISpotOrderRestClient EndpointOptions ISpotOrderRestClient.GetSpotOrderTradesOptions { get; } = new EndpointOptions(true); async Task>> ISpotOrderRestClient.GetSpotOrderTradesAsync(GetOrderTradesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetSpotOrderTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((ISpotOrderRestClient)this).GetSpotOrderTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult>(Exchange, new ArgumentError("Invalid order id")); - var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), orderId: orderId).ConfigureAwait(false); + var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol(FormatSymbol), orderId: orderId).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); @@ -399,7 +399,7 @@ async Task>> ISpotOrderRestClient PaginatedEndpointOptions ISpotOrderRestClient.GetSpotUserTradesOptions { get; } = new PaginatedEndpointOptions(true, true); async Task>> ISpotOrderRestClient.GetSpotUserTradesAsync(GetUserTradesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetSpotUserTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((ISpotOrderRestClient)this).GetSpotUserTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -409,7 +409,7 @@ async Task>> ISpotOrderRestClient fromId = long.Parse(fromIdToken.FromToken); // Get data - var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), + var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol(FormatSymbol), startTime: request.StartTime, endTime: request.EndTime, limit: request.Limit ?? 500, @@ -442,14 +442,14 @@ async Task>> ISpotOrderRestClient EndpointOptions ISpotOrderRestClient.CancelSpotOrderOptions { get; } = new EndpointOptions(true); async Task> ISpotOrderRestClient.CancelSpotOrderAsync(CancelOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).CancelSpotOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((ISpotOrderRestClient)this).CancelSpotOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); - var order = await Trading.CancelOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), orderId).ConfigureAwait(false); + var order = await Trading.CancelOrderAsync(request.Symbol.GetSymbol(FormatSymbol), orderId).ConfigureAwait(false); if (!order) return order.AsExchangeResult(Exchange, default); diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs index cd8b8d5b5..e04760f88 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs @@ -21,7 +21,7 @@ internal partial class BinanceSocketClientSpotApi : IBinanceSocketClientSpotApiS #region Tickers client SubscriptionOptions ITickersSocketClient.SubscribeAllTickersOptions { get; } = new SubscriptionOptions("SubscribeTickersRequest", false); - async Task> ITickersSocketClient.SubscribeToAllTickersUpdatesAsync(ApiType apiType, Action>> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> ITickersSocketClient.SubscribeToAllTickersUpdatesAsync(Action>> handler, ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((ITickersSocketClient)this).SubscribeAllTickersOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); if (validationError != null) @@ -38,11 +38,11 @@ async Task> ITickersSocketClient.SubscribeToA SubscriptionOptions ITickerSocketClient.SubscribeTickerOptions { get; } = new SubscriptionOptions(false); async Task> ITickerSocketClient.SubscribeToTickerUpdatesAsync(SubscribeTickerRequest request, Action> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ITickerSocketClient)this).SubscribeTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((ITickerSocketClient)this).SubscribeTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)); + var symbol = request.Symbol.GetSymbol(FormatSymbol); var result = await ExchangeData.SubscribeToMiniTickerUpdatesAsync(symbol, update => handler(update.AsExchangeEvent(Exchange, new SharedSpotTicker(update.Data.Symbol, update.Data.LastPrice, update.Data.HighPrice, update.Data.LowPrice, update.Data.Volume))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -54,11 +54,11 @@ async Task> ITickerSocketClient.SubscribeToTi SubscriptionOptions ITradeSocketClient.SubscribeTradeOptions { get; } = new SubscriptionOptions(false); async Task> ITradeSocketClient.SubscribeToTradeUpdatesAsync(SubscribeTradeRequest request, Action>> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)); + var symbol = request.Symbol.GetSymbol(FormatSymbol); var result = await ExchangeData.SubscribeToTradeUpdatesAsync(symbol, update => handler(update.AsExchangeEvent>(Exchange, new[] { new SharedTrade(update.Data.Price, update.Data.Quantity, update.Data.TradeTime) })), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -71,11 +71,11 @@ async Task> ITradeSocketClient.SubscribeToTra SubscriptionOptions IBookTickerSocketClient.SubscribeBookTickerOptions { get; } = new SubscriptionOptions(false); async Task> IBookTickerSocketClient.SubscribeToBookTickerUpdatesAsync(SubscribeBookTickerRequest request, Action> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)); + var symbol = request.Symbol.GetSymbol(FormatSymbol); var result = await ExchangeData.SubscribeToBookTickerUpdatesAsync(symbol, update => handler(update.AsExchangeEvent(Exchange, new SharedBookTicker(update.Data.BestAskPrice, update.Data.BestAskQuantity, update.Data.BestBidPrice, update.Data.BestBidQuantity))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -85,7 +85,7 @@ async Task> IBookTickerSocketClient.Subscribe #region Balance client SubscriptionOptions IBalanceSocketClient.SubscribeBalanceOptions { get; } = new SubscriptionOptions("SubscribeBalanceRequest", false); - async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(ApiType apiType, Action>> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(Action>> handler, ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); if (validationError != null) @@ -157,11 +157,11 @@ async Task> IKlineSocketClient.SubscribeToKli if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeResult(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)); + var symbol = request.Symbol.GetSymbol(FormatSymbol); var result = await ExchangeData.SubscribeToKlineUpdatesAsync(symbol, interval, update => handler(update.AsExchangeEvent(Exchange, new SharedKline(update.Data.Data.OpenTime, update.Data.Data.ClosePrice, update.Data.Data.HighPrice, update.Data.Data.LowPrice, update.Data.Data.OpenPrice, update.Data.Data.Volume))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -172,11 +172,11 @@ async Task> IKlineSocketClient.SubscribeToKli SubscribeOrderBookOptions IOrderBookSocketClient.SubscribeOrderBookOptions { get; } = new SubscribeOrderBookOptions(false, new[] { 5, 10, 20 }); async Task> IOrderBookSocketClient.SubscribeToOrderBookUpdatesAsync(SubscribeOrderBookRequest request, Action> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)); + var symbol = request.Symbol.GetSymbol(FormatSymbol); var result = await ExchangeData.SubscribeToPartialOrderBookUpdatesAsync(symbol, request.Limit ?? 20, 100, update => handler(update.AsExchangeEvent(Exchange, new SharedOrderBook(update.Data.Asks, update.Data.Bids))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs index 0064b5657..f133a54f5 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -35,7 +35,7 @@ async Task>> IKlineRestClient.GetKlin if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -45,7 +45,7 @@ async Task>> IKlineRestClient.GetKlin fromTimestamp = dateTimeToken.LastTime; var result = await ExchangeData.GetKlinesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), + request.Symbol.GetSymbol(FormatSymbol), interval, fromTimestamp ?? request.StartTime, request.EndTime, @@ -82,7 +82,7 @@ async Task>> IMarkPriceKlineRestC if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IMarkPriceKlineRestClient)this).GetMarkPriceKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IMarkPriceKlineRestClient)this).GetMarkPriceKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -92,7 +92,7 @@ async Task>> IMarkPriceKlineRestC fromTimestamp = dateTimeToken.LastTime; var result = await ExchangeData.GetMarkPriceKlinesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), + request.Symbol.GetSymbol(FormatSymbol), interval, request.Limit ?? 1000, fromTimestamp ?? request.StartTime, @@ -119,7 +119,7 @@ async Task>> IMarkPriceKlineRestC #region Futures Symbol client EndpointOptions IFuturesSymbolRestClient.GetFuturesSymbolsOptions { get; } = new EndpointOptions("GetFuturesSymbolsRequest", false); - async Task>> IFuturesSymbolRestClient.GetFuturesSymbolsAsync(ApiType apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IFuturesSymbolRestClient.GetFuturesSymbolsAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((IFuturesSymbolRestClient)this).GetFuturesSymbolsOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); if (validationError != null) @@ -129,8 +129,10 @@ async Task>> IFuturesSymbolRe if (!result) return result.AsExchangeResult< IEnumerable>(Exchange, default); - var data = result.Data.Symbols.Where(x => apiType == ApiType.PerpetualLinear ? x.ContractType == ContractType.Perpetual : x.ContractType != ContractType.Perpetual); - return result.AsExchangeResult(Exchange, data.Select(s => new SharedFuturesSymbol(s.ContractType == ContractType.Perpetual ? SharedSymbolType.PerpetualLinear : SharedSymbolType.DeliveryLinear, s.BaseAsset, s.QuoteAsset, s.Name, s.Status == SymbolStatus.Trading) + var data = result.Data.Symbols.Where(x => x.ContractType != null); + if (apiType != null) + data = data.Where(x => apiType == ApiType.PerpetualLinear ? x.ContractType == ContractType.Perpetual : (x.ContractType != ContractType.Perpetual && x.ContractType != ContractType.PerpetualDelivering)); + return result.AsExchangeResult>(Exchange, data.Select(s => new SharedFuturesSymbol(s.ContractType == ContractType.Perpetual ? SharedSymbolType.PerpetualLinear : SharedSymbolType.DeliveryLinear, s.BaseAsset, s.QuoteAsset, s.Name, s.Status == SymbolStatus.Trading) { MinTradeQuantity = s.LotSizeFilter?.MinQuantity, MaxTradeQuantity = s.LotSizeFilter?.MaxQuantity, @@ -138,7 +140,7 @@ async Task>> IFuturesSymbolRe PriceStep = s.PriceFilter?.TickSize, ContractSize = 1, DeliveryTime = s.DeliveryDate - })); + }).ToArray()); } #endregion @@ -148,12 +150,12 @@ async Task>> IFuturesSymbolRe EndpointOptions IFuturesTickerRestClient.GetFuturesTickerOptions { get; } = new EndpointOptions(false); async Task> IFuturesTickerRestClient.GetFuturesTickerAsync(GetTickerRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var resultTicker = ExchangeData.GetTickerAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), ct); - var resultMarkPrice = ExchangeData.GetMarkPriceAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), ct); + var resultTicker = ExchangeData.GetTickerAsync(request.Symbol.GetSymbol(FormatSymbol), ct); + var resultMarkPrice = ExchangeData.GetMarkPriceAsync(request.Symbol.GetSymbol(FormatSymbol), ct); await Task.WhenAll(resultTicker, resultMarkPrice).ConfigureAwait(false); if (!resultTicker.Result) @@ -171,7 +173,7 @@ async Task> IFuturesTickerRestClient.GetF } EndpointOptions IFuturesTickerRestClient.GetFuturesTickersOptions { get; } = new EndpointOptions("GetTickersRequest", false); - async Task>> IFuturesTickerRestClient.GetFuturesTickersAsync(ApiType apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IFuturesTickerRestClient.GetFuturesTickersAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickerOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); if (validationError != null) @@ -205,12 +207,12 @@ async Task>> IFuturesTickerRe GetRecentTradesOptions IRecentTradeRestClient.GetRecentTradesOptions { get; } = new GetRecentTradesOptions(1000, false); async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IRecentTradeRestClient)this).GetRecentTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IRecentTradeRestClient)this).GetRecentTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); var result = await ExchangeData.GetRecentTradesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), // Don't pass api type; need only the pair + request.Symbol.GetSymbol(FormatSymbol), // Don't pass api type; need only the pair limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) @@ -243,12 +245,12 @@ async Task>> IRecentTradeRestClient.G async Task> IFuturesOrderRestClient.PlaceFuturesOrderAsync(PlaceFuturesOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).PlaceFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).PlaceFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); var result = await Trading.PlaceOrderAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), + request.Symbol.GetSymbol(FormatSymbol), request.Side == SharedOrderSide.Buy ? Enums.OrderSide.Buy : Enums.OrderSide.Sell, request.OrderType == SharedOrderType.Limit ? Enums.FuturesOrderType.Limit : Enums.FuturesOrderType.Market, quantity: request.Quantity, @@ -267,14 +269,14 @@ async Task> IFuturesOrderRestClient.PlaceFuturesOrde EndpointOptions IFuturesOrderRestClient.GetFuturesOrderOptions { get; } = new EndpointOptions(true); async Task> IFuturesOrderRestClient.GetFuturesOrderAsync(GetOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); - var order = await Trading.GetOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), orderId).ConfigureAwait(false); + var order = await Trading.GetOrderAsync(request.Symbol.GetSymbol(FormatSymbol), orderId).ConfigureAwait(false); if (!order) return order.AsExchangeResult(Exchange, default); @@ -302,11 +304,11 @@ async Task> IFuturesOrderRestClient.GetFut EndpointOptions IFuturesOrderRestClient.GetOpenFuturesOrdersOptions { get; } = new EndpointOptions(true); async Task>> IFuturesOrderRestClient.GetOpenFuturesOrdersAsync(GetOpenOrdersRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetOpenFuturesOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetOpenFuturesOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); - var symbol = request.Symbol?.GetSymbol((baseAsset, quoteAsset, deliveryDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliveryDate)); + var symbol = request.Symbol?.GetSymbol(FormatSymbol); var orders = await Trading.GetOpenOrdersAsync(symbol).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); @@ -335,7 +337,7 @@ async Task>> IFuturesOrderRest PaginatedEndpointOptions IFuturesOrderRestClient.GetClosedFuturesOrdersOptions { get; } = new PaginatedEndpointOptions(true, true); async Task>> IFuturesOrderRestClient.GetClosedFuturesOrdersAsync(GetClosedOrdersRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetClosedFuturesOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetClosedFuturesOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -345,7 +347,7 @@ async Task>> IFuturesOrderRest fromTimestamp = dateTimeToken.LastTime; // Get data - var orders = await Trading.GetOrdersAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), + var orders = await Trading.GetOrdersAsync(request.Symbol.GetSymbol(FormatSymbol), startTime: fromTimestamp ?? request.StartTime, endTime: request.EndTime, limit: request.Limit ?? 1000).ConfigureAwait(false); @@ -381,14 +383,14 @@ async Task>> IFuturesOrderRest EndpointOptions IFuturesOrderRestClient.GetFuturesOrderTradesOptions { get; } = new EndpointOptions(true); async Task>> IFuturesOrderRestClient.GetFuturesOrderTradesAsync(GetOrderTradesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult>(Exchange, new ArgumentError("Invalid order id")); - var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), orderId: orderId).ConfigureAwait(false); + var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol(FormatSymbol), orderId: orderId).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); @@ -411,7 +413,7 @@ async Task>> IFuturesOrderRestCli PaginatedEndpointOptions IFuturesOrderRestClient.GetFuturesUserTradesOptions { get; } = new PaginatedEndpointOptions(true, true); async Task>> IFuturesOrderRestClient.GetFuturesUserTradesAsync(GetUserTradesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetFuturesUserTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetFuturesUserTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -421,7 +423,7 @@ async Task>> IFuturesOrderRestCli fromId = long.Parse(fromIdToken.FromToken); // Get data - var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), + var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol(FormatSymbol), startTime: request.StartTime, endTime: request.EndTime, limit: request.Limit ?? 500, @@ -454,14 +456,14 @@ async Task>> IFuturesOrderRestCli EndpointOptions IFuturesOrderRestClient.CancelFuturesOrderOptions { get; } = new EndpointOptions(true); async Task> IFuturesOrderRestClient.CancelFuturesOrderAsync(CancelOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).CancelFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).CancelFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); - var order = await Trading.CancelOrderAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), orderId).ConfigureAwait(false); + var order = await Trading.CancelOrderAsync(request.Symbol.GetSymbol(FormatSymbol), orderId).ConfigureAwait(false); if (!order) return order.AsExchangeResult(Exchange, default); @@ -471,11 +473,11 @@ async Task> IFuturesOrderRestClient.CancelFuturesOrd EndpointOptions IFuturesOrderRestClient.GetPositionsOptions { get; } = new EndpointOptions(true); async Task>> IFuturesOrderRestClient.GetPositionsAsync(GetPositionsRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetPositionsOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetPositionsOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); - var result = await Account.GetPositionInformationAsync(symbol: request.Symbol?.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), ct: ct).ConfigureAwait(false); + var result = await Account.GetPositionInformationAsync(symbol: request.Symbol?.GetSymbol(FormatSymbol), ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult>(Exchange, default); @@ -492,12 +494,12 @@ async Task>> IFuturesOrderRestClie EndpointOptions IFuturesOrderRestClient.ClosePositionOptions { get; } = new EndpointOptions(true); async Task> IFuturesOrderRestClient.ClosePositionAsync(ClosePositionRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).ClosePositionOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).ClosePositionOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); var result = await Trading.PlaceOrderAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), + request.Symbol.GetSymbol(FormatSymbol), request.PositionSide == SharedPositionSide.Long ? OrderSide.Sell : OrderSide.Buy, FuturesOrderType.Market, request.Quantity, @@ -554,11 +556,11 @@ private SharedOrderType ParseOrderType(FuturesOrderType type) EndpointOptions ILeverageRestClient.GetLeverageOptions { get; } = new EndpointOptions(true); async Task> ILeverageRestClient.GetLeverageAsync(GetLeverageRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ILeverageRestClient)this).GetLeverageOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((ILeverageRestClient)this).GetLeverageOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var result = await Account.GetPositionInformationAsync(symbol: request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), ct: ct).ConfigureAwait(false); + var result = await Account.GetPositionInformationAsync(symbol: request.Symbol.GetSymbol(FormatSymbol), ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -579,11 +581,11 @@ async Task> ILeverageRestClient.GetLeverageAsy SetLeverageOptions ILeverageRestClient.SetLeverageOptions { get; } = new SetLeverageOptions(false); async Task> ILeverageRestClient.SetLeverageAsync(SetLeverageRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ILeverageRestClient)this).SetLeverageOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((ILeverageRestClient)this).SetLeverageOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var result = await Account.ChangeInitialLeverageAsync(symbol: request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), (int)request.Leverage, ct: ct).ConfigureAwait(false); + var result = await Account.ChangeInitialLeverageAsync(symbol: request.Symbol.GetSymbol(FormatSymbol), (int)request.Leverage, ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -595,12 +597,12 @@ async Task> ILeverageRestClient.SetLeverageAsy GetOrderBookOptions IOrderBookRestClient.GetOrderBookOptions { get; } = new GetOrderBookOptions(new[] { 5, 10, 20, 50, 100, 500, 1000 }, false); async Task> IOrderBookRestClient.GetOrderBookAsync(GetOrderBookRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); var result = await ExchangeData.GetOrderBookAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), + request.Symbol.GetSymbol(FormatSymbol), limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) @@ -616,7 +618,7 @@ async Task> IOrderBookRestClient.GetOrderBook async Task>> ITradeHistoryRestClient.GetTradeHistoryAsync(GetTradeHistoryRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ITradeHistoryRestClient)this).GetTradeHistoryOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((ITradeHistoryRestClient)this).GetTradeHistoryOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -626,7 +628,7 @@ async Task>> ITradeHistoryRestClient. // Get data var result = await ExchangeData.GetAggregatedTradeHistoryAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), + request.Symbol.GetSymbol(FormatSymbol), startTime: fromId != null ? null : request.StartTime, endTime: fromId != null ? null : request.EndTime, limit: 1000, @@ -657,7 +659,7 @@ async Task>> IIndexPriceKlineRest if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IIndexPriceKlineRestClient)this).GetIndexPriceKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IIndexPriceKlineRestClient)this).GetIndexPriceKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -667,7 +669,7 @@ async Task>> IIndexPriceKlineRest fromTimestamp = dateTimeToken.LastTime; var result = await ExchangeData.GetMarkPriceKlinesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), + request.Symbol.GetSymbol(FormatSymbol), interval, request.Limit ?? 1000, fromTimestamp ?? request.StartTime, @@ -696,11 +698,11 @@ async Task>> IIndexPriceKlineRest EndpointOptions IOpenInterestRestClient.GetOpenInterestOptions { get; } = new EndpointOptions(true); async Task> IOpenInterestRestClient.GetOpenInterestAsync(GetOpenInterestRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IOpenInterestRestClient)this).GetOpenInterestOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IOpenInterestRestClient)this).GetOpenInterestOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var result = await ExchangeData.GetOpenInterestAsync(request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), ct: ct).ConfigureAwait(false); + var result = await ExchangeData.GetOpenInterestAsync(request.Symbol.GetSymbol(FormatSymbol), ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -714,7 +716,7 @@ async Task> IOpenInterestRestClient.GetOpe async Task>> IFundingRateRestClient.GetFundingRateHistoryAsync(GetFundingRateHistoryRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFundingRateRestClient)this).GetFundingRateHistoryOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IFundingRateRestClient)this).GetFundingRateHistoryOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -724,7 +726,7 @@ async Task>> IFundingRateRestCl // Get data var result = await ExchangeData.GetFundingRatesAsync( - request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)), + request.Symbol.GetSymbol(FormatSymbol), startTime: fromTime ?? request.StartTime, endTime: request.EndTime, limit: 1000, @@ -744,7 +746,7 @@ async Task>> IFundingRateRestCl #region Balance Client EndpointOptions IBalanceRestClient.GetBalancesOptions { get; } = new EndpointOptions("GetBalancesRequest", true); - async Task>> IBalanceRestClient.GetBalancesAsync(ApiType apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IBalanceRestClient.GetBalancesAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((IBalanceRestClient)this).GetBalancesOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); if (validationError != null) @@ -764,7 +766,7 @@ async Task>> IBalanceRestClient.Get GetPositionModeOptions IPositionModeRestClient.GetPositionModeOptions { get; } = new GetPositionModeOptions(false); async Task> IPositionModeRestClient.GetPositionModeAsync(GetPositionModeRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IPositionModeRestClient)this).GetPositionModeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IPositionModeRestClient)this).GetPositionModeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -778,7 +780,7 @@ async Task> IPositionModeRestClient. SetPositionModeOptions IPositionModeRestClient.SetPositionModeOptions { get; } = new SetPositionModeOptions(true, true, false); async Task> IPositionModeRestClient.SetPositionModeAsync(SetPositionModeRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IPositionModeRestClient)this).SetPositionModeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IPositionModeRestClient)this).SetPositionModeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs index 2c9a03d82..b18715799 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs @@ -26,11 +26,11 @@ internal partial class BinanceSocketClientUsdFuturesApi : IBinanceSocketClientUs SubscriptionOptions ITickerSocketClient.SubscribeTickerOptions { get; } = new SubscriptionOptions(false); async Task> ITickerSocketClient.SubscribeToTickerUpdatesAsync(SubscribeTickerRequest request, Action> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ITickerSocketClient)this).SubscribeTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((ITickerSocketClient)this).SubscribeTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)); + var symbol = request.Symbol.GetSymbol(FormatSymbol); var result = await SubscribeToTickerUpdatesAsync(symbol, update => handler(update.AsExchangeEvent(Exchange, new SharedSpotTicker(symbol, update.Data.LastPrice, update.Data.LowPrice, update.Data.HighPrice, update.Data.Volume))), ct: ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -41,7 +41,7 @@ async Task> ITickerSocketClient.SubscribeToTi #region Tickers client SubscriptionOptions ITickersSocketClient.SubscribeAllTickersOptions { get; } = new SubscriptionOptions("SubscribeTickersRequest", false); - async Task> ITickersSocketClient.SubscribeToAllTickersUpdatesAsync(ApiType apiType, Action>> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> ITickersSocketClient.SubscribeToAllTickersUpdatesAsync(Action>> handler, ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((ITickersSocketClient)this).SubscribeAllTickersOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); if (validationError != null) @@ -49,9 +49,13 @@ async Task> ITickersSocketClient.SubscribeToA var result = await SubscribeToAllTickerUpdatesAsync(update => { - var data = update.Data.Where(x => apiType == ApiType.PerpetualLinear ? x.Symbol.Contains("_") : !x.Symbol.Contains("_")); + var data = update.Data; + if (apiType != null) + data = data.Where(x => apiType == ApiType.PerpetualLinear ? !x.Symbol.Contains("_") : x.Symbol.Contains("_")); + if (!data.Any()) return; + handler(update.AsExchangeEvent(Exchange, data.Select(x => new SharedSpotTicker(x.Symbol, x.LastPrice, x.LowPrice, x.HighPrice, x.Volume)))); }, ct: ct).ConfigureAwait(false); @@ -65,11 +69,11 @@ async Task> ITickersSocketClient.SubscribeToA SubscriptionOptions ITradeSocketClient.SubscribeTradeOptions { get; } = new SubscriptionOptions(false); async Task> ITradeSocketClient.SubscribeToTradeUpdatesAsync(SubscribeTradeRequest request, Action>> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)); + var symbol = request.Symbol.GetSymbol(FormatSymbol); var result = await SubscribeToAggregatedTradeUpdatesAsync(symbol, update => handler(update.AsExchangeEvent>(Exchange, new[] { new SharedTrade(update.Data.Price, update.Data.Quantity, update.Data.TradeTime) })), ct:ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -82,11 +86,11 @@ async Task> ITradeSocketClient.SubscribeToTra SubscriptionOptions IBookTickerSocketClient.SubscribeBookTickerOptions { get; } = new SubscriptionOptions(false); async Task> IBookTickerSocketClient.SubscribeToBookTickerUpdatesAsync(SubscribeBookTickerRequest request, Action> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)); + var symbol = request.Symbol.GetSymbol(FormatSymbol); var result = await SubscribeToBookTickerUpdatesAsync(symbol, update => handler(update.AsExchangeEvent(Exchange, new SharedBookTicker(update.Data.BestAskPrice, update.Data.BestAskQuantity, update.Data.BestBidPrice, update.Data.BestBidQuantity))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -102,7 +106,7 @@ async Task> IBookTickerSocketClient.Subscribe new ParameterDescription("ListenKey", typeof(string), "The listenkey for starting the user stream", "123123123") } }; - async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(ApiType apiType, Action>> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(Action>> handler, ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); if (validationError != null) @@ -128,7 +132,7 @@ async Task> IBalanceSocketClient.SubscribeToB new ParameterDescription("ListenKey", typeof(string), "The listenkey for starting the user stream", "123123123") } }; - async Task> IFuturesOrderSocketClient.SubscribeToFuturesOrderUpdatesAsync(ApiType apiType, Action>> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IFuturesOrderSocketClient.SubscribeToFuturesOrderUpdatesAsync(Action>> handler, ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); if (validationError != null) @@ -176,11 +180,11 @@ async Task> IKlineSocketClient.SubscribeToKli if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeResult(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)); + var symbol = request.Symbol.GetSymbol(FormatSymbol); var result = await SubscribeToKlineUpdatesAsync(symbol, interval, update => handler(update.AsExchangeEvent(Exchange, new SharedKline(update.Data.Data.OpenTime, update.Data.Data.ClosePrice, update.Data.Data.HighPrice, update.Data.Data.LowPrice, update.Data.Data.OpenPrice, update.Data.Data.Volume))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -191,11 +195,11 @@ async Task> IKlineSocketClient.SubscribeToKli SubscribeOrderBookOptions IOrderBookSocketClient.SubscribeOrderBookOptions { get; } = new SubscribeOrderBookOptions(false, new[] { 5, 10, 20 }); async Task> IOrderBookSocketClient.SubscribeToOrderBookUpdatesAsync(SubscribeOrderBookRequest request, Action> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); - var symbol = request.Symbol.GetSymbol((baseAsset, quoteAsset, deliverDate) => FormatSymbol(baseAsset, quoteAsset, request.ApiType, deliverDate)); + var symbol = request.Symbol.GetSymbol(FormatSymbol); var result = await SubscribeToPartialOrderBookUpdatesAsync(symbol, request.Limit ?? 20, 100, update => handler(update.AsExchangeEvent(Exchange, new SharedOrderBook(update.Data.Asks, update.Data.Bids))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -210,7 +214,7 @@ async Task> IOrderBookSocketClient.SubscribeT new ParameterDescription("ListenKey", typeof(string), "The listenkey for starting the user stream", "123123123") } }; - async Task> IPositionSocketClient.SubscribeToPositionUpdatesAsync(ApiType apiType, Action>> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IPositionSocketClient.SubscribeToPositionUpdatesAsync(Action>> handler, ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((IPositionSocketClient)this).SubscribePositionOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); if (validationError != null) @@ -218,7 +222,12 @@ async Task> IPositionSocketClient.SubscribeTo var listenKey = exchangeParameters.GetValue(Exchange, "ListenKey"); var result = await SubscribeToUserDataUpdatesAsync(listenKey!, - onAccountUpdate: update => handler(update.AsExchangeEvent(Exchange, update.Data.UpdateData.Positions.Select(x => new SharedPosition(x.Symbol, x.Quantity, update.Data.EventTime)))), + onAccountUpdate: update => handler(update.AsExchangeEvent(Exchange, update.Data.UpdateData.Positions.Select(x => new SharedPosition(x.Symbol, x.Quantity, update.Data.EventTime) + { + AverageEntryPrice = x.EntryPrice, + PositionSide = x.PositionSide == Enums.PositionSide.Both ? (x.Quantity > 0 ? SharedPositionSide.Long : SharedPositionSide.Short) : x.PositionSide == Enums.PositionSide.Short ? SharedPositionSide.Short : SharedPositionSide.Long, + UnrealizedPnl = x.UnrealizedPnl + }))), ct: ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); From 80395a0f53f86073434f74ff01b9230a79eda5ba Mon Sep 17 00:00:00 2001 From: JKorf Date: Tue, 10 Sep 2024 22:19:26 +0200 Subject: [PATCH 33/54] wip --- .../BinanceRestClientCoinFuturesApiShared.cs | 46 ++++--- ...BinanceSocketClientCoinFuturesApiShared.cs | 4 +- .../SpotApi/BinanceRestClientSpotApiShared.cs | 120 +++++++++++------- .../BinanceSocketClientSpotApiShared.cs | 4 +- .../BinanceRestClientUsdFuturesApiShared.cs | 46 ++++--- .../BinanceSocketClientUsdFuturesApiShared.cs | 4 +- 6 files changed, 138 insertions(+), 86 deletions(-) diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs index 7672e25f0..35d210708 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -21,7 +21,7 @@ internal partial class BinanceRestClientCoinFuturesApi : IBinanceRestClientCoinF #region Klines client - GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(true, false) + GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(SharedPaginationType.Descending, false) { MaxRequestDataPoints = 1000 }; @@ -36,17 +36,29 @@ async Task>> IKlineRestClient.GetKlin if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); - // Determine page token - DateTime? fromTimestamp = null; + // Determine pagination + // Data is normally returned oldest first, so to do newest first pagination we have to do some calc + DateTime endTime = request.EndTime ?? DateTime.UtcNow; + DateTime? startTime = request.StartTime; if (pageToken is DateTimeToken dateTimeToken) - fromTimestamp = dateTimeToken.LastTime; + endTime = dateTimeToken.LastTime; + + var limit = request.Limit ?? 1000; + if (startTime == null || startTime < endTime) + { + var offset = (int)interval * limit; + startTime = endTime.AddSeconds(-offset); + } + + if (startTime < request.StartTime) + startTime = request.StartTime; var result = await ExchangeData.GetKlinesAsync( request.Symbol.GetSymbol(FormatSymbol), interval, - fromTimestamp ?? request.StartTime, - request.EndTime, - request.Limit ?? 1000, + startTime, + endTime, + limit, ct: ct ).ConfigureAwait(false); if (!result) @@ -54,14 +66,14 @@ async Task>> IKlineRestClient.GetKlin // Get next token DateTimeToken? nextToken = null; - if (request.StartTime != null && result.Data.Any()) + if (result.Data.Count() == limit) { - var maxOpenTime = result.Data.Max(x => x.OpenTime); - if (maxOpenTime < request.EndTime!.Value.AddSeconds(-(int)request.Interval)) - nextToken = new DateTimeToken(maxOpenTime.AddSeconds((int)interval)); + var minOpenTime = result.Data.Min(x => x.OpenTime); + if (request.StartTime == null || minOpenTime > request.StartTime.Value) + nextToken = new DateTimeToken(minOpenTime.AddSeconds(-(int)interval)); } - return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)), nextToken); + return result.AsExchangeResult(Exchange, result.Data.Reverse().Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)), nextToken); } #endregion @@ -288,7 +300,7 @@ async Task>> IFuturesOrderRest })); } - PaginatedEndpointOptions IFuturesOrderRestClient.GetClosedFuturesOrdersOptions { get; } = new PaginatedEndpointOptions(true, true); + PaginatedEndpointOptions IFuturesOrderRestClient.GetClosedFuturesOrdersOptions { get; } = new PaginatedEndpointOptions(SharedPaginationType.Descending, true); async Task>> IFuturesOrderRestClient.GetClosedFuturesOrdersAsync(GetClosedOrdersRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((IFuturesOrderRestClient)this).GetClosedFuturesOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); @@ -364,7 +376,7 @@ async Task>> IFuturesOrderRestCli })); } - PaginatedEndpointOptions IFuturesOrderRestClient.GetFuturesUserTradesOptions { get; } = new PaginatedEndpointOptions(true, true); + PaginatedEndpointOptions IFuturesOrderRestClient.GetFuturesUserTradesOptions { get; } = new PaginatedEndpointOptions(SharedPaginationType.Descending, true); async Task>> IFuturesOrderRestClient.GetFuturesUserTradesAsync(GetUserTradesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((IFuturesOrderRestClient)this).GetFuturesUserTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); @@ -537,7 +549,7 @@ async Task> ILeverageRestClient.SetLeverageAsy #region Mark Klines client - GetKlinesOptions IMarkPriceKlineRestClient.GetMarkPriceKlinesOptions { get; } = new GetKlinesOptions(true, false) + GetKlinesOptions IMarkPriceKlineRestClient.GetMarkPriceKlinesOptions { get; } = new GetKlinesOptions(SharedPaginationType.Ascending, false) { MaxRequestDataPoints = 1000 }; @@ -603,7 +615,7 @@ async Task> IOrderBookRestClient.GetOrderBook #endregion #region Trade History client - GetTradeHistoryOptions ITradeHistoryRestClient.GetTradeHistoryOptions { get; } = new GetTradeHistoryOptions(true, false); + GetTradeHistoryOptions ITradeHistoryRestClient.GetTradeHistoryOptions { get; } = new GetTradeHistoryOptions(SharedPaginationType.Ascending, false); async Task>> ITradeHistoryRestClient.GetTradeHistoryAsync(GetTradeHistoryRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { @@ -637,7 +649,7 @@ async Task>> ITradeHistoryRestClient. #region Index Klines client - GetKlinesOptions IIndexPriceKlineRestClient.GetIndexPriceKlinesOptions { get; } = new GetKlinesOptions(true, false) + GetKlinesOptions IIndexPriceKlineRestClient.GetIndexPriceKlinesOptions { get; } = new GetKlinesOptions(SharedPaginationType.Ascending, false) { MaxRequestDataPoints = 1000 }; diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs index e32693543..c35e1c309 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs @@ -31,7 +31,7 @@ async Task> ITickerSocketClient.SubscribeToTi return new ExchangeResult(Exchange, validationError); var symbol = request.Symbol.GetSymbol(FormatSymbol); - var result = await SubscribeToTickerUpdatesAsync(symbol, update => handler(update.AsExchangeEvent(Exchange, new SharedSpotTicker(symbol, update.Data.LastPrice, update.Data.LowPrice, update.Data.HighPrice, update.Data.Volume))), ct: ct).ConfigureAwait(false); + var result = await SubscribeToTickerUpdatesAsync(symbol, update => handler(update.AsExchangeEvent(Exchange, new SharedSpotTicker(symbol, update.Data.LastPrice, update.Data.LowPrice, update.Data.HighPrice, update.Data.Volume, update.Data.PriceChangePercent))), ct: ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); } @@ -56,7 +56,7 @@ async Task> ITickersSocketClient.SubscribeToA if (!data.Any()) return; - handler(update.AsExchangeEvent(Exchange, data.Select(x => new SharedSpotTicker(x.Symbol, x.LastPrice, x.LowPrice, x.HighPrice, x.Volume)))); + handler(update.AsExchangeEvent(Exchange, data.Select(x => new SharedSpotTicker(x.Symbol, x.LastPrice, x.LowPrice, x.HighPrice, x.Volume, x.PriceChangePercent)))); }, ct: ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index 9c29b6761..d7ef065ee 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -18,7 +18,7 @@ internal partial class BinanceRestClientSpotApi : IBinanceRestClientSpotApiShare #region Klines Client - GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(true, false) + GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(SharedPaginationType.Descending, false) { MaxRequestDataPoints = 1000 }; @@ -33,18 +33,33 @@ async Task>> IKlineRestClient.GetKlin if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); - // Determine page token - DateTime? fromTimestamp = null; + // Determine pagination + // Data is normally returned oldest first, so to do newest first pagination we have to do some calc + DateTime endTime = request.EndTime ?? DateTime.UtcNow; + DateTime? startTime = request.StartTime; if (pageToken is DateTimeToken dateTimeToken) - fromTimestamp = dateTimeToken.LastTime; + endTime = dateTimeToken.LastTime; + + var limit = request.Limit ?? 1000; + if (startTime == null || startTime < endTime) + { + var offset = (int)interval * limit; + if (request.EndTime == null && pageToken is null) + offset = (int)interval * (limit - 1); + + startTime = endTime.AddSeconds(-offset); + } + + if (startTime < request.StartTime) + startTime = request.StartTime; // Get data var result = await ExchangeData.GetKlinesAsync( request.Symbol.GetSymbol(FormatSymbol), interval, - fromTimestamp ?? request.StartTime, - request.EndTime?.AddSeconds(-1), - request.Limit ?? 1000, + startTime, + endTime, + limit, ct: ct ).ConfigureAwait(false); if (!result) @@ -52,14 +67,14 @@ async Task>> IKlineRestClient.GetKlin // Get next token DateTimeToken? nextToken = null; - if (request.StartTime != null && result.Data.Any()) + if (result.Data.Count() == limit) { - var maxOpenTime = result.Data.Max(x => x.OpenTime); - if (maxOpenTime < request.EndTime!.Value.AddSeconds(-(int)request.Interval)) - nextToken = new DateTimeToken(maxOpenTime.AddSeconds((int)interval)); + var minOpenTime = result.Data.Min(x => x.OpenTime); + if (request.StartTime == null || minOpenTime > request.StartTime.Value) + nextToken = new DateTimeToken(minOpenTime.AddSeconds(-(int)interval)); } - return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)), nextToken); + return result.AsExchangeResult>(Exchange, result.Data.Reverse().Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)).ToArray(), nextToken); } #endregion @@ -77,13 +92,14 @@ async Task>> ISpotSymbolRestClie if (!result) return result.AsExchangeResult>(Exchange, default); - return result.AsExchangeResult(Exchange, result.Data.Symbols.Select(s => new SharedSpotSymbol(s.BaseAsset, s.QuoteAsset, s.Name, s.Status == SymbolStatus.Trading) + return result.AsExchangeResult>(Exchange, result.Data.Symbols.Select(s => new SharedSpotSymbol(s.BaseAsset, s.QuoteAsset, s.Name, s.Status == SymbolStatus.Trading && s.IsSpotTradingAllowed) { MinTradeQuantity = s.LotSizeFilter?.MinQuantity, MaxTradeQuantity = s.LotSizeFilter?.MaxQuantity, + MinNotionalValue = s.MinNotionalFilter?.MinNotional ?? s.NotionalFilter?.MinNotional, QuantityStep = s.LotSizeFilter?.StepSize, PriceStep = s.PriceFilter?.TickSize - })); + }).ToArray()); } #endregion @@ -101,7 +117,7 @@ async Task> ISpotTickerRestClient.GetSpotTic if (!result) return result.AsExchangeResult(Exchange, default); - return result.AsExchangeResult(Exchange, new SharedSpotTicker(result.Data.Symbol, result.Data.LastPrice, result.Data.HighPrice, result.Data.LowPrice, result.Data.Volume)); + return result.AsExchangeResult(Exchange, new SharedSpotTicker(result.Data.Symbol, result.Data.LastPrice, result.Data.HighPrice, result.Data.LowPrice, result.Data.Volume, result.Data.PriceChangePercent)); } EndpointOptions ISpotTickerRestClient.GetSpotTickersOptions { get; } = new EndpointOptions("GetSpotTickersRequest", false); @@ -115,7 +131,7 @@ async Task>> ISpotTickerRestClie if (!result) return result.AsExchangeResult>(Exchange, default); - return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedSpotTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume))); + return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedSpotTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume, x.PriceChangePercent)).ToArray()); } #endregion @@ -138,12 +154,12 @@ async Task>> IRecentTradeRestClient.G return result.AsExchangeResult>(Exchange, default); // Return - return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedTrade(x.BaseQuantity, x.Price, x.TradeTime))); + return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedTrade(x.BaseQuantity, x.Price, x.TradeTime)).ToArray()); } #endregion #region Trade History client - GetTradeHistoryOptions ITradeHistoryRestClient.GetTradeHistoryOptions { get; } = new GetTradeHistoryOptions(true, false); + GetTradeHistoryOptions ITradeHistoryRestClient.GetTradeHistoryOptions { get; } = new GetTradeHistoryOptions(SharedPaginationType.Ascending, false); async Task>> ITradeHistoryRestClient.GetTradeHistoryAsync(GetTradeHistoryRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { @@ -160,7 +176,7 @@ async Task>> ITradeHistoryRestClient. request.Symbol.GetSymbol(FormatSymbol), startTime: fromId != null ? null : request.StartTime, endTime: fromId != null ? null : request.EndTime, - limit: 1000, + limit: request.Limit ?? 1000, fromId: fromId, ct: ct).ConfigureAwait(false); if (!result) @@ -171,7 +187,7 @@ async Task>> ITradeHistoryRestClient. nextToken = new FromIdToken(result.Data.Max(x => x.Id).ToString()); // Return - return result.AsExchangeResult(Exchange, result.Data.Where(x => x.TradeTime < request.EndTime).Select(x => new SharedTrade(x.Quantity, x.Price, x.TradeTime)), nextToken); + return result.AsExchangeResult>(Exchange, result.Data.Where(x => x.TradeTime < request.EndTime).Select(x => new SharedTrade(x.Quantity, x.Price, x.TradeTime)).ToArray(), nextToken); } #endregion @@ -208,7 +224,7 @@ async Task>> IBalanceRestClient.Get if (!result) return result.AsExchangeResult>(Exchange, default); - return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedBalance(x.Asset, x.Available, x.Total))); + return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedBalance(x.Asset, x.Available, x.Total)).ToArray()); } #endregion @@ -247,6 +263,7 @@ async Task> ISpotOrderRestClient.PlaceSpotOrderAsync quantity: request.Quantity, quoteQuantity: request.QuoteQuantity, price: request.Price, + timeInForce: GetTimeInForce(request.TimeInForce, request.OrderType), newClientOrderId: request.ClientOrderId).ConfigureAwait(false); if (!result) @@ -301,7 +318,7 @@ async Task>> ISpotOrderRestClient if (!orders) return orders.AsExchangeResult>(Exchange, default); - return orders.AsExchangeResult(Exchange, orders.Data.Select(x => new SharedSpotOrder( + return orders.AsExchangeResult>(Exchange, orders.Data.Select(x => new SharedSpotOrder( x.Symbol, x.Id.ToString(), ParseOrderType(x.Type), @@ -318,10 +335,10 @@ async Task>> ISpotOrderRestClient QuoteQuantityFilled = x.QuoteQuantityFilled, TimeInForce = ParseTimeInForce(x.TimeInForce), UpdateTime = x.UpdateTime - })); + }).ToArray()); } - PaginatedEndpointOptions ISpotOrderRestClient.GetClosedSpotOrdersOptions { get; } = new PaginatedEndpointOptions(true, true); + PaginatedEndpointOptions ISpotOrderRestClient.GetClosedSpotOrdersOptions { get; } = new PaginatedEndpointOptions(SharedPaginationType.Ascending, true); async Task>> ISpotOrderRestClient.GetClosedSpotOrdersAsync(GetClosedOrdersRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((ISpotOrderRestClient)this).GetClosedSpotOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); @@ -329,24 +346,25 @@ async Task>> ISpotOrderRestClient return new ExchangeWebResult>(Exchange, validationError); // Determine page token - DateTime? fromTimestamp = null; - if (pageToken is DateTimeToken dateTimeToken) - fromTimestamp = dateTimeToken.LastTime; + long? fromId = null; + if (pageToken is FromIdToken fromIdToken) + fromId = long.Parse(fromIdToken.FromToken); // Get data var orders = await Trading.GetOrdersAsync(request.Symbol.GetSymbol(FormatSymbol), - startTime: fromTimestamp ?? request.StartTime, + orderId: fromId, + startTime: request.StartTime, endTime: request.EndTime, limit: request.Limit ?? 1000).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); // Get next token - DateTimeToken? nextToken = null; - if (orders.Data.Count() == (request.Limit ?? 1000)) - nextToken = new DateTimeToken(orders.Data.Max(o => o.CreateTime)); + FromIdToken? nextToken = null; + if (orders.Data.Any()) + nextToken = new FromIdToken(orders.Data.Max(o => o.Id + 1).ToString()); - return orders.AsExchangeResult(Exchange, orders.Data.Where(x => x.Status == OrderStatus.Filled || x.Status == OrderStatus.Canceled || x.Status == OrderStatus.Expired).Select(x => new SharedSpotOrder( + return orders.AsExchangeResult>(Exchange, orders.Data.Where(x => x.Status == OrderStatus.Filled || x.Status == OrderStatus.Canceled || x.Status == OrderStatus.Expired).Select(x => new SharedSpotOrder( x.Symbol, x.Id.ToString(), ParseOrderType(x.Type), @@ -363,7 +381,7 @@ async Task>> ISpotOrderRestClient QuoteQuantityFilled = x.QuoteQuantityFilled, TimeInForce = ParseTimeInForce(x.TimeInForce), UpdateTime = x.UpdateTime - })); + }).ToArray(), nextToken); } EndpointOptions ISpotOrderRestClient.GetSpotOrderTradesOptions { get; } = new EndpointOptions(true); @@ -380,7 +398,7 @@ async Task>> ISpotOrderRestClient if (!orders) return orders.AsExchangeResult>(Exchange, default); - return orders.AsExchangeResult(Exchange, orders.Data.Select(x => new SharedUserTrade( + return orders.AsExchangeResult>(Exchange, orders.Data.Select(x => new SharedUserTrade( x.Symbol, x.OrderId.ToString(), x.Id.ToString(), @@ -393,10 +411,10 @@ async Task>> ISpotOrderRestClient Fee = x.Fee, FeeAsset = x.FeeAsset, Role = x.IsMaker ? SharedRole.Maker : SharedRole.Taker - })); + }).ToArray()); } - PaginatedEndpointOptions ISpotOrderRestClient.GetSpotUserTradesOptions { get; } = new PaginatedEndpointOptions(true, true); + PaginatedEndpointOptions ISpotOrderRestClient.GetSpotUserTradesOptions { get; } = new PaginatedEndpointOptions(SharedPaginationType.Descending, true); async Task>> ISpotOrderRestClient.GetSpotUserTradesAsync(GetUserTradesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((ISpotOrderRestClient)this).GetSpotUserTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); @@ -423,7 +441,7 @@ async Task>> ISpotOrderRestClient if (orders.Data.Count() == (request.Limit ?? 500)) nextToken = new FromIdToken(orders.Data.Max(o => o.Id).ToString()); - return orders.AsExchangeResult(Exchange, orders.Data.Select(x => new SharedUserTrade( + return orders.AsExchangeResult>(Exchange, orders.Data.Select(x => new SharedUserTrade( x.Symbol, x.OrderId.ToString(), x.Id.ToString(), @@ -436,7 +454,7 @@ async Task>> ISpotOrderRestClient Fee = x.Fee, FeeAsset = x.FeeAsset, Role = x.IsMaker ? SharedRole.Maker : SharedRole.Taker - }), nextToken); + }).ToArray(), nextToken); } EndpointOptions ISpotOrderRestClient.CancelSpotOrderOptions { get; } = new EndpointOptions(true); @@ -456,6 +474,16 @@ async Task> ISpotOrderRestClient.CancelSpotOrderAsyn return order.AsExchangeResult(Exchange, new SharedId(order.Data.Id.ToString())); } + private Enums.TimeInForce? GetTimeInForce(SharedTimeInForce? tif, SharedOrderType type) + { + if (tif == SharedTimeInForce.FillOrKill) return TimeInForce.FillOrKill; + if (tif == SharedTimeInForce.ImmediateOrCancel) return TimeInForce.ImmediateOrCancel; + if (tif == SharedTimeInForce.GoodTillCanceled) return TimeInForce.GoodTillCanceled; + if (type == SharedOrderType.Limit) return TimeInForce.GoodTillCanceled; // Limit orders needs tif + + return null; + } + private SharedOrderStatus ParseOrderStatus(OrderStatus status) { if (status == OrderStatus.PendingNew || status == OrderStatus.New || status == OrderStatus.PartiallyFilled || status == OrderStatus.PendingCancel) return SharedOrderStatus.Open; @@ -497,7 +525,7 @@ async Task>> IAssetsRestClient.GetAss if (!assets) return assets.AsExchangeResult>(Exchange, default); - return assets.AsExchangeResult(Exchange, assets.Data.Select(x => new SharedAsset(x.Asset) + return assets.AsExchangeResult>(Exchange, assets.Data.Select(x => new SharedAsset(x.Asset) { FullName = x.Name, Networks = x.NetworkList.Select(x => new SharedAssetNetwork(x.Network) @@ -510,7 +538,7 @@ async Task>> IAssetsRestClient.GetAss WithdrawEnabled = x.WithdrawEnabled, WithdrawFee = x.WithdrawFee }) - })); + }).ToArray()); } EndpointOptions IAssetsRestClient.GetAssetOptions { get; } = new EndpointOptions(false); @@ -566,7 +594,7 @@ async Task>> IDepositRestCli }); } - GetDepositsOptions IDepositRestClient.GetDepositsOptions { get; } = new GetDepositsOptions(true, true); + GetDepositsOptions IDepositRestClient.GetDepositsOptions { get; } = new GetDepositsOptions(SharedPaginationType.Descending, true); async Task>> IDepositRestClient.GetDepositsAsync(GetDepositsRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((IDepositRestClient)this).GetDepositsOptions.ValidateRequest(Exchange, request, exchangeParameters, ApiType.Spot, SupportedApiTypes); @@ -594,20 +622,20 @@ async Task>> IDepositRestClient.Get if (deposits.Data.Count() == (request.Limit ?? 100)) nextToken = new OffsetToken((offset ?? 0) + deposits.Data.Count()); - return deposits.AsExchangeResult(Exchange, deposits.Data.Select(x => new SharedDeposit(x.Asset, x.Quantity, x.Status == DepositStatus.Success, x.InsertTime) + return deposits.AsExchangeResult>(Exchange, deposits.Data.Select(x => new SharedDeposit(x.Asset, x.Quantity, x.Status == DepositStatus.Success, x.InsertTime) { Confirmations = x.Confirmations.Contains("/") ? int.Parse(x.Confirmations.Split(new[] { "/" }, StringSplitOptions.RemoveEmptyEntries)[0]) : null, Network = x.Network, TransactionId = x.TransactionId, Tag = x.AddressTag - }), nextToken); + }).ToArray(), nextToken); } #endregion #region Withdrawal client - GetWithdrawalsOptions IWithdrawalRestClient.GetWithdrawalsOptions { get; } = new GetWithdrawalsOptions(true, true); + GetWithdrawalsOptions IWithdrawalRestClient.GetWithdrawalsOptions { get; } = new GetWithdrawalsOptions(SharedPaginationType.Descending, true); async Task>> IWithdrawalRestClient.GetWithdrawalsAsync(GetWithdrawalsRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((IWithdrawalRestClient)this).GetWithdrawalsOptions.ValidateRequest(Exchange, request, exchangeParameters, ApiType.Spot, SupportedApiTypes); @@ -635,14 +663,14 @@ async Task>> IWithdrawalRestClie if (withdrawals.Data.Count() == (request.Limit ?? 100)) nextToken = new OffsetToken((offset ?? 0) + withdrawals.Data.Count()); - return withdrawals.AsExchangeResult(Exchange, withdrawals.Data.Select(x => new SharedWithdrawal(x.Asset, x.Address, x.Quantity, x.Status == WithdrawalStatus.Completed, x.ApplyTime) + return withdrawals.AsExchangeResult>(Exchange, withdrawals.Data.Select(x => new SharedWithdrawal(x.Asset, x.Address, x.Quantity, x.Status == WithdrawalStatus.Completed, x.ApplyTime) { Confirmations = x.ConfirmTimes, Network = x.Network, Tag = x.AddressTag, TransactionId = x.TransactionId, Fee = x.TransactionFee - })); + }).ToArray()); } #endregion diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs index e04760f88..7fd9f0899 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs @@ -27,7 +27,7 @@ async Task> ITickersSocketClient.SubscribeToA if (validationError != null) return new ExchangeResult(Exchange, validationError); - var result = await ExchangeData.SubscribeToAllMiniTickerUpdatesAsync(update => handler(update.AsExchangeEvent(Exchange, update.Data.Select(x => new SharedSpotTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume)))), ct).ConfigureAwait(false); + var result = await ExchangeData.SubscribeToAllTickerUpdatesAsync(update => handler(update.AsExchangeEvent(Exchange, update.Data.Select(x => new SharedSpotTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume, x.PriceChangePercent)))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); } @@ -43,7 +43,7 @@ async Task> ITickerSocketClient.SubscribeToTi return new ExchangeResult(Exchange, validationError); var symbol = request.Symbol.GetSymbol(FormatSymbol); - var result = await ExchangeData.SubscribeToMiniTickerUpdatesAsync(symbol, update => handler(update.AsExchangeEvent(Exchange, new SharedSpotTicker(update.Data.Symbol, update.Data.LastPrice, update.Data.HighPrice, update.Data.LowPrice, update.Data.Volume))), ct).ConfigureAwait(false); + var result = await ExchangeData.SubscribeToTickerUpdatesAsync(symbol, update => handler(update.AsExchangeEvent(Exchange, new SharedSpotTicker(update.Data.Symbol, update.Data.LastPrice, update.Data.HighPrice, update.Data.LowPrice, update.Data.Volume, update.Data.PriceChangePercent))), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); } diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs index f133a54f5..42b2d8dea 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -24,7 +24,7 @@ internal partial class BinanceRestClientUsdFuturesApi : IBinanceRestClientUsdFut #region Klines client - GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(true, false) + GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(SharedPaginationType.Descending, false) { MaxRequestDataPoints = 1000 }; @@ -39,17 +39,29 @@ async Task>> IKlineRestClient.GetKlin if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); - // Determine page token - DateTime? fromTimestamp = null; + // Determine pagination + // Data is normally returned oldest first, so to do newest first pagination we have to do some calc + DateTime endTime = request.EndTime ?? DateTime.UtcNow; + DateTime? startTime = request.StartTime; if (pageToken is DateTimeToken dateTimeToken) - fromTimestamp = dateTimeToken.LastTime; + endTime = dateTimeToken.LastTime; + + var limit = request.Limit ?? 1000; + if (startTime == null || startTime < endTime) + { + var offset = (int)interval * limit; + startTime = endTime.AddSeconds(-offset); + } + + if (startTime < request.StartTime) + startTime = request.StartTime; var result = await ExchangeData.GetKlinesAsync( request.Symbol.GetSymbol(FormatSymbol), interval, - fromTimestamp ?? request.StartTime, - request.EndTime, - request.Limit ?? 1000, + startTime, + endTime, + limit, ct: ct ).ConfigureAwait(false); if (!result) @@ -57,21 +69,21 @@ async Task>> IKlineRestClient.GetKlin // Get next token DateTimeToken? nextToken = null; - if (request.StartTime != null && result.Data.Any()) + if (result.Data.Count() == limit) { - var maxOpenTime = result.Data.Max(x => x.OpenTime); - if (maxOpenTime < request.EndTime!.Value.AddSeconds(-(int)request.Interval)) - nextToken = new DateTimeToken(maxOpenTime.AddSeconds((int)interval)); + var minOpenTime = result.Data.Min(x => x.OpenTime); + if (request.StartTime == null || minOpenTime > request.StartTime.Value) + nextToken = new DateTimeToken(minOpenTime.AddSeconds(-(int)interval)); } - return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)), nextToken); + return result.AsExchangeResult(Exchange, result.Data.Reverse().Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)), nextToken); } #endregion #region Mark Klines client - GetKlinesOptions IMarkPriceKlineRestClient.GetMarkPriceKlinesOptions { get; } = new GetKlinesOptions(true, false) + GetKlinesOptions IMarkPriceKlineRestClient.GetMarkPriceKlinesOptions { get; } = new GetKlinesOptions(SharedPaginationType.Descending, false) { MaxRequestDataPoints = 1000 }; @@ -334,7 +346,7 @@ async Task>> IFuturesOrderRest })); } - PaginatedEndpointOptions IFuturesOrderRestClient.GetClosedFuturesOrdersOptions { get; } = new PaginatedEndpointOptions(true, true); + PaginatedEndpointOptions IFuturesOrderRestClient.GetClosedFuturesOrdersOptions { get; } = new PaginatedEndpointOptions(SharedPaginationType.Descending, true); async Task>> IFuturesOrderRestClient.GetClosedFuturesOrdersAsync(GetClosedOrdersRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((IFuturesOrderRestClient)this).GetClosedFuturesOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); @@ -410,7 +422,7 @@ async Task>> IFuturesOrderRestCli })); } - PaginatedEndpointOptions IFuturesOrderRestClient.GetFuturesUserTradesOptions { get; } = new PaginatedEndpointOptions(true, true); + PaginatedEndpointOptions IFuturesOrderRestClient.GetFuturesUserTradesOptions { get; } = new PaginatedEndpointOptions(SharedPaginationType.Descending, true); async Task>> IFuturesOrderRestClient.GetFuturesUserTradesAsync(GetUserTradesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((IFuturesOrderRestClient)this).GetFuturesUserTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); @@ -614,7 +626,7 @@ async Task> IOrderBookRestClient.GetOrderBook #endregion #region Trade History client - GetTradeHistoryOptions ITradeHistoryRestClient.GetTradeHistoryOptions { get; } = new GetTradeHistoryOptions(true, false); + GetTradeHistoryOptions ITradeHistoryRestClient.GetTradeHistoryOptions { get; } = new GetTradeHistoryOptions(SharedPaginationType.Ascending, false); async Task>> ITradeHistoryRestClient.GetTradeHistoryAsync(GetTradeHistoryRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { @@ -648,7 +660,7 @@ async Task>> ITradeHistoryRestClient. #region Index Klines client - GetKlinesOptions IIndexPriceKlineRestClient.GetIndexPriceKlinesOptions { get; } = new GetKlinesOptions(true, false) + GetKlinesOptions IIndexPriceKlineRestClient.GetIndexPriceKlinesOptions { get; } = new GetKlinesOptions(SharedPaginationType.Descending, false) { MaxRequestDataPoints = 1000 }; diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs index b18715799..3d5d9cfa4 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs @@ -31,7 +31,7 @@ async Task> ITickerSocketClient.SubscribeToTi return new ExchangeResult(Exchange, validationError); var symbol = request.Symbol.GetSymbol(FormatSymbol); - var result = await SubscribeToTickerUpdatesAsync(symbol, update => handler(update.AsExchangeEvent(Exchange, new SharedSpotTicker(symbol, update.Data.LastPrice, update.Data.LowPrice, update.Data.HighPrice, update.Data.Volume))), ct: ct).ConfigureAwait(false); + var result = await SubscribeToTickerUpdatesAsync(symbol, update => handler(update.AsExchangeEvent(Exchange, new SharedSpotTicker(symbol, update.Data.LastPrice, update.Data.LowPrice, update.Data.HighPrice, update.Data.Volume, update.Data.PriceChangePercent))), ct: ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); } @@ -56,7 +56,7 @@ async Task> ITickersSocketClient.SubscribeToA if (!data.Any()) return; - handler(update.AsExchangeEvent(Exchange, data.Select(x => new SharedSpotTicker(x.Symbol, x.LastPrice, x.LowPrice, x.HighPrice, x.Volume)))); + handler(update.AsExchangeEvent(Exchange, data.Select(x => new SharedSpotTicker(x.Symbol, x.LastPrice, x.LowPrice, x.HighPrice, x.Volume, x.PriceChangePercent)))); }, ct: ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); From d6a3d0114c504a1d9e843b5359d1caa907294bec Mon Sep 17 00:00:00 2001 From: JKorf Date: Wed, 11 Sep 2024 21:55:44 +0200 Subject: [PATCH 34/54] wip --- .../BinanceRestClientCoinFuturesApiShared.cs | 1 - ...BinanceSocketClientCoinFuturesApiShared.cs | 2 +- .../SpotApi/BinanceRestClientSpotApiShared.cs | 37 +++++++++---------- .../BinanceSocketClientSpotApiShared.cs | 16 ++++---- .../BinanceRestClientUsdFuturesApiShared.cs | 1 - .../BinanceSocketClientUsdFuturesApiShared.cs | 2 +- 6 files changed, 29 insertions(+), 30 deletions(-) diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs index 35d210708..eae056eb4 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -498,7 +498,6 @@ private SharedOrderType ParseOrderType(FuturesOrderType type) if (tif == TimeInForce.GoodTillCanceled) return SharedTimeInForce.GoodTillCanceled; if (tif == TimeInForce.ImmediateOrCancel) return SharedTimeInForce.ImmediateOrCancel; if (tif == TimeInForce.FillOrKill) return SharedTimeInForce.FillOrKill; - if (tif == TimeInForce.GoodTillDate) return SharedTimeInForce.GoodTillDate; return null; } diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs index c35e1c309..9d065364a 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs @@ -222,7 +222,7 @@ async Task> IFuturesOrderSocketClient.Subscri AveragePrice = update.Data.UpdateData.AveragePrice, PositionSide = update.Data.UpdateData.PositionSide == Enums.PositionSide.Long ? SharedPositionSide.Long : update.Data.UpdateData.PositionSide == Enums.PositionSide.Short ? SharedPositionSide.Short : null, ReduceOnly = update.Data.UpdateData.IsReduce, - TimeInForce = update.Data.UpdateData.TimeInForce == Enums.TimeInForce.ImmediateOrCancel ? SharedTimeInForce.ImmediateOrCancel : update.Data.UpdateData.TimeInForce == Enums.TimeInForce.FillOrKill ? SharedTimeInForce.FillOrKill : update.Data.UpdateData.TimeInForce == Enums.TimeInForce.GoodTillDate ? SharedTimeInForce.GoodTillDate : SharedTimeInForce.GoodTillCanceled, + TimeInForce = update.Data.UpdateData.TimeInForce == Enums.TimeInForce.ImmediateOrCancel ? SharedTimeInForce.ImmediateOrCancel : update.Data.UpdateData.TimeInForce == Enums.TimeInForce.FillOrKill ? SharedTimeInForce.FillOrKill : SharedTimeInForce.GoodTillCanceled, LastTrade = update.Data.UpdateData.QuantityOfLastFilledTrade == 0 ? null : new SharedUserTrade(update.Data.UpdateData.Symbol, update.Data.UpdateData.OrderId.ToString(), update.Data.UpdateData.TradeId.ToString(), update.Data.UpdateData.QuantityOfLastFilledTrade, update.Data.UpdateData.PriceLastFilledTrade, update.Data.UpdateData.UpdateTime) { Role = update.Data.UpdateData.BuyerIsMaker ? SharedRole.Maker : SharedRole.Taker diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index d7ef065ee..176bfbea3 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -264,7 +264,8 @@ async Task> ISpotOrderRestClient.PlaceSpotOrderAsync quoteQuantity: request.QuoteQuantity, price: request.Price, timeInForce: GetTimeInForce(request.TimeInForce, request.OrderType), - newClientOrderId: request.ClientOrderId).ConfigureAwait(false); + newClientOrderId: request.ClientOrderId, + ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -282,7 +283,7 @@ async Task> ISpotOrderRestClient.GetSpotOrder if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); - var order = await Trading.GetOrderAsync(request.Symbol.GetSymbol(FormatSymbol), orderId).ConfigureAwait(false); + var order = await Trading.GetOrderAsync(request.Symbol.GetSymbol(FormatSymbol), orderId, ct: ct).ConfigureAwait(false); if (!order) return order.AsExchangeResult(Exchange, default); @@ -309,12 +310,12 @@ async Task> ISpotOrderRestClient.GetSpotOrder EndpointOptions ISpotOrderRestClient.GetOpenSpotOrdersOptions { get; } = new EndpointOptions(true); async Task>> ISpotOrderRestClient.GetOpenSpotOrdersAsync(GetOpenOrdersRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetOpenSpotOrdersOptions.ValidateRequest(Exchange, request,exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ISpotOrderRestClient)this).GetOpenSpotOrdersOptions.ValidateRequest(Exchange, request,exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); var symbol = request.Symbol?.GetSymbol(FormatSymbol); - var orders = await Trading.GetOpenOrdersAsync(symbol).ConfigureAwait(false); + var orders = await Trading.GetOpenOrdersAsync(symbol, ct: ct).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); @@ -355,7 +356,8 @@ async Task>> ISpotOrderRestClient orderId: fromId, startTime: request.StartTime, endTime: request.EndTime, - limit: request.Limit ?? 1000).ConfigureAwait(false); + limit: request.Limit ?? 1000, + ct: ct).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); @@ -394,7 +396,7 @@ async Task>> ISpotOrderRestClient if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult>(Exchange, new ArgumentError("Invalid order id")); - var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol(FormatSymbol), orderId: orderId).ConfigureAwait(false); + var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol(FormatSymbol), orderId: orderId, ct: ct).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); @@ -406,15 +408,13 @@ async Task>> ISpotOrderRestClient x.Price, x.Timestamp) { - Price = x.Price, - Quantity = x.Quantity, Fee = x.Fee, FeeAsset = x.FeeAsset, Role = x.IsMaker ? SharedRole.Maker : SharedRole.Taker }).ToArray()); } - PaginatedEndpointOptions ISpotOrderRestClient.GetSpotUserTradesOptions { get; } = new PaginatedEndpointOptions(SharedPaginationType.Descending, true); + PaginatedEndpointOptions ISpotOrderRestClient.GetSpotUserTradesOptions { get; } = new PaginatedEndpointOptions(SharedPaginationType.Ascending, true); async Task>> ISpotOrderRestClient.GetSpotUserTradesAsync(GetUserTradesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((ISpotOrderRestClient)this).GetSpotUserTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); @@ -431,7 +431,8 @@ async Task>> ISpotOrderRestClient startTime: request.StartTime, endTime: request.EndTime, limit: request.Limit ?? 500, - fromId: fromId + fromId: fromId, + ct: ct ).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); @@ -449,8 +450,6 @@ async Task>> ISpotOrderRestClient x.Price, x.Timestamp) { - Price = x.Price, - Quantity = x.Quantity, Fee = x.Fee, FeeAsset = x.FeeAsset, Role = x.IsMaker ? SharedRole.Maker : SharedRole.Taker @@ -467,7 +466,7 @@ async Task> ISpotOrderRestClient.CancelSpotOrderAsyn if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); - var order = await Trading.CancelOrderAsync(request.Symbol.GetSymbol(FormatSymbol), orderId).ConfigureAwait(false); + var order = await Trading.CancelOrderAsync(request.Symbol.GetSymbol(FormatSymbol), orderId, ct: ct).ConfigureAwait(false); if (!order) return order.AsExchangeResult(Exchange, default); @@ -505,7 +504,6 @@ private SharedOrderType ParseOrderType(SpotOrderType type) if (tif == TimeInForce.GoodTillCanceled) return SharedTimeInForce.GoodTillCanceled; if (tif == TimeInForce.ImmediateOrCancel) return SharedTimeInForce.ImmediateOrCancel; if (tif == TimeInForce.FillOrKill) return SharedTimeInForce.FillOrKill; - if (tif == TimeInForce.GoodTillDate) return SharedTimeInForce.GoodTillDate; return null; } @@ -536,7 +534,7 @@ async Task>> IAssetsRestClient.GetAss MinWithdrawQuantity = x.WithdrawMin, MaxWithdrawQuantity = x.WithdrawMax, WithdrawEnabled = x.WithdrawEnabled, - WithdrawFee = x.WithdrawFee + WithdrawFee = x.WithdrawFee, }) }).ToArray()); } @@ -583,7 +581,7 @@ async Task>> IDepositRestCli if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); - var depositAddresses = await Account.GetDepositAddressAsync(request.Asset, request.Network).ConfigureAwait(false); + var depositAddresses = await Account.GetDepositAddressAsync(request.Asset, request.Network, ct: ct).ConfigureAwait(false); if (!depositAddresses) return depositAddresses.AsExchangeResult>(Exchange, default); @@ -627,7 +625,8 @@ async Task>> IDepositRestClient.Get Confirmations = x.Confirmations.Contains("/") ? int.Parse(x.Confirmations.Split(new[] { "/" }, StringSplitOptions.RemoveEmptyEntries)[0]) : null, Network = x.Network, TransactionId = x.TransactionId, - Tag = x.AddressTag + Tag = x.AddressTag, + Id = x.Id }).ToArray(), nextToken); } @@ -669,7 +668,8 @@ async Task>> IWithdrawalRestClie Network = x.Network, Tag = x.AddressTag, TransactionId = x.TransactionId, - Fee = x.TransactionFee + Fee = x.TransactionFee, + Id = x.Id }).ToArray()); } @@ -678,7 +678,6 @@ async Task>> IWithdrawalRestClie #region Withdraw client WithdrawOptions IWithdrawRestClient.WithdrawOptions { get; } = new WithdrawOptions(); - async Task > IWithdrawRestClient.WithdrawAsync(WithdrawRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((IWithdrawRestClient)this).WithdrawOptions.ValidateRequest(Exchange, request, exchangeParameters, ApiType.Spot, SupportedApiTypes); diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs index 7fd9f0899..b2a65620b 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs @@ -106,18 +106,20 @@ async Task> IBalanceSocketClient.SubscribeToB #region Spot Order client - SubscriptionOptions ISpotOrderSocketClient.SubscribeSpotOrderOptions { get; } = new SubscriptionOptions("SubscribeSpotOrderRequest", false); + SubscriptionOptions ISpotOrderSocketClient.SubscribeSpotOrderOptions { get; } = new SubscriptionOptions("SubscribeSpotOrderRequest", false) + { + RequiredExchangeParameters = new List + { + new ParameterDescription("ListenKey", typeof(string), "Listenkey for the user stream", "123123123") + } + }; async Task> ISpotOrderSocketClient.SubscribeToSpotOrderUpdatesAsync(Action>> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((ISpotOrderSocketClient)this).SubscribeSpotOrderOptions.ValidateRequest(Exchange, exchangeParameters, ApiType.Spot, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); - var listenKey = await Account.StartUserStreamAsync().ConfigureAwait(false); - if (!listenKey) - return new ExchangeResult(Exchange, listenKey.As(default)); - - var result = await Account.SubscribeToUserDataUpdatesAsync(listenKey.Data.Result, + var result = await Account.SubscribeToUserDataUpdatesAsync(exchangeParameters.GetValue(Exchange, "ListenKey"), onOrderUpdateMessage: update => handler(update.AsExchangeEvent>(Exchange, new[] { new SharedSpotOrder( update.Data.Symbol, @@ -136,7 +138,7 @@ async Task> ISpotOrderSocketClient.SubscribeT UpdateTime = update.Data.UpdateTime, Fee = update.Data.Fee, FeeAsset = update.Data.FeeAsset, - TimeInForce = update.Data.TimeInForce == Enums.TimeInForce.ImmediateOrCancel ? SharedTimeInForce.ImmediateOrCancel : update.Data.TimeInForce == Enums.TimeInForce.FillOrKill ? SharedTimeInForce.FillOrKill : update.Data.TimeInForce == Enums.TimeInForce.GoodTillDate ? SharedTimeInForce.GoodTillDate : SharedTimeInForce.GoodTillCanceled, + TimeInForce = update.Data.TimeInForce == Enums.TimeInForce.ImmediateOrCancel ? SharedTimeInForce.ImmediateOrCancel : update.Data.TimeInForce == Enums.TimeInForce.FillOrKill ? SharedTimeInForce.FillOrKill : SharedTimeInForce.GoodTillCanceled, LastTrade = update.Data.LastQuantityFilled == 0 ? null : new SharedUserTrade(update.Data.Symbol, update.Data.Id.ToString(), update.Data.TradeId.ToString(), update.Data.LastQuantityFilled, update.Data.LastPriceFilled, update.Data.UpdateTime) { Role = update.Data.BuyerIsMaker ? SharedRole.Maker : SharedRole.Taker diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs index 42b2d8dea..76dfe9cb7 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -556,7 +556,6 @@ private SharedOrderType ParseOrderType(FuturesOrderType type) if (tif == TimeInForce.GoodTillCanceled) return SharedTimeInForce.GoodTillCanceled; if (tif == TimeInForce.ImmediateOrCancel) return SharedTimeInForce.ImmediateOrCancel; if (tif == TimeInForce.FillOrKill) return SharedTimeInForce.FillOrKill; - if (tif == TimeInForce.GoodTillDate) return SharedTimeInForce.GoodTillDate; return null; } diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs index 3d5d9cfa4..9c9cf9baa 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs @@ -159,7 +159,7 @@ async Task> IFuturesOrderSocketClient.Subscri AveragePrice = update.Data.UpdateData.AveragePrice, PositionSide = update.Data.UpdateData.PositionSide == Enums.PositionSide.Long ? SharedPositionSide.Long : update.Data.UpdateData.PositionSide == Enums.PositionSide.Short ? SharedPositionSide.Short : null, ReduceOnly = update.Data.UpdateData.IsReduce, - TimeInForce = update.Data.UpdateData.TimeInForce == Enums.TimeInForce.ImmediateOrCancel ? SharedTimeInForce.ImmediateOrCancel : update.Data.UpdateData.TimeInForce == Enums.TimeInForce.FillOrKill ? SharedTimeInForce.FillOrKill : update.Data.UpdateData.TimeInForce == Enums.TimeInForce.GoodTillDate ? SharedTimeInForce.GoodTillDate : SharedTimeInForce.GoodTillCanceled, + TimeInForce = update.Data.UpdateData.TimeInForce == Enums.TimeInForce.ImmediateOrCancel ? SharedTimeInForce.ImmediateOrCancel : update.Data.UpdateData.TimeInForce == Enums.TimeInForce.FillOrKill ? SharedTimeInForce.FillOrKill : SharedTimeInForce.GoodTillCanceled, LastTrade = update.Data.UpdateData.QuantityOfLastFilledTrade == 0 ? null : new SharedUserTrade(update.Data.UpdateData.Symbol, update.Data.UpdateData.OrderId.ToString(), update.Data.UpdateData.TradeId.ToString(), update.Data.UpdateData.QuantityOfLastFilledTrade, update.Data.UpdateData.PriceLastFilledTrade, update.Data.UpdateData.UpdateTime) { Role = update.Data.UpdateData.BuyerIsMaker ? SharedRole.Maker : SharedRole.Taker From dc0d830cf920230ccaedd362a4b130f48c3e6f8a Mon Sep 17 00:00:00 2001 From: Jkorf Date: Thu, 12 Sep 2024 16:39:34 +0200 Subject: [PATCH 35/54] wip --- .../BinanceRestClientCoinFuturesApiShared.cs | 85 ++++--- ...BinanceSocketClientCoinFuturesApiShared.cs | 8 +- .../SpotApi/BinanceRestClientSpotApiShared.cs | 8 +- .../BinanceSocketClientSpotApiShared.cs | 18 +- .../BinanceRestClientUsdFuturesApiShared.cs | 233 ++++++++++-------- .../BinanceSocketClientUsdFuturesApiShared.cs | 8 +- 6 files changed, 203 insertions(+), 157 deletions(-) diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs index eae056eb4..82932754d 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -73,17 +73,17 @@ async Task>> IKlineRestClient.GetKlin nextToken = new DateTimeToken(minOpenTime.AddSeconds(-(int)interval)); } - return result.AsExchangeResult(Exchange, result.Data.Reverse().Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)), nextToken); + return result.AsExchangeResult>(Exchange, result.Data.Reverse().Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)).ToArray(), nextToken); } #endregion #region Futures Symbol client - EndpointOptions IFuturesSymbolRestClient.GetFuturesSymbolsOptions { get; } = new EndpointOptions("GetFuturesSymbolsRequest", false); - async Task>> IFuturesSymbolRestClient.GetFuturesSymbolsAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + EndpointOptions IFuturesSymbolRestClient.GetFuturesSymbolsOptions { get; } = new EndpointOptions(false); + async Task>> IFuturesSymbolRestClient.GetFuturesSymbolsAsync(GetFuturesSymbolsRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesSymbolRestClient)this).GetFuturesSymbolsOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); + var validationError = ((IFuturesSymbolRestClient)this).GetFuturesSymbolsOptions.ValidateRequest(Exchange, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -92,8 +92,8 @@ async Task>> IFuturesSymbolRe return result.AsExchangeResult>(Exchange, default); var data = result.Data.Symbols.Where(x => x.ContractType != null); - if (apiType != null) - data = data.Where(x => apiType == ApiType.PerpetualInverse ? x.ContractType == ContractType.Perpetual : (x.ContractType != ContractType.Perpetual && x.ContractType != ContractType.PerpetualDelivering)); + if (request.ApiType != null) + data = data.Where(x => request.ApiType == ApiType.PerpetualInverse ? x.ContractType == ContractType.Perpetual : (x.ContractType != ContractType.Perpetual && x.ContractType != ContractType.PerpetualDelivering)); return result.AsExchangeResult>(Exchange, data.Select(s => new SharedFuturesSymbol(s.ContractType == ContractType.Perpetual ? SharedSymbolType.PerpetualInverse : SharedSymbolType.DeliveryInverse, s.BaseAsset, s.QuoteAsset, s.Name, s.Status == SymbolStatus.Trading) { MinTradeQuantity = s.LotSizeFilter?.MinQuantity, @@ -130,7 +130,7 @@ async Task> IFuturesTickerRestClient.GetF if (ticker == null || mark == null) return resultTicker.Result.AsExchangeError(Exchange, new ServerError("Not found")); - return resultTicker.Result.AsExchangeResult(Exchange, new SharedFuturesTicker(ticker.Symbol, ticker.LastPrice, ticker.HighPrice, ticker.LowPrice, ticker.Volume) + return resultTicker.Result.AsExchangeResult(Exchange, new SharedFuturesTicker(ticker.Symbol, ticker.LastPrice, ticker.HighPrice, ticker.LowPrice, ticker.Volume, ticker.PriceChangePercent) { IndexPrice = mark.IndexPrice, MarkPrice = mark.MarkPrice, @@ -139,10 +139,10 @@ async Task> IFuturesTickerRestClient.GetF }); } - EndpointOptions IFuturesTickerRestClient.GetFuturesTickersOptions { get; } = new EndpointOptions("GetTickersRequest", false); - async Task>> IFuturesTickerRestClient.GetFuturesTickersAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + EndpointOptions IFuturesTickerRestClient.GetFuturesTickersOptions { get; } = new EndpointOptions(false); + async Task>> IFuturesTickerRestClient.GetFuturesTickersAsync(GetTickersRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickerOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); + var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickerOptions.ValidateRequest(Exchange, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -157,14 +157,14 @@ async Task>> IFuturesTickerRe return resultTickers.Result.AsExchangeResult>(Exchange, resultTickers.Result.Data.Select(x => { var markPrice = resultMarkPrices.Result.Data.Single(p => p.Symbol == x.Symbol); - return new SharedFuturesTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume) + return new SharedFuturesTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume, x.PriceChangePercent) { IndexPrice = markPrice.IndexPrice, MarkPrice = markPrice.MarkPrice, FundingRate = markPrice.FundingRate, NextFundingTime = markPrice.NextFundingTime }; - })); + }).ToArray()); } #endregion @@ -185,7 +185,7 @@ async Task>> IRecentTradeRestClient.G if (!result) return result.AsExchangeResult>(Exchange, default); - return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedTrade(x.BaseQuantity, x.Price, x.TradeTime))); + return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedTrade(x.BaseQuantity, x.Price, x.TradeTime)).ToArray()); } #endregion @@ -224,7 +224,8 @@ async Task> IFuturesOrderRestClient.PlaceFuturesOrde price: request.Price, positionSide: request.PositionSide == null ? null : request.PositionSide == SharedPositionSide.Long ? PositionSide.Long: PositionSide.Short, reduceOnly: request.ReduceOnly, - newClientOrderId: request.ClientOrderId).ConfigureAwait(false); + newClientOrderId: request.ClientOrderId, + ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -242,7 +243,7 @@ async Task> IFuturesOrderRestClient.GetFut if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); - var order = await Trading.GetOrderAsync(request.Symbol.GetSymbol(FormatSymbol), orderId).ConfigureAwait(false); + var order = await Trading.GetOrderAsync(request.Symbol.GetSymbol(FormatSymbol), orderId, ct: ct).ConfigureAwait(false); if (!order) return order.AsExchangeResult(Exchange, default); @@ -270,16 +271,16 @@ async Task> IFuturesOrderRestClient.GetFut EndpointOptions IFuturesOrderRestClient.GetOpenFuturesOrdersOptions { get; } = new EndpointOptions(true); async Task>> IFuturesOrderRestClient.GetOpenFuturesOrdersAsync(GetOpenOrdersRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetOpenFuturesOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetOpenFuturesOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol?.ApiType ?? request.ApiType!.Value, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); var symbol = request.Symbol?.GetSymbol(FormatSymbol); - var orders = await Trading.GetOpenOrdersAsync(symbol).ConfigureAwait(false); + var orders = await Trading.GetOpenOrdersAsync(symbol, ct: ct).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); - return orders.AsExchangeResult(Exchange, orders.Data.Select(x => new SharedFuturesOrder( + return orders.AsExchangeResult>(Exchange, orders.Data.Select(x => new SharedFuturesOrder( x.Symbol, x.Id.ToString(), ParseOrderType(x.Type), @@ -297,7 +298,7 @@ async Task>> IFuturesOrderRest UpdateTime = x.UpdateTime, PositionSide = x.PositionSide == PositionSide.Both ? null : x.PositionSide == PositionSide.Long ? SharedPositionSide.Long : SharedPositionSide.Short, ReduceOnly = x.ReduceOnly - })); + }).ToArray()); } PaginatedEndpointOptions IFuturesOrderRestClient.GetClosedFuturesOrdersOptions { get; } = new PaginatedEndpointOptions(SharedPaginationType.Descending, true); @@ -316,7 +317,8 @@ async Task>> IFuturesOrderRest var orders = await Trading.GetOrdersAsync(request.Symbol.GetSymbol(FormatSymbol), startTime: fromTimestamp ?? request.StartTime, endTime: request.EndTime, - limit: request.Limit ?? 1000).ConfigureAwait(false); + limit: request.Limit ?? 1000, + ct: ct).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); @@ -325,7 +327,7 @@ async Task>> IFuturesOrderRest if (orders.Data.Count() == (request.Limit ?? 1000)) nextToken = new DateTimeToken(orders.Data.Max(o => o.CreateTime)); - return orders.AsExchangeResult(Exchange, orders.Data.Where(x => x.Status == OrderStatus.Filled || x.Status == OrderStatus.Canceled || x.Status == OrderStatus.Expired).Select(x => new SharedFuturesOrder( + return orders.AsExchangeResult>(Exchange, orders.Data.Where(x => x.Status == OrderStatus.Filled || x.Status == OrderStatus.Canceled || x.Status == OrderStatus.Expired).Select(x => new SharedFuturesOrder( x.Symbol, x.Id.ToString(), ParseOrderType(x.Type), @@ -343,7 +345,7 @@ async Task>> IFuturesOrderRest UpdateTime = x.UpdateTime, PositionSide = x.PositionSide == PositionSide.Both ? null : x.PositionSide == PositionSide.Long ? SharedPositionSide.Long : SharedPositionSide.Short, ReduceOnly = x.ReduceOnly - })); + }).ToArray()); } EndpointOptions IFuturesOrderRestClient.GetFuturesOrderTradesOptions { get; } = new EndpointOptions(true); @@ -356,11 +358,11 @@ async Task>> IFuturesOrderRestCli if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult>(Exchange, new ArgumentError("Invalid order id")); - var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol(FormatSymbol), orderId: orderId).ConfigureAwait(false); + var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol(FormatSymbol), orderId: orderId, ct: ct).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); - return orders.AsExchangeResult(Exchange, orders.Data.Select(x => new SharedUserTrade( + return orders.AsExchangeResult>(Exchange, orders.Data.Select(x => new SharedUserTrade( x.Symbol, x.OrderId.ToString(), x.Id.ToString(), @@ -373,7 +375,7 @@ async Task>> IFuturesOrderRestCli Fee = x.Fee, FeeAsset = x.FeeAsset, Role = x.Maker ? SharedRole.Maker : SharedRole.Taker - })); + }).ToArray()); } PaginatedEndpointOptions IFuturesOrderRestClient.GetFuturesUserTradesOptions { get; } = new PaginatedEndpointOptions(SharedPaginationType.Descending, true); @@ -393,7 +395,8 @@ async Task>> IFuturesOrderRestCli startTime: request.StartTime, endTime: request.EndTime, limit: request.Limit ?? 500, - fromId: fromId + fromId: fromId, + ct: ct ).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); @@ -403,7 +406,7 @@ async Task>> IFuturesOrderRestCli if (orders.Data.Count() == (request.Limit ?? 500)) nextToken = new FromIdToken(orders.Data.Max(o => o.Id).ToString()); - return orders.AsExchangeResult(Exchange, orders.Data.Select(x => new SharedUserTrade( + return orders.AsExchangeResult>(Exchange, orders.Data.Select(x => new SharedUserTrade( x.Symbol, x.OrderId.ToString(), x.Id.ToString(), @@ -416,7 +419,7 @@ async Task>> IFuturesOrderRestCli Fee = x.Fee, FeeAsset = x.FeeAsset, Role = x.Maker ? SharedRole.Maker : SharedRole.Taker - }), nextToken); + }).ToArray(), nextToken); } EndpointOptions IFuturesOrderRestClient.CancelFuturesOrderOptions { get; } = new EndpointOptions(true); @@ -439,7 +442,7 @@ async Task> IFuturesOrderRestClient.CancelFuturesOrd EndpointOptions IFuturesOrderRestClient.GetPositionsOptions { get; } = new EndpointOptions(true); async Task>> IFuturesOrderRestClient.GetPositionsAsync(GetPositionsRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetPositionsOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetPositionsOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol?.ApiType ?? request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -454,7 +457,7 @@ async Task>> IFuturesOrderRestClie Leverage = x.Leverage, AverageEntryPrice = x.EntryPrice, PositionSide = x.PositionSide == PositionSide.Both ? (x.Quantity > 0 ? SharedPositionSide.Long : SharedPositionSide.Short) : x.PositionSide == PositionSide.Short ? SharedPositionSide.Short : SharedPositionSide.Long - }).ToList()); + }).ToArray()); } EndpointOptions IFuturesOrderRestClient.ClosePositionOptions { get; } = new EndpointOptions(true); @@ -588,7 +591,7 @@ async Task>> IMarkPriceKlineRestC nextToken = new DateTimeToken(maxOpenTime.AddSeconds((int)interval)); } - return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedMarkKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)), nextToken); + return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedMarkKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)).ToArray(), nextToken); } #endregion @@ -642,7 +645,7 @@ async Task>> ITradeHistoryRestClient. nextToken = new FromIdToken(result.Data.Max(x => x.Id).ToString()); // Return - return result.AsExchangeResult(Exchange, result.Data.Where(x => x.TradeTime < request.EndTime).Select(x => new SharedTrade(x.Quantity, x.Price, x.TradeTime)), nextToken); + return result.AsExchangeResult>(Exchange, result.Data.Where(x => x.TradeTime < request.EndTime).Select(x => new SharedTrade(x.Quantity, x.Price, x.TradeTime)).ToArray(), nextToken); } #endregion @@ -688,7 +691,7 @@ async Task>> IIndexPriceKlineRest nextToken = new DateTimeToken(maxOpenTime.AddSeconds((int)interval)); } - return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedMarkKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)), nextToken); + return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedMarkKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)).ToArray(), nextToken); } #endregion @@ -712,7 +715,7 @@ async Task> IOpenInterestRestClient.GetOpe #endregion #region Funding Rate client - GetFundingRateHistoryOptions IFundingRateRestClient.GetFundingRateHistoryOptions { get; } = new GetFundingRateHistoryOptions(true, false); + GetFundingRateHistoryOptions IFundingRateRestClient.GetFundingRateHistoryOptions { get; } = new GetFundingRateHistoryOptions(SharedPaginationType.Ascending, false); async Task>> IFundingRateRestClient.GetFundingRateHistoryAsync(GetFundingRateHistoryRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { @@ -739,16 +742,16 @@ async Task>> IFundingRateRestCl nextToken = new DateTimeToken(result.Data.Max(x => x.FundingTime)); // Return - return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedFundingRate(x.FundingRate, x.FundingTime)), nextToken); + return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedFundingRate(x.FundingRate, x.FundingTime)).ToArray(), nextToken); } #endregion #region Balance Client - EndpointOptions IBalanceRestClient.GetBalancesOptions { get; } = new EndpointOptions("GetBalancesRequest", true); + EndpointOptions IBalanceRestClient.GetBalancesOptions { get; } = new EndpointOptions(true); - async Task>> IBalanceRestClient.GetBalancesAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IBalanceRestClient.GetBalancesAsync(GetBalancesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IBalanceRestClient)this).GetBalancesOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); + var validationError = ((IBalanceRestClient)this).GetBalancesOptions.ValidateRequest(Exchange, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -756,7 +759,7 @@ async Task>> IBalanceRestClient.Get if (!result) return result.AsExchangeResult>(Exchange, default); - return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedBalance(x.Asset, x.AvailableBalance, x.WalletBalance))); + return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedBalance(x.Asset, x.AvailableBalance, x.WalletBalance)).ToArray()); } #endregion @@ -766,7 +769,7 @@ async Task>> IBalanceRestClient.Get GetPositionModeOptions IPositionModeRestClient.GetPositionModeOptions { get; } = new GetPositionModeOptions(false); async Task> IPositionModeRestClient.GetPositionModeAsync(GetPositionModeRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IPositionModeRestClient)this).GetPositionModeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IPositionModeRestClient)this).GetPositionModeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol?.ApiType ?? request.ApiType!.Value, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -780,7 +783,7 @@ async Task> IPositionModeRestClient. SetPositionModeOptions IPositionModeRestClient.SetPositionModeOptions { get; } = new SetPositionModeOptions(true, true, false); async Task> IPositionModeRestClient.SetPositionModeAsync(SetPositionModeRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IPositionModeRestClient)this).SetPositionModeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IPositionModeRestClient)this).SetPositionModeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol?.ApiType ?? request.ApiType!.Value, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs index 9d065364a..8bde6af0c 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs @@ -56,7 +56,7 @@ async Task> ITickersSocketClient.SubscribeToA if (!data.Any()) return; - handler(update.AsExchangeEvent(Exchange, data.Select(x => new SharedSpotTicker(x.Symbol, x.LastPrice, x.LowPrice, x.HighPrice, x.Volume, x.PriceChangePercent)))); + handler(update.AsExchangeEvent>(Exchange, data.Select(x => new SharedSpotTicker(x.Symbol, x.LastPrice, x.LowPrice, x.HighPrice, x.Volume, x.PriceChangePercent)).ToArray())); }, ct: ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -149,7 +149,7 @@ async Task> IBalanceSocketClient.SubscribeToB var listenKey = exchangeParameters.GetValue(Exchange, "ListenKey"); var result = await SubscribeToUserDataUpdatesAsync(listenKey!, #warning correct? - onAccountUpdate: update => handler(update.AsExchangeEvent(Exchange, update.Data.UpdateData.Balances.Select(x => new SharedBalance(x.Asset, x.WalletBalance, x.WalletBalance + x.CrossWalletBalance)))), + onAccountUpdate: update => handler(update.AsExchangeEvent>(Exchange, update.Data.UpdateData.Balances.Select(x => new SharedBalance(x.Asset, x.WalletBalance, x.WalletBalance + x.CrossWalletBalance)).ToArray())), ct: ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -173,12 +173,12 @@ async Task> IPositionSocketClient.SubscribeTo var listenKey = exchangeParameters.GetValue(Exchange, "ListenKey"); var result = await SubscribeToUserDataUpdatesAsync(listenKey!, - onAccountUpdate: update => handler(update.AsExchangeEvent(Exchange, update.Data.UpdateData.Positions.Select(x => new SharedPosition(x.Symbol, x.Quantity, update.Data.EventTime) + onAccountUpdate: update => handler(update.AsExchangeEvent>(Exchange, update.Data.UpdateData.Positions.Select(x => new SharedPosition(x.Symbol, x.Quantity, update.Data.EventTime) { AverageEntryPrice = x.EntryPrice, PositionSide = x.PositionSide == Enums.PositionSide.Both ? (x.Quantity > 0 ? SharedPositionSide.Long : SharedPositionSide.Short) : x.PositionSide == Enums.PositionSide.Short ? SharedPositionSide.Short : SharedPositionSide.Long, UnrealizedPnl = x.UnrealizedPnl - }))), + }).ToArray())), ct: ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index 176bfbea3..4fbe6ea2f 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -212,11 +212,11 @@ async Task> IOrderBookRestClient.GetOrderBook #endregion #region Balance Client - EndpointOptions IBalanceRestClient.GetBalancesOptions { get; } = new EndpointOptions("GetBalancesRequest", true); + EndpointOptions IBalanceRestClient.GetBalancesOptions { get; } = new EndpointOptions(true); - async Task>> IBalanceRestClient.GetBalancesAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IBalanceRestClient.GetBalancesAsync(GetBalancesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IBalanceRestClient)this).GetBalancesOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); + var validationError = ((IBalanceRestClient)this).GetBalancesOptions.ValidateRequest(Exchange, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -310,7 +310,7 @@ async Task> ISpotOrderRestClient.GetSpotOrder EndpointOptions ISpotOrderRestClient.GetOpenSpotOrdersOptions { get; } = new EndpointOptions(true); async Task>> ISpotOrderRestClient.GetOpenSpotOrdersAsync(GetOpenOrdersRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetOpenSpotOrdersOptions.ValidateRequest(Exchange, request,exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((ISpotOrderRestClient)this).GetOpenSpotOrdersOptions.ValidateRequest(Exchange, request,exchangeParameters, request.Symbol?.ApiType ?? request.ApiType!.Value, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs index b2a65620b..a9f8c4cfa 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs @@ -27,7 +27,7 @@ async Task> ITickersSocketClient.SubscribeToA if (validationError != null) return new ExchangeResult(Exchange, validationError); - var result = await ExchangeData.SubscribeToAllTickerUpdatesAsync(update => handler(update.AsExchangeEvent(Exchange, update.Data.Select(x => new SharedSpotTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume, x.PriceChangePercent)))), ct).ConfigureAwait(false); + var result = await ExchangeData.SubscribeToAllTickerUpdatesAsync(update => handler(update.AsExchangeEvent>(Exchange, update.Data.Select(x => new SharedSpotTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume, x.PriceChangePercent)).ToArray())), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); } @@ -84,19 +84,21 @@ async Task> IBookTickerSocketClient.Subscribe #endregion #region Balance client - SubscriptionOptions IBalanceSocketClient.SubscribeBalanceOptions { get; } = new SubscriptionOptions("SubscribeBalanceRequest", false); + SubscriptionOptions IBalanceSocketClient.SubscribeBalanceOptions { get; } = new SubscriptionOptions("SubscribeBalanceRequest", false) + { + RequiredExchangeParameters = new List + { + new ParameterDescription("ListenKey", typeof(string), "Listenkey for the user stream", "123123123") + } + }; async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(Action>> handler, ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); - var listenKey = await Account.StartUserStreamAsync().ConfigureAwait(false); - if (!listenKey) - return new ExchangeResult(Exchange, listenKey.As(default)); - - var result = await Account.SubscribeToUserDataUpdatesAsync(listenKey.Data.Result, - onAccountPositionMessage: update => handler(update.AsExchangeEvent(Exchange, update.Data.Balances.Select(x => new SharedBalance(x.Asset, x.Available, x.Total)))), + var result = await Account.SubscribeToUserDataUpdatesAsync(exchangeParameters.GetValue(Exchange, "ListenKey"), + onAccountPositionMessage: update => handler(update.AsExchangeEvent>(Exchange, update.Data.Balances.Select(x => new SharedBalance(x.Asset, x.Available, x.Total)).ToArray())), ct: ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs index 76dfe9cb7..609877e95 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -65,7 +65,7 @@ async Task>> IKlineRestClient.GetKlin ct: ct ).ConfigureAwait(false); if (!result) - return result.AsExchangeResult< IEnumerable>(Exchange, default); + return result.AsExchangeResult>(Exchange, default); // Get next token DateTimeToken? nextToken = null; @@ -73,10 +73,10 @@ async Task>> IKlineRestClient.GetKlin { var minOpenTime = result.Data.Min(x => x.OpenTime); if (request.StartTime == null || minOpenTime > request.StartTime.Value) - nextToken = new DateTimeToken(minOpenTime.AddSeconds(-(int)interval)); + nextToken = new DateTimeToken(minOpenTime.AddSeconds(-(int)(interval - 1))); } - return result.AsExchangeResult(Exchange, result.Data.Reverse().Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)), nextToken); + return result.AsExchangeResult>(Exchange, result.Data.Reverse().Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)).ToArray(), nextToken); } #endregion @@ -98,17 +98,29 @@ async Task>> IMarkPriceKlineRestC if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); - // Determine page token - DateTime? fromTimestamp = null; + // Determine pagination + // Data is normally returned oldest first, so to do newest first pagination we have to do some calc + DateTime endTime = request.EndTime ?? DateTime.UtcNow; + DateTime? startTime = request.StartTime; if (pageToken is DateTimeToken dateTimeToken) - fromTimestamp = dateTimeToken.LastTime; + endTime = dateTimeToken.LastTime; + + var limit = request.Limit ?? 1000; + if (startTime == null || startTime < endTime) + { + var offset = (int)interval * limit; + startTime = endTime.AddSeconds(-offset); + } + + if (startTime < request.StartTime) + startTime = request.StartTime; var result = await ExchangeData.GetMarkPriceKlinesAsync( request.Symbol.GetSymbol(FormatSymbol), interval, - request.Limit ?? 1000, - fromTimestamp ?? request.StartTime, - request.EndTime, + limit, + startTime, + endTime, ct: ct ).ConfigureAwait(false); if (!result) @@ -116,24 +128,24 @@ async Task>> IMarkPriceKlineRestC // Get next token DateTimeToken? nextToken = null; - if (request.StartTime != null && result.Data.Any()) + if (result.Data.Count() == limit) { - var maxOpenTime = result.Data.Max(x => x.OpenTime); - if (maxOpenTime < request.EndTime!.Value.AddSeconds(-(int)request.Interval)) - nextToken = new DateTimeToken(maxOpenTime.AddSeconds((int)interval)); + var minOpenTime = result.Data.Min(x => x.OpenTime); + if (request.StartTime == null || minOpenTime > request.StartTime.Value) + nextToken = new DateTimeToken(minOpenTime.AddSeconds(-(int)(interval - 1))); } - return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedMarkKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)), nextToken); + return result.AsExchangeResult>(Exchange, result.Data.Reverse().Select(x => new SharedMarkKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)).ToArray(), nextToken); } #endregion #region Futures Symbol client - EndpointOptions IFuturesSymbolRestClient.GetFuturesSymbolsOptions { get; } = new EndpointOptions("GetFuturesSymbolsRequest", false); - async Task>> IFuturesSymbolRestClient.GetFuturesSymbolsAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + EndpointOptions IFuturesSymbolRestClient.GetFuturesSymbolsOptions { get; } = new EndpointOptions(false); + async Task>> IFuturesSymbolRestClient.GetFuturesSymbolsAsync(GetFuturesSymbolsRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesSymbolRestClient)this).GetFuturesSymbolsOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); + var validationError = ((IFuturesSymbolRestClient)this).GetFuturesSymbolsOptions.ValidateRequest(Exchange, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -142,8 +154,8 @@ async Task>> IFuturesSymbolRe return result.AsExchangeResult< IEnumerable>(Exchange, default); var data = result.Data.Symbols.Where(x => x.ContractType != null); - if (apiType != null) - data = data.Where(x => apiType == ApiType.PerpetualLinear ? x.ContractType == ContractType.Perpetual : (x.ContractType != ContractType.Perpetual && x.ContractType != ContractType.PerpetualDelivering)); + if (request.ApiType != null) + data = data.Where(x => request.ApiType == ApiType.PerpetualLinear ? x.ContractType == ContractType.Perpetual : (x.ContractType != ContractType.Perpetual && x.ContractType != ContractType.PerpetualDelivering)); return result.AsExchangeResult>(Exchange, data.Select(s => new SharedFuturesSymbol(s.ContractType == ContractType.Perpetual ? SharedSymbolType.PerpetualLinear : SharedSymbolType.DeliveryLinear, s.BaseAsset, s.QuoteAsset, s.Name, s.Status == SymbolStatus.Trading) { MinTradeQuantity = s.LotSizeFilter?.MinQuantity, @@ -175,19 +187,19 @@ async Task> IFuturesTickerRestClient.GetF if (!resultMarkPrice.Result) return resultMarkPrice.Result.AsExchangeResult(Exchange, default); - return resultTicker.Result.AsExchangeResult(Exchange, new SharedFuturesTicker(resultTicker.Result.Data.Symbol, resultTicker.Result.Data.LastPrice, resultTicker.Result.Data.HighPrice, resultTicker.Result.Data.LowPrice, resultTicker.Result.Data.Volume) + return resultTicker.Result.AsExchangeResult(Exchange, new SharedFuturesTicker(resultTicker.Result.Data.Symbol, resultTicker.Result.Data.LastPrice, resultTicker.Result.Data.HighPrice, resultTicker.Result.Data.LowPrice, resultTicker.Result.Data.Volume, resultTicker.Result.Data.PriceChangePercent) { MarkPrice = resultMarkPrice.Result.Data.MarkPrice, IndexPrice = resultMarkPrice.Result.Data.IndexPrice, FundingRate = resultMarkPrice.Result.Data.FundingRate, - NextFundingTime = resultMarkPrice.Result.Data.NextFundingTime + NextFundingTime = resultMarkPrice.Result.Data.NextFundingTime == default ? null : resultMarkPrice.Result.Data.NextFundingTime }); } - EndpointOptions IFuturesTickerRestClient.GetFuturesTickersOptions { get; } = new EndpointOptions("GetTickersRequest", false); - async Task>> IFuturesTickerRestClient.GetFuturesTickersAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + EndpointOptions IFuturesTickerRestClient.GetFuturesTickersOptions { get; } = new EndpointOptions(false); + async Task>> IFuturesTickerRestClient.GetFuturesTickersAsync(GetTickersRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickerOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); + var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickerOptions.ValidateRequest(Exchange, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -199,17 +211,21 @@ async Task>> IFuturesTickerRe if (!resultMarkPrices.Result) return resultMarkPrices.Result.AsExchangeResult>(Exchange, default); - return resultTickers.Result.AsExchangeResult>(Exchange, resultTickers.Result.Data.Select(x => + var data = resultTickers.Result.Data; + if (request.ApiType.HasValue) + data = data.Where(x => (request.ApiType == ApiType.DeliveryLinear ? x.Symbol.Contains("_") : !x.Symbol.Contains("_"))); + + return resultTickers.Result.AsExchangeResult>(Exchange, data.Select(x => { var markPrice = resultMarkPrices.Result.Data.Single(p => p.Symbol == x.Symbol); - return new SharedFuturesTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume) + return new SharedFuturesTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume, x.PriceChangePercent) { IndexPrice = markPrice.IndexPrice, MarkPrice = markPrice.MarkPrice, FundingRate = markPrice.FundingRate, - NextFundingTime = markPrice.NextFundingTime + NextFundingTime = markPrice.NextFundingTime == default ? null : markPrice.NextFundingTime }; - })); + }).ToArray()); } #endregion @@ -224,13 +240,13 @@ async Task>> IRecentTradeRestClient.G return new ExchangeWebResult>(Exchange, validationError); var result = await ExchangeData.GetRecentTradesAsync( - request.Symbol.GetSymbol(FormatSymbol), // Don't pass api type; need only the pair + request.Symbol.GetSymbol(FormatSymbol), limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult< IEnumerable>(Exchange, default); + return result.AsExchangeResult>(Exchange, default); - return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedTrade(x.BaseQuantity, x.Price, x.TradeTime))); + return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedTrade(x.BaseQuantity, x.Price, x.TradeTime)).ToArray()); } #endregion @@ -269,8 +285,9 @@ async Task> IFuturesOrderRestClient.PlaceFuturesOrde price: request.Price, positionSide: request.PositionSide == null ? null : request.PositionSide == SharedPositionSide.Long ? PositionSide.Long : PositionSide.Short, reduceOnly: request.ReduceOnly, - timeInForce: GetTimeInForce(request.TimeInForce), - newClientOrderId: request.ClientOrderId).ConfigureAwait(false); + timeInForce: GetTimeInForce(request.OrderType, request.TimeInForce), + newClientOrderId: request.ClientOrderId, + ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -288,7 +305,7 @@ async Task> IFuturesOrderRestClient.GetFut if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); - var order = await Trading.GetOrderAsync(request.Symbol.GetSymbol(FormatSymbol), orderId).ConfigureAwait(false); + var order = await Trading.GetOrderAsync(request.Symbol.GetSymbol(FormatSymbol), orderId, ct: ct).ConfigureAwait(false); if (!order) return order.AsExchangeResult(Exchange, default); @@ -301,8 +318,8 @@ async Task> IFuturesOrderRestClient.GetFut order.Data.CreateTime) { ClientOrderId = order.Data.ClientOrderId, - AveragePrice = order.Data.AveragePrice, - Price = order.Data.Price, + AveragePrice = order.Data.AveragePrice == 0 ? null : order.Data.AveragePrice, + Price = order.Data.Price == 0 ? null : order.Data.Price, Quantity = order.Data.Quantity, QuantityFilled = order.Data.QuantityFilled, QuoteQuantityFilled = order.Data.QuoteQuantityFilled, @@ -316,16 +333,16 @@ async Task> IFuturesOrderRestClient.GetFut EndpointOptions IFuturesOrderRestClient.GetOpenFuturesOrdersOptions { get; } = new EndpointOptions(true); async Task>> IFuturesOrderRestClient.GetOpenFuturesOrdersAsync(GetOpenOrdersRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetOpenFuturesOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetOpenFuturesOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol?.ApiType ?? request.ApiType!.Value, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); var symbol = request.Symbol?.GetSymbol(FormatSymbol); - var orders = await Trading.GetOpenOrdersAsync(symbol).ConfigureAwait(false); + var orders = await Trading.GetOpenOrdersAsync(symbol, ct: ct).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); - return orders.AsExchangeResult(Exchange, orders.Data.Select(x => new SharedFuturesOrder( + return orders.AsExchangeResult>(Exchange, orders.Data.Select(x => new SharedFuturesOrder( x.Symbol, x.Id.ToString(), ParseOrderType(x.Type), @@ -334,8 +351,8 @@ async Task>> IFuturesOrderRest x.CreateTime) { ClientOrderId = x.ClientOrderId, - AveragePrice = x.AveragePrice, - Price = x.Price, + AveragePrice = x.AveragePrice == 0 ? null : x.AveragePrice, + Price = x.Price == 0 ? null : x.Price, Quantity = x.Quantity, QuantityFilled = x.QuantityFilled, QuoteQuantityFilled = x.QuoteQuantityFilled, @@ -343,7 +360,7 @@ async Task>> IFuturesOrderRest UpdateTime = x.UpdateTime, PositionSide = x.PositionSide == PositionSide.Both ? null : x.PositionSide == PositionSide.Long ? SharedPositionSide.Long : SharedPositionSide.Short, ReduceOnly = x.ReduceOnly - })); + }).ToArray()); } PaginatedEndpointOptions IFuturesOrderRestClient.GetClosedFuturesOrdersOptions { get; } = new PaginatedEndpointOptions(SharedPaginationType.Descending, true); @@ -362,7 +379,8 @@ async Task>> IFuturesOrderRest var orders = await Trading.GetOrdersAsync(request.Symbol.GetSymbol(FormatSymbol), startTime: fromTimestamp ?? request.StartTime, endTime: request.EndTime, - limit: request.Limit ?? 1000).ConfigureAwait(false); + limit: request.Limit ?? 1000, + ct: ct).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); @@ -371,7 +389,7 @@ async Task>> IFuturesOrderRest if (orders.Data.Count() == (request.Limit ?? 1000)) nextToken = new DateTimeToken(orders.Data.Max(o => o.CreateTime)); - return orders.AsExchangeResult(Exchange, orders.Data.Where(x => x.Status == OrderStatus.Filled || x.Status == OrderStatus.Canceled || x.Status == OrderStatus.Expired).Select(x => new SharedFuturesOrder( + return orders.AsExchangeResult>(Exchange, orders.Data.Where(x => x.Status == OrderStatus.Filled || x.Status == OrderStatus.Canceled || x.Status == OrderStatus.Expired).Select(x => new SharedFuturesOrder( x.Symbol, x.Id.ToString(), ParseOrderType(x.Type), @@ -380,8 +398,8 @@ async Task>> IFuturesOrderRest x.CreateTime) { ClientOrderId = x.ClientOrderId, - AveragePrice = x.AveragePrice, - Price = x.Price, + AveragePrice = x.AveragePrice == 0 ? null : x.AveragePrice, + Price = x.Price == 0 ? null : x.Price, Quantity = x.Quantity, QuantityFilled = x.QuantityFilled, QuoteQuantityFilled = x.QuoteQuantityFilled, @@ -389,7 +407,7 @@ async Task>> IFuturesOrderRest UpdateTime = x.UpdateTime, PositionSide = x.PositionSide == PositionSide.Both ? null : x.PositionSide == PositionSide.Long ? SharedPositionSide.Long : SharedPositionSide.Short, ReduceOnly = x.ReduceOnly - })); + }).ToArray()); } EndpointOptions IFuturesOrderRestClient.GetFuturesOrderTradesOptions { get; } = new EndpointOptions(true); @@ -402,11 +420,11 @@ async Task>> IFuturesOrderRestCli if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult>(Exchange, new ArgumentError("Invalid order id")); - var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol(FormatSymbol), orderId: orderId).ConfigureAwait(false); + var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol(FormatSymbol), orderId: orderId, ct: ct).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); - return orders.AsExchangeResult(Exchange, orders.Data.Select(x => new SharedUserTrade( + return orders.AsExchangeResult>(Exchange, orders.Data.Select(x => new SharedUserTrade( x.Symbol, x.OrderId.ToString(), x.Id.ToString(), @@ -419,7 +437,7 @@ async Task>> IFuturesOrderRestCli Fee = x.Fee, FeeAsset = x.FeeAsset, Role = x.Maker ? SharedRole.Maker : SharedRole.Taker - })); + }).ToArray()); } PaginatedEndpointOptions IFuturesOrderRestClient.GetFuturesUserTradesOptions { get; } = new PaginatedEndpointOptions(SharedPaginationType.Descending, true); @@ -439,7 +457,8 @@ async Task>> IFuturesOrderRestCli startTime: request.StartTime, endTime: request.EndTime, limit: request.Limit ?? 500, - fromId: fromId + fromId: fromId, + ct: ct ).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); @@ -449,7 +468,7 @@ async Task>> IFuturesOrderRestCli if (orders.Data.Count() == (request.Limit ?? 500)) nextToken = new FromIdToken(orders.Data.Max(o => o.Id).ToString()); - return orders.AsExchangeResult(Exchange, orders.Data.Select(x => new SharedUserTrade( + return orders.AsExchangeResult>(Exchange, orders.Data.Select(x => new SharedUserTrade( x.Symbol, x.OrderId.ToString(), x.Id.ToString(), @@ -462,7 +481,7 @@ async Task>> IFuturesOrderRestCli Fee = x.Fee, FeeAsset = x.FeeAsset, Role = x.Maker ? SharedRole.Maker : SharedRole.Taker - }), nextToken); + }).ToArray(), nextToken); } EndpointOptions IFuturesOrderRestClient.CancelFuturesOrderOptions { get; } = new EndpointOptions(true); @@ -475,7 +494,7 @@ async Task> IFuturesOrderRestClient.CancelFuturesOrd if (!long.TryParse(request.OrderId, out var orderId)) return new ExchangeWebResult(Exchange, new ArgumentError("Invalid order id")); - var order = await Trading.CancelOrderAsync(request.Symbol.GetSymbol(FormatSymbol), orderId).ConfigureAwait(false); + var order = await Trading.CancelOrderAsync(request.Symbol.GetSymbol(FormatSymbol), orderId, ct: ct).ConfigureAwait(false); if (!order) return order.AsExchangeResult(Exchange, default); @@ -485,7 +504,7 @@ async Task> IFuturesOrderRestClient.CancelFuturesOrd EndpointOptions IFuturesOrderRestClient.GetPositionsOptions { get; } = new EndpointOptions(true); async Task>> IFuturesOrderRestClient.GetPositionsAsync(GetPositionsRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetPositionsOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetPositionsOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol?.ApiType ?? request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -493,30 +512,46 @@ async Task>> IFuturesOrderRestClie if (!result) return result.AsExchangeResult>(Exchange, default); - return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedPosition(x.Symbol, Math.Abs(x.Quantity), x.UpdateTime) + var data = result.Data; + if (request.ApiType.HasValue) + data = data.Where(x => request.ApiType == ApiType.DeliveryLinear ? x.Symbol.Contains("_") : !x.Symbol.Contains("_")); + + return result.AsExchangeResult>(Exchange, data.Select(x => new SharedPosition(x.Symbol, Math.Abs(x.Quantity), x.UpdateTime) { UnrealizedPnl = x.UnrealizedPnl, - LiquidationPrice = x.LiquidationPrice, + LiquidationPrice = x.LiquidationPrice == 0 ? null: x.LiquidationPrice, Leverage = x.Leverage, AverageEntryPrice = x.EntryPrice, - PositionSide = x.PositionSide == PositionSide.Both ? (x.Quantity > 0 ? SharedPositionSide.Long : SharedPositionSide.Short) : x.PositionSide == PositionSide.Short ? SharedPositionSide.Short : SharedPositionSide.Long - }).ToList()); + PositionSide = x.PositionSide == PositionSide.Both ? (x.Quantity >= 0 ? SharedPositionSide.Long : SharedPositionSide.Short) : x.PositionSide == PositionSide.Short ? SharedPositionSide.Short : SharedPositionSide.Long + }).ToArray()); } - EndpointOptions IFuturesOrderRestClient.ClosePositionOptions { get; } = new EndpointOptions(true); + EndpointOptions IFuturesOrderRestClient.ClosePositionOptions { get; } = new EndpointOptions(true) + { + RequiredOptionalParameters = new List + { + new ParameterDescription(nameof(ClosePositionRequest.PositionSide), typeof(SharedPositionSide), "The position side to close", SharedPositionSide.Long), + new ParameterDescription(nameof(ClosePositionRequest.Quantity), typeof(decimal), "Quantity of the position is required", 0.1m) + } + }; async Task> IFuturesOrderRestClient.ClosePositionAsync(ClosePositionRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((IFuturesOrderRestClient)this).ClosePositionOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); + var symbol = request.Symbol.GetSymbol(FormatSymbol); + var positionMode = await Account.GetPositionModeAsync().ConfigureAwait(false); + if (!positionMode) + return positionMode.AsExchangeResult(Exchange, default); + var result = await Trading.PlaceOrderAsync( - request.Symbol.GetSymbol(FormatSymbol), + symbol, request.PositionSide == SharedPositionSide.Long ? OrderSide.Sell : OrderSide.Buy, FuturesOrderType.Market, request.Quantity, - positionSide: request.PositionSide == null ? null : request.PositionSide == SharedPositionSide.Short ? PositionSide.Short : PositionSide.Long, - reduceOnly: true, + positionSide: !positionMode.Data.IsHedgeMode ? null : request.PositionSide == SharedPositionSide.Short ? PositionSide.Short : PositionSide.Long, + reduceOnly: positionMode.Data.IsHedgeMode ? null : true, ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -524,14 +559,12 @@ async Task> IFuturesOrderRestClient.ClosePositionAsy return result.AsExchangeResult(Exchange, new SharedId(result.Data.Id.ToString())); } - private TimeInForce? GetTimeInForce(SharedTimeInForce? tif) + private TimeInForce? GetTimeInForce(SharedOrderType type, SharedTimeInForce? tif) { - if (tif == null) - return null; - if (tif == SharedTimeInForce.ImmediateOrCancel) return TimeInForce.ImmediateOrCancel; if (tif == SharedTimeInForce.FillOrKill) return TimeInForce.FillOrKill; if (tif == SharedTimeInForce.GoodTillCanceled) return TimeInForce.GoodTillCanceled; + if (type == SharedOrderType.Limit) return TimeInForce.GoodTillCanceled; // Limit order always needs tif return null; } @@ -578,12 +611,7 @@ async Task> ILeverageRestClient.GetLeverageAsy if (!result.Data.Any()) return result.AsExchangeError(Exchange, new ServerError("Not found")); - var sideData = - request.Side == SharedPositionSide.Short ? result.Data.SingleOrDefault(x => x.PositionSide == PositionSide.Short) : - request.Side == SharedPositionSide.Long ? result.Data.SingleOrDefault(x => x.PositionSide == PositionSide.Long) : - result.Data.SingleOrDefault(x => x.PositionSide == PositionSide.Both); - - return result.AsExchangeResult(Exchange, new SharedLeverage(sideData.Leverage) + return result.AsExchangeResult(Exchange, new SharedLeverage(result.Data.First().Leverage) { Side = request.Side }); @@ -642,7 +670,7 @@ async Task>> ITradeHistoryRestClient. request.Symbol.GetSymbol(FormatSymbol), startTime: fromId != null ? null : request.StartTime, endTime: fromId != null ? null : request.EndTime, - limit: 1000, + limit: request.Limit ?? 1000, fromId: fromId, ct: ct).ConfigureAwait(false); if (!result) @@ -653,7 +681,7 @@ async Task>> ITradeHistoryRestClient. nextToken = new FromIdToken(result.Data.Max(x => x.Id).ToString()); // Return - return result.AsExchangeResult(Exchange, result.Data.Where(x => x.TradeTime < request.EndTime).Select(x => new SharedTrade(x.Quantity, x.Price, x.TradeTime)), nextToken); + return result.AsExchangeResult>(Exchange, result.Data.Where(x => x.TradeTime < request.EndTime).Select(x => new SharedTrade(x.Quantity, x.Price, x.TradeTime)).ToArray(), nextToken); } #endregion @@ -674,17 +702,29 @@ async Task>> IIndexPriceKlineRest if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); - // Determine page token - DateTime? fromTimestamp = null; + // Determine pagination + // Data is normally returned oldest first, so to do newest first pagination we have to do some calc + DateTime endTime = request.EndTime ?? DateTime.UtcNow; + DateTime? startTime = request.StartTime; if (pageToken is DateTimeToken dateTimeToken) - fromTimestamp = dateTimeToken.LastTime; + endTime = dateTimeToken.LastTime; + + var limit = request.Limit ?? 1000; + if (startTime == null || startTime < endTime) + { + var offset = (int)interval * limit; + startTime = endTime.AddSeconds(-offset); + } + + if (startTime < request.StartTime) + startTime = request.StartTime; var result = await ExchangeData.GetMarkPriceKlinesAsync( request.Symbol.GetSymbol(FormatSymbol), interval, - request.Limit ?? 1000, - fromTimestamp ?? request.StartTime, - request.EndTime, + limit, + startTime, + endTime, ct: ct ).ConfigureAwait(false); if (!result) @@ -692,14 +732,14 @@ async Task>> IIndexPriceKlineRest // Get next token DateTimeToken? nextToken = null; - if (request.StartTime != null && result.Data.Any()) + if (result.Data.Count() == limit) { - var maxOpenTime = result.Data.Max(x => x.OpenTime); - if (maxOpenTime < request.EndTime!.Value.AddSeconds(-(int)request.Interval)) - nextToken = new DateTimeToken(maxOpenTime.AddSeconds((int)interval)); + var minOpenTime = result.Data.Min(x => x.OpenTime); + if (request.StartTime == null || minOpenTime > request.StartTime.Value) + nextToken = new DateTimeToken(minOpenTime.AddSeconds(-(int)(interval - 1))); } - return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedMarkKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)), nextToken); + return result.AsExchangeResult>(Exchange, result.Data.Reverse().Select(x => new SharedMarkKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)).ToArray(), nextToken); } #endregion @@ -723,7 +763,7 @@ async Task> IOpenInterestRestClient.GetOpe #endregion #region Funding Rate client - GetFundingRateHistoryOptions IFundingRateRestClient.GetFundingRateHistoryOptions { get; } = new GetFundingRateHistoryOptions(true, false); + GetFundingRateHistoryOptions IFundingRateRestClient.GetFundingRateHistoryOptions { get; } = new GetFundingRateHistoryOptions(SharedPaginationType.Ascending, false); async Task>> IFundingRateRestClient.GetFundingRateHistoryAsync(GetFundingRateHistoryRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) { @@ -740,26 +780,26 @@ async Task>> IFundingRateRestCl request.Symbol.GetSymbol(FormatSymbol), startTime: fromTime ?? request.StartTime, endTime: request.EndTime, - limit: 1000, + limit: request.Limit ?? 1000, ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult>(Exchange, default); DateTimeToken? nextToken = null; - if (result.Data.Count() == 1000) + if (result.Data.Count() == (request.Limit ?? 1000)) nextToken = new DateTimeToken(result.Data.Max(x => x.FundingTime)); // Return - return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedFundingRate(x.FundingRate, x.FundingTime)), nextToken); + return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedFundingRate(x.FundingRate, x.FundingTime)).ToArray(), nextToken); } #endregion #region Balance Client - EndpointOptions IBalanceRestClient.GetBalancesOptions { get; } = new EndpointOptions("GetBalancesRequest", true); + EndpointOptions IBalanceRestClient.GetBalancesOptions { get; } = new EndpointOptions(true); - async Task>> IBalanceRestClient.GetBalancesAsync(ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IBalanceRestClient.GetBalancesAsync(GetBalancesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IBalanceRestClient)this).GetBalancesOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); + var validationError = ((IBalanceRestClient)this).GetBalancesOptions.ValidateRequest(Exchange, exchangeParameters, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -767,7 +807,7 @@ async Task>> IBalanceRestClient.Get if (!result) return result.AsExchangeResult>(Exchange, default); - return result.AsExchangeResult(Exchange, result.Data.Select(x => new SharedBalance(x.Asset, x.AvailableBalance, x.WalletBalance))); + return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedBalance(x.Asset, x.AvailableBalance, x.WalletBalance)).ToArray()); } #endregion @@ -777,7 +817,7 @@ async Task>> IBalanceRestClient.Get GetPositionModeOptions IPositionModeRestClient.GetPositionModeOptions { get; } = new GetPositionModeOptions(false); async Task> IPositionModeRestClient.GetPositionModeAsync(GetPositionModeRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IPositionModeRestClient)this).GetPositionModeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IPositionModeRestClient)this).GetPositionModeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol?.ApiType ?? request.ApiType!.Value, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -791,7 +831,7 @@ async Task> IPositionModeRestClient. SetPositionModeOptions IPositionModeRestClient.SetPositionModeOptions { get; } = new SetPositionModeOptions(true, true, false); async Task> IPositionModeRestClient.SetPositionModeAsync(SetPositionModeRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IPositionModeRestClient)this).SetPositionModeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IPositionModeRestClient)this).SetPositionModeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol?.ApiType ?? request.ApiType!.Value, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -802,5 +842,6 @@ async Task> IPositionModeRestClient. return result.AsExchangeResult(Exchange, new SharedPositionModeResult(request.Mode)); } #endregion + } } diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs index 9c9cf9baa..c1d18eb33 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs @@ -56,7 +56,7 @@ async Task> ITickersSocketClient.SubscribeToA if (!data.Any()) return; - handler(update.AsExchangeEvent(Exchange, data.Select(x => new SharedSpotTicker(x.Symbol, x.LastPrice, x.LowPrice, x.HighPrice, x.Volume, x.PriceChangePercent)))); + handler(update.AsExchangeEvent>(Exchange, data.Select(x => new SharedSpotTicker(x.Symbol, x.LastPrice, x.LowPrice, x.HighPrice, x.Volume, x.PriceChangePercent)).ToArray())); }, ct: ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -115,7 +115,7 @@ async Task> IBalanceSocketClient.SubscribeToB var listenKey = exchangeParameters.GetValue(Exchange, "ListenKey"); var result = await SubscribeToUserDataUpdatesAsync(listenKey!, #warning correct? - onAccountUpdate: update => handler(update.AsExchangeEvent(Exchange, update.Data.UpdateData.Balances.Select(x => new SharedBalance(x.Asset, x.WalletBalance, x.WalletBalance + x.CrossWalletBalance)))), + onAccountUpdate: update => handler(update.AsExchangeEvent>(Exchange, update.Data.UpdateData.Balances.Select(x => new SharedBalance(x.Asset, x.WalletBalance, x.WalletBalance + x.CrossWalletBalance)).ToArray())), ct: ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -222,12 +222,12 @@ async Task> IPositionSocketClient.SubscribeTo var listenKey = exchangeParameters.GetValue(Exchange, "ListenKey"); var result = await SubscribeToUserDataUpdatesAsync(listenKey!, - onAccountUpdate: update => handler(update.AsExchangeEvent(Exchange, update.Data.UpdateData.Positions.Select(x => new SharedPosition(x.Symbol, x.Quantity, update.Data.EventTime) + onAccountUpdate: update => handler(update.AsExchangeEvent>(Exchange, update.Data.UpdateData.Positions.Select(x => new SharedPosition(x.Symbol, x.Quantity, update.Data.EventTime) { AverageEntryPrice = x.EntryPrice, PositionSide = x.PositionSide == Enums.PositionSide.Both ? (x.Quantity > 0 ? SharedPositionSide.Long : SharedPositionSide.Short) : x.PositionSide == Enums.PositionSide.Short ? SharedPositionSide.Short : SharedPositionSide.Long, UnrealizedPnl = x.UnrealizedPnl - }))), + }).ToArray())), ct: ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); From cf182e01ddfee97ca6350056ba80110531ab4103 Mon Sep 17 00:00:00 2001 From: JKorf Date: Thu, 12 Sep 2024 22:16:27 +0200 Subject: [PATCH 36/54] wip --- .../BinanceRestClientCoinFuturesApiShared.cs | 211 +++++++++++++----- ...BinanceSocketClientCoinFuturesApiShared.cs | 45 ++-- .../SpotApi/BinanceRestClientSpotApiShared.cs | 55 ++++- .../BinanceSocketClientSpotApiShared.cs | 22 +- .../BinanceRestClientUsdFuturesApiShared.cs | 56 ++++- .../BinanceSocketClientUsdFuturesApiShared.cs | 42 ++-- .../IBinanceRestClientCoinFuturesApiShared.cs | 3 +- .../IBinanceRestClientSpotApiShared.cs | 3 +- .../IBinanceRestClientUsdFuturesApiShared.cs | 3 +- 9 files changed, 310 insertions(+), 130 deletions(-) diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs index 82932754d..ec4aab501 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -100,8 +100,8 @@ async Task>> IFuturesSymbolRe MaxTradeQuantity = s.LotSizeFilter?.MaxQuantity, QuantityStep = s.LotSizeFilter?.StepSize, PriceStep = s.PriceFilter?.TickSize, - ContractSize = 1, - DeliveryTime = s.DeliveryDate + ContractSize = s.ContractSize, + DeliveryTime = s.DeliveryDate.Year == 2100 ? null: s.DeliveryDate }).ToArray()); } @@ -135,7 +135,7 @@ async Task> IFuturesTickerRestClient.GetF IndexPrice = mark.IndexPrice, MarkPrice = mark.MarkPrice, FundingRate = mark.FundingRate, - NextFundingTime = mark.NextFundingTime + NextFundingTime = mark.NextFundingTime == default ? null: mark.NextFundingTime }); } @@ -205,10 +205,10 @@ async Task>> IRecentTradeRestClient.G SharedTimeInForce.FillOrKill }, new SharedQuantitySupport( - SharedQuantityType.BaseAssetQuantity, - SharedQuantityType.BaseAssetQuantity, - SharedQuantityType.BaseAssetQuantity, - SharedQuantityType.BaseAssetQuantity)); + SharedQuantityType.Contracts, + SharedQuantityType.Contracts, + SharedQuantityType.Contracts, + SharedQuantityType.Contracts)); async Task> IFuturesOrderRestClient.PlaceFuturesOrderAsync(PlaceFuturesOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { @@ -216,7 +216,7 @@ async Task> IFuturesOrderRestClient.PlaceFuturesOrde if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var result = await Trading.PlaceOrderAsync( + var result = await Trading.PlaceOrderAsync( request.Symbol.GetSymbol(FormatSymbol), request.Side == SharedOrderSide.Buy ? Enums.OrderSide.Buy : Enums.OrderSide.Sell, request.OrderType == SharedOrderType.Limit ? Enums.FuturesOrderType.Limit : Enums.FuturesOrderType.Market, @@ -224,7 +224,8 @@ async Task> IFuturesOrderRestClient.PlaceFuturesOrde price: request.Price, positionSide: request.PositionSide == null ? null : request.PositionSide == SharedPositionSide.Long ? PositionSide.Long: PositionSide.Short, reduceOnly: request.ReduceOnly, - newClientOrderId: request.ClientOrderId, + timeInForce: GetTimeInForce(request.OrderType, request.TimeInForce), + newClientOrderId: request.ClientOrderId, ct: ct).ConfigureAwait(false); if (!result) @@ -256,8 +257,8 @@ async Task> IFuturesOrderRestClient.GetFut order.Data.CreateTime) { ClientOrderId = order.Data.ClientOrderId, - AveragePrice = order.Data.AveragePrice, - Price = order.Data.Price, + AveragePrice = order.Data.AveragePrice == 0 ? null : order.Data.AveragePrice, + Price = order.Data.Price == 0 ? null : order.Data.Price, Quantity = order.Data.Quantity, QuantityFilled = order.Data.QuantityFilled, QuoteQuantityFilled = order.Data.QuoteQuantityFilled, @@ -289,8 +290,8 @@ async Task>> IFuturesOrderRest x.CreateTime) { ClientOrderId = x.ClientOrderId, - AveragePrice = x.AveragePrice, - Price = x.Price, + AveragePrice = x.AveragePrice == 0 ? null : x.AveragePrice, + Price = x.Price == 0 ? null : x.Price, Quantity = x.Quantity, QuantityFilled = x.QuantityFilled, QuoteQuantityFilled = x.QuoteQuantityFilled, @@ -317,14 +318,14 @@ async Task>> IFuturesOrderRest var orders = await Trading.GetOrdersAsync(request.Symbol.GetSymbol(FormatSymbol), startTime: fromTimestamp ?? request.StartTime, endTime: request.EndTime, - limit: request.Limit ?? 1000, + limit: request.Limit ?? 100, ct: ct).ConfigureAwait(false); if (!orders) return orders.AsExchangeResult>(Exchange, default); // Get next token DateTimeToken? nextToken = null; - if (orders.Data.Count() == (request.Limit ?? 1000)) + if (orders.Data.Count() == (request.Limit ?? 100)) nextToken = new DateTimeToken(orders.Data.Max(o => o.CreateTime)); return orders.AsExchangeResult>(Exchange, orders.Data.Where(x => x.Status == OrderStatus.Filled || x.Status == OrderStatus.Canceled || x.Status == OrderStatus.Expired).Select(x => new SharedFuturesOrder( @@ -336,8 +337,8 @@ async Task>> IFuturesOrderRest x.CreateTime) { ClientOrderId = x.ClientOrderId, - AveragePrice = x.AveragePrice, - Price = x.Price, + AveragePrice = x.AveragePrice == 0 ? null : x.AveragePrice, + Price = x.Price == 0 ? null : x.Price, Quantity = x.Quantity, QuantityFilled = x.QuantityFilled, QuoteQuantityFilled = x.QuoteQuantityFilled, @@ -446,34 +447,47 @@ async Task>> IFuturesOrderRestClie if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); - var result = await Account.GetPositionInformationAsync(pair: request.Symbol?.GetSymbol(FormatSymbol), ct: ct).ConfigureAwait(false); + var symbol = request.Symbol?.GetSymbol(FormatSymbol); + var result = await Account.GetPositionInformationAsync(pair: symbol?.Split('_')[0], ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult>(Exchange, default); return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedPosition(x.Symbol, Math.Abs(x.Quantity), x.UpdateTime) { UnrealizedPnl = x.UnrealizedPnl, - LiquidationPrice = x.LiquidationPrice, + LiquidationPrice = x.LiquidationPrice == 0 ? null : x.LiquidationPrice, Leverage = x.Leverage, AverageEntryPrice = x.EntryPrice, - PositionSide = x.PositionSide == PositionSide.Both ? (x.Quantity > 0 ? SharedPositionSide.Long : SharedPositionSide.Short) : x.PositionSide == PositionSide.Short ? SharedPositionSide.Short : SharedPositionSide.Long + PositionSide = x.PositionSide == PositionSide.Both ? (x.Quantity >= 0 ? SharedPositionSide.Long : SharedPositionSide.Short) : x.PositionSide == PositionSide.Short ? SharedPositionSide.Short : SharedPositionSide.Long }).ToArray()); } - EndpointOptions IFuturesOrderRestClient.ClosePositionOptions { get; } = new EndpointOptions(true); + EndpointOptions IFuturesOrderRestClient.ClosePositionOptions { get; } = new EndpointOptions(true) + { + RequiredOptionalParameters = new List + { + new ParameterDescription(nameof(ClosePositionRequest.PositionSide), typeof(SharedPositionSide), "The position side to close", SharedPositionSide.Long), + new ParameterDescription(nameof(ClosePositionRequest.Quantity), typeof(decimal), "Quantity of the position is required", 0.1m) + } + }; async Task> IFuturesOrderRestClient.ClosePositionAsync(ClosePositionRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((IFuturesOrderRestClient)this).ClosePositionOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); + var symbol = request.Symbol.GetSymbol(FormatSymbol); + var positionMode = await Account.GetPositionModeAsync().ConfigureAwait(false); + if (!positionMode) + return positionMode.AsExchangeResult(Exchange, default); + var result = await Trading.PlaceOrderAsync( - request.Symbol.GetSymbol(FormatSymbol), + symbol, request.PositionSide == SharedPositionSide.Long ? OrderSide.Sell : OrderSide.Buy, FuturesOrderType.Market, request.Quantity, - positionSide: request.PositionSide == null ? null : request.PositionSide == SharedPositionSide.Short ? PositionSide.Short : PositionSide.Long, - reduceOnly: true, + positionSide: !positionMode.Data.IsHedgeMode ? null : request.PositionSide == SharedPositionSide.Short ? PositionSide.Short : PositionSide.Long, + reduceOnly: positionMode.Data.IsHedgeMode ? null : true, ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); @@ -481,6 +495,16 @@ async Task> IFuturesOrderRestClient.ClosePositionAsy return result.AsExchangeResult(Exchange, new SharedId(result.Data.Id.ToString())); } + private TimeInForce? GetTimeInForce(SharedOrderType type, SharedTimeInForce? tif) + { + if (tif == SharedTimeInForce.ImmediateOrCancel) return TimeInForce.ImmediateOrCancel; + if (tif == SharedTimeInForce.FillOrKill) return TimeInForce.FillOrKill; + if (tif == SharedTimeInForce.GoodTillCanceled) return TimeInForce.GoodTillCanceled; + if (type == SharedOrderType.Limit) return TimeInForce.GoodTillCanceled; // Limit order always needs tif + + return null; + } + private SharedOrderStatus ParseOrderStatus(OrderStatus status) { if (status == OrderStatus.PendingNew || status == OrderStatus.New || status == OrderStatus.PartiallyFilled || status == OrderStatus.PendingCancel) return SharedOrderStatus.Open; @@ -516,25 +540,22 @@ async Task> ILeverageRestClient.GetLeverageAsy if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var result = await Account.GetPositionInformationAsync(pair: request.Symbol.GetSymbol(FormatSymbol), ct: ct).ConfigureAwait(false); + var symbol = request.Symbol.GetSymbol(FormatSymbol); + var result = await Account.GetPositionInformationAsync(pair: symbol.Split('_')[0], ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); if (!result.Data.Any()) return result.AsExchangeError(Exchange, new ServerError("Not found")); - var sideData = - request.Side == SharedPositionSide.Short ? result.Data.SingleOrDefault(x => x.PositionSide == PositionSide.Short) : - request.Side == SharedPositionSide.Long ? result.Data.SingleOrDefault(x => x.PositionSide == PositionSide.Long) : - result.Data.SingleOrDefault(x => x.PositionSide == PositionSide.Both); - - return result.AsExchangeResult(Exchange, new SharedLeverage(sideData.Leverage) + var data = result.Data.Where(x => x.Symbol == symbol).ToList(); + return result.AsExchangeResult(Exchange, new SharedLeverage(data.First().Leverage) { Side = request.Side }); } - SetLeverageOptions ILeverageRestClient.SetLeverageOptions { get; } = new SetLeverageOptions(false); + SetLeverageOptions ILeverageRestClient.SetLeverageOptions { get; } = new SetLeverageOptions(true); async Task> ILeverageRestClient.SetLeverageAsync(SetLeverageRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((ILeverageRestClient)this).SetLeverageOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); @@ -566,17 +587,29 @@ async Task>> IMarkPriceKlineRestC if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); - // Determine page token - DateTime? fromTimestamp = null; + // Determine pagination + // Data is normally returned oldest first, so to do newest first pagination we have to do some calc + DateTime endTime = request.EndTime ?? DateTime.UtcNow; + DateTime? startTime = request.StartTime; if (pageToken is DateTimeToken dateTimeToken) - fromTimestamp = dateTimeToken.LastTime; + endTime = dateTimeToken.LastTime; + + var limit = request.Limit ?? 1000; + if (startTime == null || startTime < endTime) + { + var offset = (int)interval * limit; + startTime = endTime.AddSeconds(-offset); + } + + if (startTime < request.StartTime) + startTime = request.StartTime; var result = await ExchangeData.GetMarkPriceKlinesAsync( request.Symbol.GetSymbol(FormatSymbol), interval, - request.Limit ?? 1000, - fromTimestamp ?? request.StartTime, - request.EndTime, + limit, + startTime, + endTime, ct: ct ).ConfigureAwait(false); if (!result) @@ -584,14 +617,14 @@ async Task>> IMarkPriceKlineRestC // Get next token DateTimeToken? nextToken = null; - if (request.StartTime != null && result.Data.Any()) + if (result.Data.Count() == limit) { - var maxOpenTime = result.Data.Max(x => x.OpenTime); - if (maxOpenTime < request.EndTime!.Value.AddSeconds(-(int)request.Interval)) - nextToken = new DateTimeToken(maxOpenTime.AddSeconds((int)interval)); + var minOpenTime = result.Data.Min(x => x.OpenTime); + if (request.StartTime == null || minOpenTime > request.StartTime.Value) + nextToken = new DateTimeToken(minOpenTime.AddSeconds(-(int)(interval - 1))); } - return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedMarkKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)).ToArray(), nextToken); + return result.AsExchangeResult>(Exchange, result.Data.Reverse().Select(x => new SharedMarkKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)).ToArray(), nextToken); } #endregion @@ -634,7 +667,7 @@ async Task>> ITradeHistoryRestClient. request.Symbol.GetSymbol(FormatSymbol), startTime: fromId != null ? null : request.StartTime, endTime: fromId != null ? null : request.EndTime, - limit: 1000, + limit: request.Limit ?? 1000, fromId: fromId, ct: ct).ConfigureAwait(false); if (!result) @@ -666,17 +699,29 @@ async Task>> IIndexPriceKlineRest if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); - // Determine page token - DateTime? fromTimestamp = null; + // Determine pagination + // Data is normally returned oldest first, so to do newest first pagination we have to do some calc + DateTime endTime = request.EndTime ?? DateTime.UtcNow; + DateTime? startTime = request.StartTime; if (pageToken is DateTimeToken dateTimeToken) - fromTimestamp = dateTimeToken.LastTime; + endTime = dateTimeToken.LastTime; + + var limit = request.Limit ?? 1000; + if (startTime == null || startTime < endTime) + { + var offset = (int)interval * limit; + startTime = endTime.AddSeconds(-offset); + } + + if (startTime < request.StartTime) + startTime = request.StartTime; var result = await ExchangeData.GetMarkPriceKlinesAsync( request.Symbol.GetSymbol(FormatSymbol), interval, - request.Limit ?? 1000, - fromTimestamp ?? request.StartTime, - request.EndTime, + limit, + startTime, + endTime, ct: ct ).ConfigureAwait(false); if (!result) @@ -684,21 +729,21 @@ async Task>> IIndexPriceKlineRest // Get next token DateTimeToken? nextToken = null; - if (request.StartTime != null && result.Data.Any()) + if (result.Data.Count() == limit) { - var maxOpenTime = result.Data.Max(x => x.OpenTime); - if (maxOpenTime < request.EndTime!.Value.AddSeconds(-(int)request.Interval)) - nextToken = new DateTimeToken(maxOpenTime.AddSeconds((int)interval)); + var minOpenTime = result.Data.Min(x => x.OpenTime); + if (request.StartTime == null || minOpenTime > request.StartTime.Value) + nextToken = new DateTimeToken(minOpenTime.AddSeconds(-(int)(interval - 1))); } - return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedMarkKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)).ToArray(), nextToken); + return result.AsExchangeResult>(Exchange, result.Data.Reverse().Select(x => new SharedMarkKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)).ToArray(), nextToken); } #endregion #region Open Interest client - EndpointOptions IOpenInterestRestClient.GetOpenInterestOptions { get; } = new EndpointOptions(true); + EndpointOptions IOpenInterestRestClient.GetOpenInterestOptions { get; } = new EndpointOptions(false); async Task> IOpenInterestRestClient.GetOpenInterestAsync(GetOpenInterestRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((IOpenInterestRestClient)this).GetOpenInterestOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); @@ -732,13 +777,13 @@ async Task>> IFundingRateRestCl request.Symbol.GetSymbol(FormatSymbol), startTime: fromTime ?? request.StartTime, endTime: request.EndTime, - limit: 1000, + limit: request.Limit ?? 1000, ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult>(Exchange, default); DateTimeToken? nextToken = null; - if (result.Data.Count() == 1000) + if (result.Data.Count() == (request.Limit ?? 1000)) nextToken = new DateTimeToken(result.Data.Max(x => x.FundingTime)); // Return @@ -769,7 +814,7 @@ async Task>> IBalanceRestClient.Get GetPositionModeOptions IPositionModeRestClient.GetPositionModeOptions { get; } = new GetPositionModeOptions(false); async Task> IPositionModeRestClient.GetPositionModeAsync(GetPositionModeRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IPositionModeRestClient)this).GetPositionModeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol?.ApiType ?? request.ApiType!.Value, SupportedApiTypes); + var validationError = ((IPositionModeRestClient)this).GetPositionModeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol?.ApiType ?? request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -783,7 +828,7 @@ async Task> IPositionModeRestClient. SetPositionModeOptions IPositionModeRestClient.SetPositionModeOptions { get; } = new SetPositionModeOptions(true, true, false); async Task> IPositionModeRestClient.SetPositionModeAsync(SetPositionModeRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IPositionModeRestClient)this).SetPositionModeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol?.ApiType ?? request.ApiType!.Value, SupportedApiTypes); + var validationError = ((IPositionModeRestClient)this).SetPositionModeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol?.ApiType ?? request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -795,5 +840,51 @@ async Task> IPositionModeRestClient. } #endregion + #region Listen Key client + + EndpointOptions IListenKeyRestClient.StartOptions { get; } = new EndpointOptions(true); + async Task> IListenKeyRestClient.StartListenKeyAsync(StartListenKeyRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IListenKeyRestClient)this).StartOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + + // Get data + var result = await Account.StartUserStreamAsync(ct: ct).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult(Exchange, default); + + return result.AsExchangeResult(Exchange, result.Data); + } + EndpointOptions IListenKeyRestClient.KeepAliveOptions { get; } = new EndpointOptions(true); + async Task> IListenKeyRestClient.KeepAliveListenKeyAsync(KeepAliveListenKeyRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IListenKeyRestClient)this).KeepAliveOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + + // Get data + var result = await Account.KeepAliveUserStreamAsync(request.ListenKey, ct: ct).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult(Exchange, default); + + return result.AsExchangeResult(Exchange, request.ListenKey); + } + + EndpointOptions IListenKeyRestClient.StopOptions { get; } = new EndpointOptions(true); + async Task> IListenKeyRestClient.StopListenKeyAsync(StopListenKeyRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IListenKeyRestClient)this).StopOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + + // Get data + var result = await Account.StopUserStreamAsync(request.ListenKey, ct: ct).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult(Exchange, default); + + return result.AsExchangeResult(Exchange, request.ListenKey); + } + #endregion } } diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs index 8bde6af0c..c36732fc7 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs @@ -133,23 +133,21 @@ async Task> IOrderBookSocketClient.SubscribeT #endregion #region Balance client - SubscriptionOptions IBalanceSocketClient.SubscribeBalanceOptions { get; } = new SubscriptionOptions("SubscribeBalanceRequest", false) + SubscriptionOptions IBalanceSocketClient.SubscribeBalanceOptions { get; } = new SubscriptionOptions(false) { - RequiredExchangeParameters = new List + RequiredOptionalParameters = new List { - new ParameterDescription("ListenKey", typeof(string), "The listenkey for starting the user stream", "123123123") + new ParameterDescription(nameof(SubscribeBalancesRequest.ListenKey), typeof(string), "The listenkey for starting the user stream", "123123123") } }; - async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(Action>> handler, ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(SubscribeBalancesRequest request, Action>> handler, ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); + var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, request, exchangeParameters, apiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); - var listenKey = exchangeParameters.GetValue(Exchange, "ListenKey"); - var result = await SubscribeToUserDataUpdatesAsync(listenKey!, -#warning correct? - onAccountUpdate: update => handler(update.AsExchangeEvent>(Exchange, update.Data.UpdateData.Balances.Select(x => new SharedBalance(x.Asset, x.WalletBalance, x.WalletBalance + x.CrossWalletBalance)).ToArray())), + var result = await SubscribeToUserDataUpdatesAsync(request.ListenKey!, + onAccountUpdate: update => handler(update.AsExchangeEvent>(Exchange, update.Data.UpdateData.Balances.Select(x => new SharedBalance(x.Asset, x.WalletBalance, x.WalletBalance)).ToArray())), ct: ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -158,25 +156,24 @@ async Task> IBalanceSocketClient.SubscribeToB #endregion #region Position client - SubscriptionOptions IPositionSocketClient.SubscribePositionOptions { get; } = new SubscriptionOptions("SubscribePositionRequest", false) + SubscriptionOptions IPositionSocketClient.SubscribePositionOptions { get; } = new SubscriptionOptions(false) { - RequiredExchangeParameters = new List + RequiredOptionalParameters = new List { - new ParameterDescription("ListenKey", typeof(string), "The listenkey for starting the user stream", "123123123") + new ParameterDescription(nameof(SubscribePositionRequest.ListenKey), typeof(string), "The listenkey for starting the user stream", "123123123") } }; - async Task> IPositionSocketClient.SubscribeToPositionUpdatesAsync(Action>> handler, ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IPositionSocketClient.SubscribeToPositionUpdatesAsync(SubscribePositionRequest request, Action>> handler, ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IPositionSocketClient)this).SubscribePositionOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); + var validationError = ((IPositionSocketClient)this).SubscribePositionOptions.ValidateRequest(Exchange, request, exchangeParameters, apiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); - var listenKey = exchangeParameters.GetValue(Exchange, "ListenKey"); - var result = await SubscribeToUserDataUpdatesAsync(listenKey!, + var result = await SubscribeToUserDataUpdatesAsync(request.ListenKey!, onAccountUpdate: update => handler(update.AsExchangeEvent>(Exchange, update.Data.UpdateData.Positions.Select(x => new SharedPosition(x.Symbol, x.Quantity, update.Data.EventTime) { AverageEntryPrice = x.EntryPrice, - PositionSide = x.PositionSide == Enums.PositionSide.Both ? (x.Quantity > 0 ? SharedPositionSide.Long : SharedPositionSide.Short) : x.PositionSide == Enums.PositionSide.Short ? SharedPositionSide.Short : SharedPositionSide.Long, + PositionSide = x.PositionSide == Enums.PositionSide.Both ? (x.Quantity >= 0 ? SharedPositionSide.Long : SharedPositionSide.Short) : x.PositionSide == Enums.PositionSide.Short ? SharedPositionSide.Short : SharedPositionSide.Long, UnrealizedPnl = x.UnrealizedPnl }).ToArray())), ct: ct).ConfigureAwait(false); @@ -188,21 +185,21 @@ async Task> IPositionSocketClient.SubscribeTo #region Futures Order client - SubscriptionOptions IFuturesOrderSocketClient.SubscribeFuturesOrderOptions { get; } = new SubscriptionOptions("SubscribeFuturesOrderRequest", false) + SubscriptionOptions IFuturesOrderSocketClient.SubscribeFuturesOrderOptions { get; } = new SubscriptionOptions(false) { - RequiredExchangeParameters = new List + RequiredOptionalParameters = new List { - new ParameterDescription("ListenKey", typeof(string), "The listenkey for starting the user stream", "123123123") + new ParameterDescription(nameof(SubscribeFuturesOrderRequest.ListenKey), typeof(string), "The listenkey for starting the user stream", "123123123") } }; - async Task> IFuturesOrderSocketClient.SubscribeToFuturesOrderUpdatesAsync(Action>> handler, ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + + async Task> IFuturesOrderSocketClient.SubscribeToFuturesOrderUpdatesAsync(SubscribeFuturesOrderRequest request, Action>> handler, ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); + var validationError = ((IFuturesOrderSocketClient)this).SubscribeFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, apiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); - var listenKey = exchangeParameters.GetValue(Exchange, "ListenKey"); - var result = await SubscribeToUserDataUpdatesAsync(listenKey, + var result = await SubscribeToUserDataUpdatesAsync(request.ListenKey!, onOrderUpdate: update => handler(update.AsExchangeEvent>(Exchange, new[] { new SharedFuturesOrder( update.Data.UpdateData.Symbol, diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index 4fbe6ea2f..84b361998 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -245,10 +245,10 @@ async Task>> IBalanceRestClient.Get SharedTimeInForce.FillOrKill }, new SharedQuantitySupport( - SharedQuantityType.BaseAssetQuantity, - SharedQuantityType.BaseAssetQuantity, - SharedQuantityType.Both, - SharedQuantityType.Both)); + SharedQuantityType.BaseAsset, + SharedQuantityType.BaseAsset, + SharedQuantityType.BaseAndQuoteAsset, + SharedQuantityType.BaseAndQuoteAsset)); async Task> ISpotOrderRestClient.PlaceSpotOrderAsync(PlaceSpotOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { @@ -699,5 +699,52 @@ async Task>> IWithdrawalRestClie } #endregion + + #region Listen Key client + + EndpointOptions IListenKeyRestClient.StartOptions { get; } = new EndpointOptions(true); + async Task> IListenKeyRestClient.StartListenKeyAsync(StartListenKeyRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IListenKeyRestClient)this).StartOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + + // Get data + var result = await Account.StartUserStreamAsync(ct: ct).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult(Exchange, default); + + return result.AsExchangeResult(Exchange, result.Data); + } + EndpointOptions IListenKeyRestClient.KeepAliveOptions { get; } = new EndpointOptions(true); + async Task> IListenKeyRestClient.KeepAliveListenKeyAsync(KeepAliveListenKeyRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IListenKeyRestClient)this).KeepAliveOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + + // Get data + var result = await Account.KeepAliveUserStreamAsync(request.ListenKey, ct: ct).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult(Exchange, default); + + return result.AsExchangeResult(Exchange, request.ListenKey); + } + + EndpointOptions IListenKeyRestClient.StopOptions { get; } = new EndpointOptions(true); + async Task> IListenKeyRestClient.StopListenKeyAsync(StopListenKeyRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IListenKeyRestClient)this).StopOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + + // Get data + var result = await Account.StopUserStreamAsync(request.ListenKey, ct: ct).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult(Exchange, default); + + return result.AsExchangeResult(Exchange, request.ListenKey); + } + #endregion } } diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs index a9f8c4cfa..293e09894 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs @@ -84,20 +84,20 @@ async Task> IBookTickerSocketClient.Subscribe #endregion #region Balance client - SubscriptionOptions IBalanceSocketClient.SubscribeBalanceOptions { get; } = new SubscriptionOptions("SubscribeBalanceRequest", false) + SubscriptionOptions IBalanceSocketClient.SubscribeBalanceOptions { get; } = new SubscriptionOptions(false) { - RequiredExchangeParameters = new List + RequiredOptionalParameters = new List { - new ParameterDescription("ListenKey", typeof(string), "Listenkey for the user stream", "123123123") + new ParameterDescription(nameof(SubscribeBalancesRequest.ListenKey), typeof(string), "The listenkey for starting the user stream", "123123123") } }; - async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(Action>> handler, ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(SubscribeBalancesRequest request, Action>> handler, ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); + var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, request, exchangeParameters, apiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); - var result = await Account.SubscribeToUserDataUpdatesAsync(exchangeParameters.GetValue(Exchange, "ListenKey"), + var result = await Account.SubscribeToUserDataUpdatesAsync(request.ListenKey!, onAccountPositionMessage: update => handler(update.AsExchangeEvent>(Exchange, update.Data.Balances.Select(x => new SharedBalance(x.Asset, x.Available, x.Total)).ToArray())), ct: ct).ConfigureAwait(false); @@ -108,20 +108,20 @@ async Task> IBalanceSocketClient.SubscribeToB #region Spot Order client - SubscriptionOptions ISpotOrderSocketClient.SubscribeSpotOrderOptions { get; } = new SubscriptionOptions("SubscribeSpotOrderRequest", false) + SubscriptionOptions ISpotOrderSocketClient.SubscribeSpotOrderOptions { get; } = new SubscriptionOptions(false) { - RequiredExchangeParameters = new List + RequiredOptionalParameters = new List { - new ParameterDescription("ListenKey", typeof(string), "Listenkey for the user stream", "123123123") + new ParameterDescription(nameof(SubscribeSpotOrderRequest.ListenKey), typeof(string), "Listenkey for the user stream", "123123123") } }; - async Task> ISpotOrderSocketClient.SubscribeToSpotOrderUpdatesAsync(Action>> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> ISpotOrderSocketClient.SubscribeToSpotOrderUpdatesAsync(SubscribeSpotOrderRequest request, Action>> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) { var validationError = ((ISpotOrderSocketClient)this).SubscribeSpotOrderOptions.ValidateRequest(Exchange, exchangeParameters, ApiType.Spot, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); - var result = await Account.SubscribeToUserDataUpdatesAsync(exchangeParameters.GetValue(Exchange, "ListenKey"), + var result = await Account.SubscribeToUserDataUpdatesAsync(request.ListenKey!, onOrderUpdateMessage: update => handler(update.AsExchangeEvent>(Exchange, new[] { new SharedSpotOrder( update.Data.Symbol, diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs index 609877e95..ab89d8e2b 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -266,10 +266,10 @@ async Task>> IRecentTradeRestClient.G SharedTimeInForce.FillOrKill }, new SharedQuantitySupport( - SharedQuantityType.BaseAssetQuantity, - SharedQuantityType.BaseAssetQuantity, - SharedQuantityType.BaseAssetQuantity, - SharedQuantityType.BaseAssetQuantity)); + SharedQuantityType.BaseAsset, + SharedQuantityType.BaseAsset, + SharedQuantityType.BaseAsset, + SharedQuantityType.BaseAsset)); async Task> IFuturesOrderRestClient.PlaceFuturesOrderAsync(PlaceFuturesOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) { @@ -277,7 +277,7 @@ async Task> IFuturesOrderRestClient.PlaceFuturesOrde if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var result = await Trading.PlaceOrderAsync( + var result = await Trading.PlaceOrderAsync( request.Symbol.GetSymbol(FormatSymbol), request.Side == SharedOrderSide.Buy ? Enums.OrderSide.Buy : Enums.OrderSide.Sell, request.OrderType == SharedOrderType.Limit ? Enums.FuturesOrderType.Limit : Enums.FuturesOrderType.Market, @@ -843,5 +843,51 @@ async Task> IPositionModeRestClient. } #endregion + #region Listen Key client + + EndpointOptions IListenKeyRestClient.StartOptions { get; } = new EndpointOptions(true); + async Task> IListenKeyRestClient.StartListenKeyAsync(StartListenKeyRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IListenKeyRestClient)this).StartOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + + // Get data + var result = await Account.StartUserStreamAsync(ct: ct).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult(Exchange, default); + + return result.AsExchangeResult(Exchange, result.Data); + } + EndpointOptions IListenKeyRestClient.KeepAliveOptions { get; } = new EndpointOptions(true); + async Task> IListenKeyRestClient.KeepAliveListenKeyAsync(KeepAliveListenKeyRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IListenKeyRestClient)this).KeepAliveOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + + // Get data + var result = await Account.KeepAliveUserStreamAsync(request.ListenKey, ct: ct).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult(Exchange, default); + + return result.AsExchangeResult(Exchange, request.ListenKey); + } + + EndpointOptions IListenKeyRestClient.StopOptions { get; } = new EndpointOptions(true); + async Task> IListenKeyRestClient.StopListenKeyAsync(StopListenKeyRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + { + var validationError = ((IListenKeyRestClient)this).StopOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + if (validationError != null) + return new ExchangeWebResult(Exchange, validationError); + + // Get data + var result = await Account.StopUserStreamAsync(request.ListenKey, ct: ct).ConfigureAwait(false); + if (!result) + return result.AsExchangeResult(Exchange, default); + + return result.AsExchangeResult(Exchange, request.ListenKey); + } + #endregion } } diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs index c1d18eb33..bdd15109f 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs @@ -99,23 +99,21 @@ async Task> IBookTickerSocketClient.Subscribe #endregion #region Balance client - SubscriptionOptions IBalanceSocketClient.SubscribeBalanceOptions { get; } = new SubscriptionOptions("SubscribeBalanceRequest", false) + SubscriptionOptions IBalanceSocketClient.SubscribeBalanceOptions { get; } = new SubscriptionOptions(false) { - RequiredExchangeParameters = new List + RequiredOptionalParameters = new List { - new ParameterDescription("ListenKey", typeof(string), "The listenkey for starting the user stream", "123123123") + new ParameterDescription(nameof(SubscribeBalancesRequest.ListenKey), typeof(string), "The listenkey for starting the user stream", "123123123") } }; - async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(Action>> handler, ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(SubscribeBalancesRequest request, Action>> handler, ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); + var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, request, exchangeParameters, apiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); - var listenKey = exchangeParameters.GetValue(Exchange, "ListenKey"); - var result = await SubscribeToUserDataUpdatesAsync(listenKey!, -#warning correct? - onAccountUpdate: update => handler(update.AsExchangeEvent>(Exchange, update.Data.UpdateData.Balances.Select(x => new SharedBalance(x.Asset, x.WalletBalance, x.WalletBalance + x.CrossWalletBalance)).ToArray())), + var result = await SubscribeToUserDataUpdatesAsync(request.ListenKey!, + onAccountUpdate: update => handler(update.AsExchangeEvent>(Exchange, update.Data.UpdateData.Balances.Select(x => new SharedBalance(x.Asset, x.WalletBalance, x.WalletBalance)).ToArray())), ct: ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -125,21 +123,20 @@ async Task> IBalanceSocketClient.SubscribeToB #region Futures Order client - SubscriptionOptions IFuturesOrderSocketClient.SubscribeFuturesOrderOptions { get; } = new SubscriptionOptions("SubscribeFuturesOrderRequest", false) + SubscriptionOptions IFuturesOrderSocketClient.SubscribeFuturesOrderOptions { get; } = new SubscriptionOptions(false) { - RequiredExchangeParameters = new List + RequiredOptionalParameters = new List { - new ParameterDescription("ListenKey", typeof(string), "The listenkey for starting the user stream", "123123123") + new ParameterDescription(nameof(SubscribeFuturesOrderRequest.ListenKey), typeof(string), "The listenkey for starting the user stream", "123123123") } }; - async Task> IFuturesOrderSocketClient.SubscribeToFuturesOrderUpdatesAsync(Action>> handler, ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IFuturesOrderSocketClient.SubscribeToFuturesOrderUpdatesAsync(SubscribeFuturesOrderRequest request, Action>> handler, ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); + var validationError = ((IFuturesOrderSocketClient)this).SubscribeFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, apiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); - var listenKey = exchangeParameters.GetValue(Exchange, "ListenKey"); - var result = await SubscribeToUserDataUpdatesAsync(listenKey, + var result = await SubscribeToUserDataUpdatesAsync(request.ListenKey!, onOrderUpdate: update => handler(update.AsExchangeEvent>(Exchange, new[] { new SharedFuturesOrder( update.Data.UpdateData.Symbol, @@ -207,21 +204,20 @@ async Task> IOrderBookSocketClient.SubscribeT #endregion #region Position client - SubscriptionOptions IPositionSocketClient.SubscribePositionOptions { get; } = new SubscriptionOptions("SubscribePositionRequest", false) + SubscriptionOptions IPositionSocketClient.SubscribePositionOptions { get; } = new SubscriptionOptions(false) { - RequiredExchangeParameters = new List + RequiredOptionalParameters = new List { - new ParameterDescription("ListenKey", typeof(string), "The listenkey for starting the user stream", "123123123") + new ParameterDescription(nameof(SubscribePositionRequest.ListenKey), typeof(string), "The listenkey for starting the user stream", "123123123") } }; - async Task> IPositionSocketClient.SubscribeToPositionUpdatesAsync(Action>> handler, ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IPositionSocketClient.SubscribeToPositionUpdatesAsync(SubscribePositionRequest request, Action>> handler, ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) { - var validationError = ((IPositionSocketClient)this).SubscribePositionOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); + var validationError = ((IPositionSocketClient)this).SubscribePositionOptions.ValidateRequest(Exchange, request, exchangeParameters, apiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); - var listenKey = exchangeParameters.GetValue(Exchange, "ListenKey"); - var result = await SubscribeToUserDataUpdatesAsync(listenKey!, + var result = await SubscribeToUserDataUpdatesAsync(request.ListenKey!, onAccountUpdate: update => handler(update.AsExchangeEvent>(Exchange, update.Data.UpdateData.Positions.Select(x => new SharedPosition(x.Symbol, x.Quantity, update.Data.EventTime) { AverageEntryPrice = x.EntryPrice, diff --git a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs index ae3a6ef11..f9b2f4e4a 100644 --- a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs @@ -21,7 +21,8 @@ public interface IBinanceRestClientCoinFuturesApiShared : IOpenInterestRestClient, IFundingRateRestClient, IBalanceRestClient, - IPositionModeRestClient + IPositionModeRestClient, + IListenKeyRestClient { } } diff --git a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs index badcc5100..888f32d37 100644 --- a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs @@ -18,7 +18,8 @@ public interface IBinanceRestClientSpotApiShared: ISpotTickerRestClient, ITradeHistoryRestClient, IWithdrawalRestClient, - IWithdrawRestClient + IWithdrawRestClient, + IListenKeyRestClient { } } diff --git a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs index fbe3d9502..10ffe48ca 100644 --- a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs @@ -21,7 +21,8 @@ public interface IBinanceRestClientUsdFuturesApiShared : IOrderBookRestClient, IOpenInterestRestClient, IFundingRateRestClient, - IPositionModeRestClient + IPositionModeRestClient, + IListenKeyRestClient { } } From b46a84cf7d2aee77f74105693dffe69de3efcd7b Mon Sep 17 00:00:00 2001 From: Jkorf Date: Fri, 13 Sep 2024 17:50:14 +0200 Subject: [PATCH 37/54] wip --- .../BinanceRestClientCoinFuturesApiShared.cs | 114 +++++++++--------- ...BinanceSocketClientCoinFuturesApiShared.cs | 42 +++---- .../SpotApi/BinanceRestClientSpotApiShared.cs | 102 ++++++++-------- .../BinanceSocketClientSpotApiShared.cs | 34 +++--- .../BinanceRestClientUsdFuturesApiShared.cs | 114 +++++++++--------- .../BinanceSocketClientUsdFuturesApiShared.cs | 42 +++---- 6 files changed, 224 insertions(+), 224 deletions(-) diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs index ec4aab501..0579695d0 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -26,13 +26,13 @@ internal partial class BinanceRestClientCoinFuturesApi : IBinanceRestClientCoinF MaxRequestDataPoints = 1000 }; - async Task>> IKlineRestClient.GetKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IKlineRestClient.GetKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, CancellationToken ct) { var interval = (Enums.KlineInterval)request.Interval; if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -80,10 +80,10 @@ async Task>> IKlineRestClient.GetKlin #region Futures Symbol client - EndpointOptions IFuturesSymbolRestClient.GetFuturesSymbolsOptions { get; } = new EndpointOptions(false); - async Task>> IFuturesSymbolRestClient.GetFuturesSymbolsAsync(GetFuturesSymbolsRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + EndpointOptions IFuturesSymbolRestClient.GetFuturesSymbolsOptions { get; } = new EndpointOptions(false); + async Task>> IFuturesSymbolRestClient.GetFuturesSymbolsAsync(GetSymbolsRequest request, CancellationToken ct) { - var validationError = ((IFuturesSymbolRestClient)this).GetFuturesSymbolsOptions.ValidateRequest(Exchange, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IFuturesSymbolRestClient)this).GetFuturesSymbolsOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -110,9 +110,9 @@ async Task>> IFuturesSymbolRe #region Ticker client EndpointOptions IFuturesTickerRestClient.GetFuturesTickerOptions { get; } = new EndpointOptions(false); - async Task> IFuturesTickerRestClient.GetFuturesTickerAsync(GetTickerRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IFuturesTickerRestClient.GetFuturesTickerAsync(GetTickerRequest request, CancellationToken ct) { - var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -140,9 +140,9 @@ async Task> IFuturesTickerRestClient.GetF } EndpointOptions IFuturesTickerRestClient.GetFuturesTickersOptions { get; } = new EndpointOptions(false); - async Task>> IFuturesTickerRestClient.GetFuturesTickersAsync(GetTickersRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IFuturesTickerRestClient.GetFuturesTickersAsync(GetTickersRequest request, CancellationToken ct) { - var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickerOptions.ValidateRequest(Exchange, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickersOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -172,9 +172,9 @@ async Task>> IFuturesTickerRe #region Recent Trade client GetRecentTradesOptions IRecentTradeRestClient.GetRecentTradesOptions { get; } = new GetRecentTradesOptions(1000, false); - async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, CancellationToken ct) { - var validationError = ((IRecentTradeRestClient)this).GetRecentTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IRecentTradeRestClient)this).GetRecentTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -210,9 +210,9 @@ async Task>> IRecentTradeRestClient.G SharedQuantityType.Contracts, SharedQuantityType.Contracts)); - async Task> IFuturesOrderRestClient.PlaceFuturesOrderAsync(PlaceFuturesOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IFuturesOrderRestClient.PlaceFuturesOrderAsync(PlaceFuturesOrderRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).PlaceFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).PlaceFuturesOrderOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -235,9 +235,9 @@ async Task> IFuturesOrderRestClient.PlaceFuturesOrde } EndpointOptions IFuturesOrderRestClient.GetFuturesOrderOptions { get; } = new EndpointOptions(true); - async Task> IFuturesOrderRestClient.GetFuturesOrderAsync(GetOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IFuturesOrderRestClient.GetFuturesOrderAsync(GetOrderRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -270,9 +270,9 @@ async Task> IFuturesOrderRestClient.GetFut } EndpointOptions IFuturesOrderRestClient.GetOpenFuturesOrdersOptions { get; } = new EndpointOptions(true); - async Task>> IFuturesOrderRestClient.GetOpenFuturesOrdersAsync(GetOpenOrdersRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IFuturesOrderRestClient.GetOpenFuturesOrdersAsync(GetOpenOrdersRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetOpenFuturesOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol?.ApiType ?? request.ApiType!.Value, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetOpenFuturesOrdersOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.ApiType!.Value, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -303,9 +303,9 @@ async Task>> IFuturesOrderRest } PaginatedEndpointOptions IFuturesOrderRestClient.GetClosedFuturesOrdersOptions { get; } = new PaginatedEndpointOptions(SharedPaginationType.Descending, true); - async Task>> IFuturesOrderRestClient.GetClosedFuturesOrdersAsync(GetClosedOrdersRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IFuturesOrderRestClient.GetClosedFuturesOrdersAsync(GetClosedOrdersRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetClosedFuturesOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetClosedFuturesOrdersOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -350,9 +350,9 @@ async Task>> IFuturesOrderRest } EndpointOptions IFuturesOrderRestClient.GetFuturesOrderTradesOptions { get; } = new EndpointOptions(true); - async Task>> IFuturesOrderRestClient.GetFuturesOrderTradesAsync(GetOrderTradesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IFuturesOrderRestClient.GetFuturesOrderTradesAsync(GetOrderTradesRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -380,9 +380,9 @@ async Task>> IFuturesOrderRestCli } PaginatedEndpointOptions IFuturesOrderRestClient.GetFuturesUserTradesOptions { get; } = new PaginatedEndpointOptions(SharedPaginationType.Descending, true); - async Task>> IFuturesOrderRestClient.GetFuturesUserTradesAsync(GetUserTradesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IFuturesOrderRestClient.GetFuturesUserTradesAsync(GetUserTradesRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetFuturesUserTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetFuturesUserTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -424,9 +424,9 @@ async Task>> IFuturesOrderRestCli } EndpointOptions IFuturesOrderRestClient.CancelFuturesOrderOptions { get; } = new EndpointOptions(true); - async Task> IFuturesOrderRestClient.CancelFuturesOrderAsync(CancelOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IFuturesOrderRestClient.CancelFuturesOrderAsync(CancelOrderRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).CancelFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).CancelFuturesOrderOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -441,9 +441,9 @@ async Task> IFuturesOrderRestClient.CancelFuturesOrd } EndpointOptions IFuturesOrderRestClient.GetPositionsOptions { get; } = new EndpointOptions(true); - async Task>> IFuturesOrderRestClient.GetPositionsAsync(GetPositionsRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IFuturesOrderRestClient.GetPositionsAsync(GetPositionsRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetPositionsOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol?.ApiType ?? request.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetPositionsOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -470,9 +470,9 @@ async Task>> IFuturesOrderRestClie new ParameterDescription(nameof(ClosePositionRequest.Quantity), typeof(decimal), "Quantity of the position is required", 0.1m) } }; - async Task> IFuturesOrderRestClient.ClosePositionAsync(ClosePositionRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IFuturesOrderRestClient.ClosePositionAsync(ClosePositionRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).ClosePositionOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).ClosePositionOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -534,9 +534,9 @@ private SharedOrderType ParseOrderType(FuturesOrderType type) #region Leverage client EndpointOptions ILeverageRestClient.GetLeverageOptions { get; } = new EndpointOptions(true); - async Task> ILeverageRestClient.GetLeverageAsync(GetLeverageRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> ILeverageRestClient.GetLeverageAsync(GetLeverageRequest request, CancellationToken ct) { - var validationError = ((ILeverageRestClient)this).GetLeverageOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ILeverageRestClient)this).GetLeverageOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -556,9 +556,9 @@ async Task> ILeverageRestClient.GetLeverageAsy } SetLeverageOptions ILeverageRestClient.SetLeverageOptions { get; } = new SetLeverageOptions(true); - async Task> ILeverageRestClient.SetLeverageAsync(SetLeverageRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> ILeverageRestClient.SetLeverageAsync(SetLeverageRequest request, CancellationToken ct) { - var validationError = ((ILeverageRestClient)this).SetLeverageOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ILeverageRestClient)this).SetLeverageOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -577,13 +577,13 @@ async Task> ILeverageRestClient.SetLeverageAsy MaxRequestDataPoints = 1000 }; - async Task>> IMarkPriceKlineRestClient.GetMarkPriceKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IMarkPriceKlineRestClient.GetMarkPriceKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, CancellationToken ct) { var interval = (Enums.KlineInterval)request.Interval; if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IMarkPriceKlineRestClient)this).GetMarkPriceKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IMarkPriceKlineRestClient)this).GetMarkPriceKlinesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -631,9 +631,9 @@ async Task>> IMarkPriceKlineRestC #region Order Book client GetOrderBookOptions IOrderBookRestClient.GetOrderBookOptions { get; } = new GetOrderBookOptions(new[] { 5, 10, 20, 50, 100, 500, 1000 }, false); - async Task> IOrderBookRestClient.GetOrderBookAsync(GetOrderBookRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IOrderBookRestClient.GetOrderBookAsync(GetOrderBookRequest request, CancellationToken ct) { - var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -652,9 +652,9 @@ async Task> IOrderBookRestClient.GetOrderBook #region Trade History client GetTradeHistoryOptions ITradeHistoryRestClient.GetTradeHistoryOptions { get; } = new GetTradeHistoryOptions(SharedPaginationType.Ascending, false); - async Task>> ITradeHistoryRestClient.GetTradeHistoryAsync(GetTradeHistoryRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> ITradeHistoryRestClient.GetTradeHistoryAsync(GetTradeHistoryRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((ITradeHistoryRestClient)this).GetTradeHistoryOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ITradeHistoryRestClient)this).GetTradeHistoryOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -689,13 +689,13 @@ async Task>> ITradeHistoryRestClient. MaxRequestDataPoints = 1000 }; - async Task>> IIndexPriceKlineRestClient.GetIndexPriceKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IIndexPriceKlineRestClient.GetIndexPriceKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, CancellationToken ct) { var interval = (Enums.KlineInterval)request.Interval; if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IIndexPriceKlineRestClient)this).GetIndexPriceKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IIndexPriceKlineRestClient)this).GetIndexPriceKlinesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -744,9 +744,9 @@ async Task>> IIndexPriceKlineRest #region Open Interest client EndpointOptions IOpenInterestRestClient.GetOpenInterestOptions { get; } = new EndpointOptions(false); - async Task> IOpenInterestRestClient.GetOpenInterestAsync(GetOpenInterestRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IOpenInterestRestClient.GetOpenInterestAsync(GetOpenInterestRequest request, CancellationToken ct) { - var validationError = ((IOpenInterestRestClient)this).GetOpenInterestOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IOpenInterestRestClient)this).GetOpenInterestOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -762,9 +762,9 @@ async Task> IOpenInterestRestClient.GetOpe #region Funding Rate client GetFundingRateHistoryOptions IFundingRateRestClient.GetFundingRateHistoryOptions { get; } = new GetFundingRateHistoryOptions(SharedPaginationType.Ascending, false); - async Task>> IFundingRateRestClient.GetFundingRateHistoryAsync(GetFundingRateHistoryRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IFundingRateRestClient.GetFundingRateHistoryAsync(GetFundingRateHistoryRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((IFundingRateRestClient)this).GetFundingRateHistoryOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFundingRateRestClient)this).GetFundingRateHistoryOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -794,9 +794,9 @@ async Task>> IFundingRateRestCl #region Balance Client EndpointOptions IBalanceRestClient.GetBalancesOptions { get; } = new EndpointOptions(true); - async Task>> IBalanceRestClient.GetBalancesAsync(GetBalancesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IBalanceRestClient.GetBalancesAsync(GetBalancesRequest request, CancellationToken ct) { - var validationError = ((IBalanceRestClient)this).GetBalancesOptions.ValidateRequest(Exchange, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IBalanceRestClient)this).GetBalancesOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -812,9 +812,9 @@ async Task>> IBalanceRestClient.Get #region Position Mode client GetPositionModeOptions IPositionModeRestClient.GetPositionModeOptions { get; } = new GetPositionModeOptions(false); - async Task> IPositionModeRestClient.GetPositionModeAsync(GetPositionModeRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IPositionModeRestClient.GetPositionModeAsync(GetPositionModeRequest request, CancellationToken ct) { - var validationError = ((IPositionModeRestClient)this).GetPositionModeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol?.ApiType ?? request.ApiType, SupportedApiTypes); + var validationError = ((IPositionModeRestClient)this).GetPositionModeOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -826,9 +826,9 @@ async Task> IPositionModeRestClient. } SetPositionModeOptions IPositionModeRestClient.SetPositionModeOptions { get; } = new SetPositionModeOptions(true, true, false); - async Task> IPositionModeRestClient.SetPositionModeAsync(SetPositionModeRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IPositionModeRestClient.SetPositionModeAsync(SetPositionModeRequest request, CancellationToken ct) { - var validationError = ((IPositionModeRestClient)this).SetPositionModeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol?.ApiType ?? request.ApiType, SupportedApiTypes); + var validationError = ((IPositionModeRestClient)this).SetPositionModeOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -843,9 +843,9 @@ async Task> IPositionModeRestClient. #region Listen Key client EndpointOptions IListenKeyRestClient.StartOptions { get; } = new EndpointOptions(true); - async Task> IListenKeyRestClient.StartListenKeyAsync(StartListenKeyRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IListenKeyRestClient.StartListenKeyAsync(StartListenKeyRequest request, CancellationToken ct) { - var validationError = ((IListenKeyRestClient)this).StartOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IListenKeyRestClient)this).StartOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -857,9 +857,9 @@ async Task> IListenKeyRestClient.StartListenKeyAsync(S return result.AsExchangeResult(Exchange, result.Data); } EndpointOptions IListenKeyRestClient.KeepAliveOptions { get; } = new EndpointOptions(true); - async Task> IListenKeyRestClient.KeepAliveListenKeyAsync(KeepAliveListenKeyRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IListenKeyRestClient.KeepAliveListenKeyAsync(KeepAliveListenKeyRequest request, CancellationToken ct) { - var validationError = ((IListenKeyRestClient)this).KeepAliveOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IListenKeyRestClient)this).KeepAliveOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -872,9 +872,9 @@ async Task> IListenKeyRestClient.KeepAliveListenKeyAsy } EndpointOptions IListenKeyRestClient.StopOptions { get; } = new EndpointOptions(true); - async Task> IListenKeyRestClient.StopListenKeyAsync(StopListenKeyRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IListenKeyRestClient.StopListenKeyAsync(StopListenKeyRequest request, CancellationToken ct) { - var validationError = ((IListenKeyRestClient)this).StopOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IListenKeyRestClient)this).StopOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs index c36732fc7..da67980e5 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs @@ -24,9 +24,9 @@ internal partial class BinanceSocketClientCoinFuturesApi : IBinanceSocketClientC #region Ticker client SubscriptionOptions ITickerSocketClient.SubscribeTickerOptions { get; } = new SubscriptionOptions(false); - async Task> ITickerSocketClient.SubscribeToTickerUpdatesAsync(SubscribeTickerRequest request, Action> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> ITickerSocketClient.SubscribeToTickerUpdatesAsync(SubscribeTickerRequest request, Action> handler, CancellationToken ct) { - var validationError = ((ITickerSocketClient)this).SubscribeTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ITickerSocketClient)this).SubscribeTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -40,18 +40,18 @@ async Task> ITickerSocketClient.SubscribeToTi #region Tickers client - SubscriptionOptions ITickersSocketClient.SubscribeAllTickersOptions { get; } = new SubscriptionOptions("SubscribeTickersRequest", false); - async Task> ITickersSocketClient.SubscribeToAllTickersUpdatesAsync(Action>> handler, ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + SubscriptionOptions ITickersSocketClient.SubscribeAllTickersOptions { get; } = new SubscriptionOptions(false); + async Task> ITickersSocketClient.SubscribeToAllTickersUpdatesAsync(SubscribeAllTickersRequest request, Action>> handler, CancellationToken ct) { - var validationError = ((ITickersSocketClient)this).SubscribeAllTickersOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); + var validationError = ((ITickersSocketClient)this).SubscribeAllTickersOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); var result = await SubscribeToAllTickerUpdatesAsync(update => { var data = update.Data; - if (apiType != null) - data = update.Data.Where(x => apiType == ApiType.PerpetualInverse ? x.Symbol.EndsWith("_PERP") : !x.Symbol.Contains("_PERP")); + if (request.ApiType != null) + data = update.Data.Where(x => request.ApiType == ApiType.PerpetualInverse ? x.Symbol.EndsWith("_PERP") : !x.Symbol.Contains("_PERP")); if (!data.Any()) return; @@ -67,9 +67,9 @@ async Task> ITickersSocketClient.SubscribeToA #region Trade client SubscriptionOptions ITradeSocketClient.SubscribeTradeOptions { get; } = new SubscriptionOptions(false); - async Task> ITradeSocketClient.SubscribeToTradeUpdatesAsync(SubscribeTradeRequest request, Action>> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> ITradeSocketClient.SubscribeToTradeUpdatesAsync(SubscribeTradeRequest request, Action>> handler, CancellationToken ct) { - var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -84,9 +84,9 @@ async Task> ITradeSocketClient.SubscribeToTra #region Book Ticker client SubscriptionOptions IBookTickerSocketClient.SubscribeBookTickerOptions { get; } = new SubscriptionOptions(false); - async Task> IBookTickerSocketClient.SubscribeToBookTickerUpdatesAsync(SubscribeBookTickerRequest request, Action> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IBookTickerSocketClient.SubscribeToBookTickerUpdatesAsync(SubscribeBookTickerRequest request, Action> handler, CancellationToken ct) { - var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -100,13 +100,13 @@ async Task> IBookTickerSocketClient.Subscribe #region Kline client SubscribeKlineOptions IKlineSocketClient.SubscribeKlineOptions { get; } = new SubscribeKlineOptions(false); - async Task> IKlineSocketClient.SubscribeToKlineUpdatesAsync(SubscribeKlineRequest request, Action> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IKlineSocketClient.SubscribeToKlineUpdatesAsync(SubscribeKlineRequest request, Action> handler, CancellationToken ct) { var interval = (Enums.KlineInterval)request.Interval; if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeResult(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -119,9 +119,9 @@ async Task> IKlineSocketClient.SubscribeToKli #region Order Book client SubscribeOrderBookOptions IOrderBookSocketClient.SubscribeOrderBookOptions { get; } = new SubscribeOrderBookOptions(false, new[] { 5, 10, 20 }); - async Task> IOrderBookSocketClient.SubscribeToOrderBookUpdatesAsync(SubscribeOrderBookRequest request, Action> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IOrderBookSocketClient.SubscribeToOrderBookUpdatesAsync(SubscribeOrderBookRequest request, Action> handler, CancellationToken ct) { - var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -140,9 +140,9 @@ async Task> IOrderBookSocketClient.SubscribeT new ParameterDescription(nameof(SubscribeBalancesRequest.ListenKey), typeof(string), "The listenkey for starting the user stream", "123123123") } }; - async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(SubscribeBalancesRequest request, Action>> handler, ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(SubscribeBalancesRequest request, Action>> handler, CancellationToken ct) { - var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, request, exchangeParameters, apiType, SupportedApiTypes); + var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -163,9 +163,9 @@ async Task> IBalanceSocketClient.SubscribeToB new ParameterDescription(nameof(SubscribePositionRequest.ListenKey), typeof(string), "The listenkey for starting the user stream", "123123123") } }; - async Task> IPositionSocketClient.SubscribeToPositionUpdatesAsync(SubscribePositionRequest request, Action>> handler, ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IPositionSocketClient.SubscribeToPositionUpdatesAsync(SubscribePositionRequest request, Action>> handler, CancellationToken ct) { - var validationError = ((IPositionSocketClient)this).SubscribePositionOptions.ValidateRequest(Exchange, request, exchangeParameters, apiType, SupportedApiTypes); + var validationError = ((IPositionSocketClient)this).SubscribePositionOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -193,9 +193,9 @@ async Task> IPositionSocketClient.SubscribeTo } }; - async Task> IFuturesOrderSocketClient.SubscribeToFuturesOrderUpdatesAsync(SubscribeFuturesOrderRequest request, Action>> handler, ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IFuturesOrderSocketClient.SubscribeToFuturesOrderUpdatesAsync(SubscribeFuturesOrderRequest request, Action>> handler, CancellationToken ct) { - var validationError = ((IFuturesOrderSocketClient)this).SubscribeFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, apiType, SupportedApiTypes); + var validationError = ((IFuturesOrderSocketClient)this).SubscribeFuturesOrderOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index 84b361998..b0329a632 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -23,13 +23,13 @@ internal partial class BinanceRestClientSpotApi : IBinanceRestClientSpotApiShare MaxRequestDataPoints = 1000 }; - async Task>> IKlineRestClient.GetKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IKlineRestClient.GetKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, CancellationToken ct) { var interval = (Enums.KlineInterval)request.Interval; if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -80,11 +80,11 @@ async Task>> IKlineRestClient.GetKlin #endregion #region Spot Symbol client - EndpointOptions ISpotSymbolRestClient.GetSpotSymbolsOptions { get; } = new EndpointOptions("GetSpotSymbolsRequest", false); + EndpointOptions ISpotSymbolRestClient.GetSpotSymbolsOptions { get; } = new EndpointOptions(false); - async Task>> ISpotSymbolRestClient.GetSpotSymbolsAsync(ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> ISpotSymbolRestClient.GetSpotSymbolsAsync(GetSymbolsRequest request, CancellationToken ct) { - var validationError = ((ISpotSymbolRestClient)this).GetSpotSymbolsOptions.ValidateRequest(Exchange, exchangeParameters, ApiType.Spot, SupportedApiTypes); + var validationError = ((ISpotSymbolRestClient)this).GetSpotSymbolsOptions.ValidateRequest(Exchange, request, ApiType.Spot, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -107,9 +107,9 @@ async Task>> ISpotSymbolRestClie #region Ticker client EndpointOptions ISpotTickerRestClient.GetSpotTickerOptions { get; } = new EndpointOptions(false); - async Task> ISpotTickerRestClient.GetSpotTickerAsync(GetTickerRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> ISpotTickerRestClient.GetSpotTickerAsync(GetTickerRequest request, CancellationToken ct) { - var validationError = ((ISpotTickerRestClient)this).GetSpotTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ISpotTickerRestClient)this).GetSpotTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -120,10 +120,10 @@ async Task> ISpotTickerRestClient.GetSpotTic return result.AsExchangeResult(Exchange, new SharedSpotTicker(result.Data.Symbol, result.Data.LastPrice, result.Data.HighPrice, result.Data.LowPrice, result.Data.Volume, result.Data.PriceChangePercent)); } - EndpointOptions ISpotTickerRestClient.GetSpotTickersOptions { get; } = new EndpointOptions("GetSpotTickersRequest", false); - async Task>> ISpotTickerRestClient.GetSpotTickersAsync(ExchangeParameters? exchangeParameters, CancellationToken ct) + EndpointOptions ISpotTickerRestClient.GetSpotTickersOptions { get; } = new EndpointOptions(false); + async Task>> ISpotTickerRestClient.GetSpotTickersAsync(GetTickersRequest request, CancellationToken ct) { - var validationError = ((ISpotTickerRestClient)this).GetSpotTickersOptions.ValidateRequest(Exchange, exchangeParameters, ApiType.Spot, SupportedApiTypes); + var validationError = ((ISpotTickerRestClient)this).GetSpotTickersOptions.ValidateRequest(Exchange, request, ApiType.Spot, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -139,9 +139,9 @@ async Task>> ISpotTickerRestClie #region Recent Trades client GetRecentTradesOptions IRecentTradeRestClient.GetRecentTradesOptions { get; } = new GetRecentTradesOptions(1000, false); - async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, CancellationToken ct) { - var validationError = ((IRecentTradeRestClient)this).GetRecentTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IRecentTradeRestClient)this).GetRecentTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -161,9 +161,9 @@ async Task>> IRecentTradeRestClient.G #region Trade History client GetTradeHistoryOptions ITradeHistoryRestClient.GetTradeHistoryOptions { get; } = new GetTradeHistoryOptions(SharedPaginationType.Ascending, false); - async Task>> ITradeHistoryRestClient.GetTradeHistoryAsync(GetTradeHistoryRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> ITradeHistoryRestClient.GetTradeHistoryAsync(GetTradeHistoryRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((ITradeHistoryRestClient)this).GetTradeHistoryOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ITradeHistoryRestClient)this).GetTradeHistoryOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -193,9 +193,9 @@ async Task>> ITradeHistoryRestClient. #region Order Book client GetOrderBookOptions IOrderBookRestClient.GetOrderBookOptions { get; } = new GetOrderBookOptions(1, 5000, false); - async Task> IOrderBookRestClient.GetOrderBookAsync(GetOrderBookRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IOrderBookRestClient.GetOrderBookAsync(GetOrderBookRequest request, CancellationToken ct) { - var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -214,9 +214,9 @@ async Task> IOrderBookRestClient.GetOrderBook #region Balance Client EndpointOptions IBalanceRestClient.GetBalancesOptions { get; } = new EndpointOptions(true); - async Task>> IBalanceRestClient.GetBalancesAsync(GetBalancesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IBalanceRestClient.GetBalancesAsync(GetBalancesRequest request, CancellationToken ct) { - var validationError = ((IBalanceRestClient)this).GetBalancesOptions.ValidateRequest(Exchange, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IBalanceRestClient)this).GetBalancesOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -250,9 +250,9 @@ async Task>> IBalanceRestClient.Get SharedQuantityType.BaseAndQuoteAsset, SharedQuantityType.BaseAndQuoteAsset)); - async Task> ISpotOrderRestClient.PlaceSpotOrderAsync(PlaceSpotOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> ISpotOrderRestClient.PlaceSpotOrderAsync(PlaceSpotOrderRequest request, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).PlaceSpotOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ISpotOrderRestClient)this).PlaceSpotOrderOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -274,9 +274,9 @@ async Task> ISpotOrderRestClient.PlaceSpotOrderAsync } EndpointOptions ISpotOrderRestClient.GetSpotOrderOptions { get; } = new EndpointOptions(true); - async Task> ISpotOrderRestClient.GetSpotOrderAsync(GetOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> ISpotOrderRestClient.GetSpotOrderAsync(GetOrderRequest request, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetSpotOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ISpotOrderRestClient)this).GetSpotOrderOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -308,9 +308,9 @@ async Task> ISpotOrderRestClient.GetSpotOrder } EndpointOptions ISpotOrderRestClient.GetOpenSpotOrdersOptions { get; } = new EndpointOptions(true); - async Task>> ISpotOrderRestClient.GetOpenSpotOrdersAsync(GetOpenOrdersRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> ISpotOrderRestClient.GetOpenSpotOrdersAsync(GetOpenOrdersRequest request, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetOpenSpotOrdersOptions.ValidateRequest(Exchange, request,exchangeParameters, request.Symbol?.ApiType ?? request.ApiType!.Value, SupportedApiTypes); + var validationError = ((ISpotOrderRestClient)this).GetOpenSpotOrdersOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.ApiType!.Value, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -340,9 +340,9 @@ async Task>> ISpotOrderRestClient } PaginatedEndpointOptions ISpotOrderRestClient.GetClosedSpotOrdersOptions { get; } = new PaginatedEndpointOptions(SharedPaginationType.Ascending, true); - async Task>> ISpotOrderRestClient.GetClosedSpotOrdersAsync(GetClosedOrdersRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> ISpotOrderRestClient.GetClosedSpotOrdersAsync(GetClosedOrdersRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetClosedSpotOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ISpotOrderRestClient)this).GetClosedSpotOrdersOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -387,9 +387,9 @@ async Task>> ISpotOrderRestClient } EndpointOptions ISpotOrderRestClient.GetSpotOrderTradesOptions { get; } = new EndpointOptions(true); - async Task>> ISpotOrderRestClient.GetSpotOrderTradesAsync(GetOrderTradesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> ISpotOrderRestClient.GetSpotOrderTradesAsync(GetOrderTradesRequest request, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetSpotOrderTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ISpotOrderRestClient)this).GetSpotOrderTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -415,9 +415,9 @@ async Task>> ISpotOrderRestClient } PaginatedEndpointOptions ISpotOrderRestClient.GetSpotUserTradesOptions { get; } = new PaginatedEndpointOptions(SharedPaginationType.Ascending, true); - async Task>> ISpotOrderRestClient.GetSpotUserTradesAsync(GetUserTradesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> ISpotOrderRestClient.GetSpotUserTradesAsync(GetUserTradesRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetSpotUserTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ISpotOrderRestClient)this).GetSpotUserTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -457,9 +457,9 @@ async Task>> ISpotOrderRestClient } EndpointOptions ISpotOrderRestClient.CancelSpotOrderOptions { get; } = new EndpointOptions(true); - async Task> ISpotOrderRestClient.CancelSpotOrderAsync(CancelOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> ISpotOrderRestClient.CancelSpotOrderAsync(CancelOrderRequest request, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).CancelSpotOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ISpotOrderRestClient)this).CancelSpotOrderOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -511,11 +511,11 @@ private SharedOrderType ParseOrderType(SpotOrderType type) #endregion #region Asset client - EndpointOptions IAssetsRestClient.GetAssetsOptions { get; } = new EndpointOptions("GetAssetsRequest", true); + EndpointOptions IAssetsRestClient.GetAssetsOptions { get; } = new EndpointOptions(true); - async Task>> IAssetsRestClient.GetAssetsAsync(ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IAssetsRestClient.GetAssetsAsync(GetAssetsRequest request, CancellationToken ct) { - var validationError = ((IAssetsRestClient)this).GetAssetsOptions.ValidateRequest(Exchange, exchangeParameters, ApiType.Spot, SupportedApiTypes); + var validationError = ((IAssetsRestClient)this).GetAssetsOptions.ValidateRequest(Exchange, request, ApiType.Spot, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -540,9 +540,9 @@ async Task>> IAssetsRestClient.GetAss } EndpointOptions IAssetsRestClient.GetAssetOptions { get; } = new EndpointOptions(false); - async Task> IAssetsRestClient.GetAssetAsync(GetAssetRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IAssetsRestClient.GetAssetAsync(GetAssetRequest request, CancellationToken ct) { - var validationError = ((IAssetsRestClient)this).GetAssetOptions.ValidateRequest(Exchange, request, exchangeParameters, ApiType.Spot, SupportedApiTypes); + var validationError = ((IAssetsRestClient)this).GetAssetOptions.ValidateRequest(Exchange, request, ApiType.Spot, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -575,9 +575,9 @@ async Task> IAssetsRestClient.GetAssetAsync(GetAs #region Deposit client EndpointOptions IDepositRestClient.GetDepositAddressesOptions { get; } = new EndpointOptions(true); - async Task>> IDepositRestClient.GetDepositAddressesAsync(GetDepositAddressesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IDepositRestClient.GetDepositAddressesAsync(GetDepositAddressesRequest request, CancellationToken ct) { - var validationError = ((IDepositRestClient)this).GetDepositAddressesOptions.ValidateRequest(Exchange, request, exchangeParameters, ApiType.Spot, SupportedApiTypes); + var validationError = ((IDepositRestClient)this).GetDepositAddressesOptions.ValidateRequest(Exchange, request, ApiType.Spot, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -593,9 +593,9 @@ async Task>> IDepositRestCli } GetDepositsOptions IDepositRestClient.GetDepositsOptions { get; } = new GetDepositsOptions(SharedPaginationType.Descending, true); - async Task>> IDepositRestClient.GetDepositsAsync(GetDepositsRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IDepositRestClient.GetDepositsAsync(GetDepositsRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((IDepositRestClient)this).GetDepositsOptions.ValidateRequest(Exchange, request, exchangeParameters, ApiType.Spot, SupportedApiTypes); + var validationError = ((IDepositRestClient)this).GetDepositsOptions.ValidateRequest(Exchange, request, ApiType.Spot, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -635,9 +635,9 @@ async Task>> IDepositRestClient.Get #region Withdrawal client GetWithdrawalsOptions IWithdrawalRestClient.GetWithdrawalsOptions { get; } = new GetWithdrawalsOptions(SharedPaginationType.Descending, true); - async Task>> IWithdrawalRestClient.GetWithdrawalsAsync(GetWithdrawalsRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IWithdrawalRestClient.GetWithdrawalsAsync(GetWithdrawalsRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((IWithdrawalRestClient)this).GetWithdrawalsOptions.ValidateRequest(Exchange, request, exchangeParameters, ApiType.Spot, SupportedApiTypes); + var validationError = ((IWithdrawalRestClient)this).GetWithdrawalsOptions.ValidateRequest(Exchange, request, ApiType.Spot, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -678,9 +678,9 @@ async Task>> IWithdrawalRestClie #region Withdraw client WithdrawOptions IWithdrawRestClient.WithdrawOptions { get; } = new WithdrawOptions(); - async Task > IWithdrawRestClient.WithdrawAsync(WithdrawRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task > IWithdrawRestClient.WithdrawAsync(WithdrawRequest request, CancellationToken ct) { - var validationError = ((IWithdrawRestClient)this).WithdrawOptions.ValidateRequest(Exchange, request, exchangeParameters, ApiType.Spot, SupportedApiTypes); + var validationError = ((IWithdrawRestClient)this).WithdrawOptions.ValidateRequest(Exchange, request, ApiType.Spot, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -703,9 +703,9 @@ async Task>> IWithdrawalRestClie #region Listen Key client EndpointOptions IListenKeyRestClient.StartOptions { get; } = new EndpointOptions(true); - async Task> IListenKeyRestClient.StartListenKeyAsync(StartListenKeyRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IListenKeyRestClient.StartListenKeyAsync(StartListenKeyRequest request, CancellationToken ct) { - var validationError = ((IListenKeyRestClient)this).StartOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IListenKeyRestClient)this).StartOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -717,9 +717,9 @@ async Task> IListenKeyRestClient.StartListenKeyAsync(S return result.AsExchangeResult(Exchange, result.Data); } EndpointOptions IListenKeyRestClient.KeepAliveOptions { get; } = new EndpointOptions(true); - async Task> IListenKeyRestClient.KeepAliveListenKeyAsync(KeepAliveListenKeyRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IListenKeyRestClient.KeepAliveListenKeyAsync(KeepAliveListenKeyRequest request, CancellationToken ct) { - var validationError = ((IListenKeyRestClient)this).KeepAliveOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IListenKeyRestClient)this).KeepAliveOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -732,9 +732,9 @@ async Task> IListenKeyRestClient.KeepAliveListenKeyAsy } EndpointOptions IListenKeyRestClient.StopOptions { get; } = new EndpointOptions(true); - async Task> IListenKeyRestClient.StopListenKeyAsync(StopListenKeyRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IListenKeyRestClient.StopListenKeyAsync(StopListenKeyRequest request, CancellationToken ct) { - var validationError = ((IListenKeyRestClient)this).StopOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IListenKeyRestClient)this).StopOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs index 293e09894..9bf2aa276 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs @@ -20,10 +20,10 @@ internal partial class BinanceSocketClientSpotApi : IBinanceSocketClientSpotApiS public ApiType[] SupportedApiTypes => new[] { ApiType.Spot }; #region Tickers client - SubscriptionOptions ITickersSocketClient.SubscribeAllTickersOptions { get; } = new SubscriptionOptions("SubscribeTickersRequest", false); - async Task> ITickersSocketClient.SubscribeToAllTickersUpdatesAsync(Action>> handler, ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + SubscriptionOptions ITickersSocketClient.SubscribeAllTickersOptions { get; } = new SubscriptionOptions(false); + async Task> ITickersSocketClient.SubscribeToAllTickersUpdatesAsync(SubscribeAllTickersRequest request, Action>> handler, CancellationToken ct) { - var validationError = ((ITickersSocketClient)this).SubscribeAllTickersOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); + var validationError = ((ITickersSocketClient)this).SubscribeAllTickersOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -36,9 +36,9 @@ async Task> ITickersSocketClient.SubscribeToA #region Ticker client SubscriptionOptions ITickerSocketClient.SubscribeTickerOptions { get; } = new SubscriptionOptions(false); - async Task> ITickerSocketClient.SubscribeToTickerUpdatesAsync(SubscribeTickerRequest request, Action> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> ITickerSocketClient.SubscribeToTickerUpdatesAsync(SubscribeTickerRequest request, Action> handler, CancellationToken ct) { - var validationError = ((ITickerSocketClient)this).SubscribeTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ITickerSocketClient)this).SubscribeTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -52,9 +52,9 @@ async Task> ITickerSocketClient.SubscribeToTi #region Trade client SubscriptionOptions ITradeSocketClient.SubscribeTradeOptions { get; } = new SubscriptionOptions(false); - async Task> ITradeSocketClient.SubscribeToTradeUpdatesAsync(SubscribeTradeRequest request, Action>> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> ITradeSocketClient.SubscribeToTradeUpdatesAsync(SubscribeTradeRequest request, Action>> handler, CancellationToken ct) { - var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -69,9 +69,9 @@ async Task> ITradeSocketClient.SubscribeToTra #region Book Ticker client SubscriptionOptions IBookTickerSocketClient.SubscribeBookTickerOptions { get; } = new SubscriptionOptions(false); - async Task> IBookTickerSocketClient.SubscribeToBookTickerUpdatesAsync(SubscribeBookTickerRequest request, Action> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IBookTickerSocketClient.SubscribeToBookTickerUpdatesAsync(SubscribeBookTickerRequest request, Action> handler, CancellationToken ct) { - var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -91,9 +91,9 @@ async Task> IBookTickerSocketClient.Subscribe new ParameterDescription(nameof(SubscribeBalancesRequest.ListenKey), typeof(string), "The listenkey for starting the user stream", "123123123") } }; - async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(SubscribeBalancesRequest request, Action>> handler, ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(SubscribeBalancesRequest request, Action>> handler, CancellationToken ct) { - var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, request, exchangeParameters, apiType, SupportedApiTypes); + var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -115,9 +115,9 @@ async Task> IBalanceSocketClient.SubscribeToB new ParameterDescription(nameof(SubscribeSpotOrderRequest.ListenKey), typeof(string), "Listenkey for the user stream", "123123123") } }; - async Task> ISpotOrderSocketClient.SubscribeToSpotOrderUpdatesAsync(SubscribeSpotOrderRequest request, Action>> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> ISpotOrderSocketClient.SubscribeToSpotOrderUpdatesAsync(SubscribeSpotOrderRequest request, Action>> handler, CancellationToken ct) { - var validationError = ((ISpotOrderSocketClient)this).SubscribeSpotOrderOptions.ValidateRequest(Exchange, exchangeParameters, ApiType.Spot, SupportedApiTypes); + var validationError = ((ISpotOrderSocketClient)this).SubscribeSpotOrderOptions.ValidateRequest(Exchange, request, ApiType.Spot, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -155,13 +155,13 @@ async Task> ISpotOrderSocketClient.SubscribeT #region Kline client SubscribeKlineOptions IKlineSocketClient.SubscribeKlineOptions { get; } = new SubscribeKlineOptions(false); - async Task> IKlineSocketClient.SubscribeToKlineUpdatesAsync(SubscribeKlineRequest request, Action> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IKlineSocketClient.SubscribeToKlineUpdatesAsync(SubscribeKlineRequest request, Action> handler, CancellationToken ct) { var interval = (Enums.KlineInterval)request.Interval; if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeResult(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -174,9 +174,9 @@ async Task> IKlineSocketClient.SubscribeToKli #region Order Book client SubscribeOrderBookOptions IOrderBookSocketClient.SubscribeOrderBookOptions { get; } = new SubscribeOrderBookOptions(false, new[] { 5, 10, 20 }); - async Task> IOrderBookSocketClient.SubscribeToOrderBookUpdatesAsync(SubscribeOrderBookRequest request, Action> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IOrderBookSocketClient.SubscribeToOrderBookUpdatesAsync(SubscribeOrderBookRequest request, Action> handler, CancellationToken ct) { - var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs index ab89d8e2b..47fb7e23a 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -29,13 +29,13 @@ internal partial class BinanceRestClientUsdFuturesApi : IBinanceRestClientUsdFut MaxRequestDataPoints = 1000 }; - async Task>> IKlineRestClient.GetKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IKlineRestClient.GetKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, CancellationToken ct) { var interval = (Enums.KlineInterval)request.Interval; if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -88,13 +88,13 @@ async Task>> IKlineRestClient.GetKlin MaxRequestDataPoints = 1000 }; - async Task>> IMarkPriceKlineRestClient.GetMarkPriceKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IMarkPriceKlineRestClient.GetMarkPriceKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, CancellationToken ct) { var interval = (Enums.KlineInterval)request.Interval; if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IMarkPriceKlineRestClient)this).GetMarkPriceKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IMarkPriceKlineRestClient)this).GetMarkPriceKlinesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -142,10 +142,10 @@ async Task>> IMarkPriceKlineRestC #region Futures Symbol client - EndpointOptions IFuturesSymbolRestClient.GetFuturesSymbolsOptions { get; } = new EndpointOptions(false); - async Task>> IFuturesSymbolRestClient.GetFuturesSymbolsAsync(GetFuturesSymbolsRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + EndpointOptions IFuturesSymbolRestClient.GetFuturesSymbolsOptions { get; } = new EndpointOptions(false); + async Task>> IFuturesSymbolRestClient.GetFuturesSymbolsAsync(GetSymbolsRequest request, CancellationToken ct) { - var validationError = ((IFuturesSymbolRestClient)this).GetFuturesSymbolsOptions.ValidateRequest(Exchange, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IFuturesSymbolRestClient)this).GetFuturesSymbolsOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -172,9 +172,9 @@ async Task>> IFuturesSymbolRe #region Ticker client EndpointOptions IFuturesTickerRestClient.GetFuturesTickerOptions { get; } = new EndpointOptions(false); - async Task> IFuturesTickerRestClient.GetFuturesTickerAsync(GetTickerRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IFuturesTickerRestClient.GetFuturesTickerAsync(GetTickerRequest request, CancellationToken ct) { - var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -197,9 +197,9 @@ async Task> IFuturesTickerRestClient.GetF } EndpointOptions IFuturesTickerRestClient.GetFuturesTickersOptions { get; } = new EndpointOptions(false); - async Task>> IFuturesTickerRestClient.GetFuturesTickersAsync(GetTickersRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IFuturesTickerRestClient.GetFuturesTickersAsync(GetTickersRequest request, CancellationToken ct) { - var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickerOptions.ValidateRequest(Exchange, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickersOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -233,9 +233,9 @@ async Task>> IFuturesTickerRe #region Recent Trade client GetRecentTradesOptions IRecentTradeRestClient.GetRecentTradesOptions { get; } = new GetRecentTradesOptions(1000, false); - async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, CancellationToken ct) { - var validationError = ((IRecentTradeRestClient)this).GetRecentTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IRecentTradeRestClient)this).GetRecentTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -271,9 +271,9 @@ async Task>> IRecentTradeRestClient.G SharedQuantityType.BaseAsset, SharedQuantityType.BaseAsset)); - async Task> IFuturesOrderRestClient.PlaceFuturesOrderAsync(PlaceFuturesOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IFuturesOrderRestClient.PlaceFuturesOrderAsync(PlaceFuturesOrderRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).PlaceFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).PlaceFuturesOrderOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -296,9 +296,9 @@ async Task> IFuturesOrderRestClient.PlaceFuturesOrde } EndpointOptions IFuturesOrderRestClient.GetFuturesOrderOptions { get; } = new EndpointOptions(true); - async Task> IFuturesOrderRestClient.GetFuturesOrderAsync(GetOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IFuturesOrderRestClient.GetFuturesOrderAsync(GetOrderRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -331,9 +331,9 @@ async Task> IFuturesOrderRestClient.GetFut } EndpointOptions IFuturesOrderRestClient.GetOpenFuturesOrdersOptions { get; } = new EndpointOptions(true); - async Task>> IFuturesOrderRestClient.GetOpenFuturesOrdersAsync(GetOpenOrdersRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IFuturesOrderRestClient.GetOpenFuturesOrdersAsync(GetOpenOrdersRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetOpenFuturesOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol?.ApiType ?? request.ApiType!.Value, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetOpenFuturesOrdersOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.ApiType!.Value, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -364,9 +364,9 @@ async Task>> IFuturesOrderRest } PaginatedEndpointOptions IFuturesOrderRestClient.GetClosedFuturesOrdersOptions { get; } = new PaginatedEndpointOptions(SharedPaginationType.Descending, true); - async Task>> IFuturesOrderRestClient.GetClosedFuturesOrdersAsync(GetClosedOrdersRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IFuturesOrderRestClient.GetClosedFuturesOrdersAsync(GetClosedOrdersRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetClosedFuturesOrdersOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetClosedFuturesOrdersOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -411,9 +411,9 @@ async Task>> IFuturesOrderRest } EndpointOptions IFuturesOrderRestClient.GetFuturesOrderTradesOptions { get; } = new EndpointOptions(true); - async Task>> IFuturesOrderRestClient.GetFuturesOrderTradesAsync(GetOrderTradesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IFuturesOrderRestClient.GetFuturesOrderTradesAsync(GetOrderTradesRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -441,9 +441,9 @@ async Task>> IFuturesOrderRestCli } PaginatedEndpointOptions IFuturesOrderRestClient.GetFuturesUserTradesOptions { get; } = new PaginatedEndpointOptions(SharedPaginationType.Descending, true); - async Task>> IFuturesOrderRestClient.GetFuturesUserTradesAsync(GetUserTradesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IFuturesOrderRestClient.GetFuturesUserTradesAsync(GetUserTradesRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetFuturesUserTradesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetFuturesUserTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -485,9 +485,9 @@ async Task>> IFuturesOrderRestCli } EndpointOptions IFuturesOrderRestClient.CancelFuturesOrderOptions { get; } = new EndpointOptions(true); - async Task> IFuturesOrderRestClient.CancelFuturesOrderAsync(CancelOrderRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IFuturesOrderRestClient.CancelFuturesOrderAsync(CancelOrderRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).CancelFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).CancelFuturesOrderOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -502,9 +502,9 @@ async Task> IFuturesOrderRestClient.CancelFuturesOrd } EndpointOptions IFuturesOrderRestClient.GetPositionsOptions { get; } = new EndpointOptions(true); - async Task>> IFuturesOrderRestClient.GetPositionsAsync(GetPositionsRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IFuturesOrderRestClient.GetPositionsAsync(GetPositionsRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetPositionsOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol?.ApiType ?? request.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetPositionsOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -534,9 +534,9 @@ async Task>> IFuturesOrderRestClie new ParameterDescription(nameof(ClosePositionRequest.Quantity), typeof(decimal), "Quantity of the position is required", 0.1m) } }; - async Task> IFuturesOrderRestClient.ClosePositionAsync(ClosePositionRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IFuturesOrderRestClient.ClosePositionAsync(ClosePositionRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).ClosePositionOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).ClosePositionOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -598,9 +598,9 @@ private SharedOrderType ParseOrderType(FuturesOrderType type) #region Leverage client EndpointOptions ILeverageRestClient.GetLeverageOptions { get; } = new EndpointOptions(true); - async Task> ILeverageRestClient.GetLeverageAsync(GetLeverageRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> ILeverageRestClient.GetLeverageAsync(GetLeverageRequest request, CancellationToken ct) { - var validationError = ((ILeverageRestClient)this).GetLeverageOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ILeverageRestClient)this).GetLeverageOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -618,9 +618,9 @@ async Task> ILeverageRestClient.GetLeverageAsy } SetLeverageOptions ILeverageRestClient.SetLeverageOptions { get; } = new SetLeverageOptions(false); - async Task> ILeverageRestClient.SetLeverageAsync(SetLeverageRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> ILeverageRestClient.SetLeverageAsync(SetLeverageRequest request, CancellationToken ct) { - var validationError = ((ILeverageRestClient)this).SetLeverageOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ILeverageRestClient)this).SetLeverageOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -634,9 +634,9 @@ async Task> ILeverageRestClient.SetLeverageAsy #region Order Book client GetOrderBookOptions IOrderBookRestClient.GetOrderBookOptions { get; } = new GetOrderBookOptions(new[] { 5, 10, 20, 50, 100, 500, 1000 }, false); - async Task> IOrderBookRestClient.GetOrderBookAsync(GetOrderBookRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IOrderBookRestClient.GetOrderBookAsync(GetOrderBookRequest request, CancellationToken ct) { - var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -655,9 +655,9 @@ async Task> IOrderBookRestClient.GetOrderBook #region Trade History client GetTradeHistoryOptions ITradeHistoryRestClient.GetTradeHistoryOptions { get; } = new GetTradeHistoryOptions(SharedPaginationType.Ascending, false); - async Task>> ITradeHistoryRestClient.GetTradeHistoryAsync(GetTradeHistoryRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> ITradeHistoryRestClient.GetTradeHistoryAsync(GetTradeHistoryRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((ITradeHistoryRestClient)this).GetTradeHistoryOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ITradeHistoryRestClient)this).GetTradeHistoryOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -692,13 +692,13 @@ async Task>> ITradeHistoryRestClient. MaxRequestDataPoints = 1000 }; - async Task>> IIndexPriceKlineRestClient.GetIndexPriceKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IIndexPriceKlineRestClient.GetIndexPriceKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, CancellationToken ct) { var interval = (Enums.KlineInterval)request.Interval; if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IIndexPriceKlineRestClient)this).GetIndexPriceKlinesOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IIndexPriceKlineRestClient)this).GetIndexPriceKlinesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -747,9 +747,9 @@ async Task>> IIndexPriceKlineRest #region Open Interest client EndpointOptions IOpenInterestRestClient.GetOpenInterestOptions { get; } = new EndpointOptions(true); - async Task> IOpenInterestRestClient.GetOpenInterestAsync(GetOpenInterestRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IOpenInterestRestClient.GetOpenInterestAsync(GetOpenInterestRequest request, CancellationToken ct) { - var validationError = ((IOpenInterestRestClient)this).GetOpenInterestOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IOpenInterestRestClient)this).GetOpenInterestOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -765,9 +765,9 @@ async Task> IOpenInterestRestClient.GetOpe #region Funding Rate client GetFundingRateHistoryOptions IFundingRateRestClient.GetFundingRateHistoryOptions { get; } = new GetFundingRateHistoryOptions(SharedPaginationType.Ascending, false); - async Task>> IFundingRateRestClient.GetFundingRateHistoryAsync(GetFundingRateHistoryRequest request, INextPageToken? pageToken, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IFundingRateRestClient.GetFundingRateHistoryAsync(GetFundingRateHistoryRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((IFundingRateRestClient)this).GetFundingRateHistoryOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFundingRateRestClient)this).GetFundingRateHistoryOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -797,9 +797,9 @@ async Task>> IFundingRateRestCl #region Balance Client EndpointOptions IBalanceRestClient.GetBalancesOptions { get; } = new EndpointOptions(true); - async Task>> IBalanceRestClient.GetBalancesAsync(GetBalancesRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task>> IBalanceRestClient.GetBalancesAsync(GetBalancesRequest request, CancellationToken ct) { - var validationError = ((IBalanceRestClient)this).GetBalancesOptions.ValidateRequest(Exchange, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IBalanceRestClient)this).GetBalancesOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -815,9 +815,9 @@ async Task>> IBalanceRestClient.Get #region Position Mode client GetPositionModeOptions IPositionModeRestClient.GetPositionModeOptions { get; } = new GetPositionModeOptions(false); - async Task> IPositionModeRestClient.GetPositionModeAsync(GetPositionModeRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IPositionModeRestClient.GetPositionModeAsync(GetPositionModeRequest request, CancellationToken ct) { - var validationError = ((IPositionModeRestClient)this).GetPositionModeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol?.ApiType ?? request.ApiType!.Value, SupportedApiTypes); + var validationError = ((IPositionModeRestClient)this).GetPositionModeOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.ApiType!.Value, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -829,9 +829,9 @@ async Task> IPositionModeRestClient. } SetPositionModeOptions IPositionModeRestClient.SetPositionModeOptions { get; } = new SetPositionModeOptions(true, true, false); - async Task> IPositionModeRestClient.SetPositionModeAsync(SetPositionModeRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IPositionModeRestClient.SetPositionModeAsync(SetPositionModeRequest request, CancellationToken ct) { - var validationError = ((IPositionModeRestClient)this).SetPositionModeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol?.ApiType ?? request.ApiType!.Value, SupportedApiTypes); + var validationError = ((IPositionModeRestClient)this).SetPositionModeOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.ApiType!.Value, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -846,9 +846,9 @@ async Task> IPositionModeRestClient. #region Listen Key client EndpointOptions IListenKeyRestClient.StartOptions { get; } = new EndpointOptions(true); - async Task> IListenKeyRestClient.StartListenKeyAsync(StartListenKeyRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IListenKeyRestClient.StartListenKeyAsync(StartListenKeyRequest request, CancellationToken ct) { - var validationError = ((IListenKeyRestClient)this).StartOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IListenKeyRestClient)this).StartOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -860,9 +860,9 @@ async Task> IListenKeyRestClient.StartListenKeyAsync(S return result.AsExchangeResult(Exchange, result.Data); } EndpointOptions IListenKeyRestClient.KeepAliveOptions { get; } = new EndpointOptions(true); - async Task> IListenKeyRestClient.KeepAliveListenKeyAsync(KeepAliveListenKeyRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IListenKeyRestClient.KeepAliveListenKeyAsync(KeepAliveListenKeyRequest request, CancellationToken ct) { - var validationError = ((IListenKeyRestClient)this).KeepAliveOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IListenKeyRestClient)this).KeepAliveOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -875,9 +875,9 @@ async Task> IListenKeyRestClient.KeepAliveListenKeyAsy } EndpointOptions IListenKeyRestClient.StopOptions { get; } = new EndpointOptions(true); - async Task> IListenKeyRestClient.StopListenKeyAsync(StopListenKeyRequest request, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IListenKeyRestClient.StopListenKeyAsync(StopListenKeyRequest request, CancellationToken ct) { - var validationError = ((IListenKeyRestClient)this).StopOptions.ValidateRequest(Exchange, request, exchangeParameters, request.ApiType, SupportedApiTypes); + var validationError = ((IListenKeyRestClient)this).StopOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs index bdd15109f..37db8d977 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs @@ -24,9 +24,9 @@ internal partial class BinanceSocketClientUsdFuturesApi : IBinanceSocketClientUs #region Ticker client SubscriptionOptions ITickerSocketClient.SubscribeTickerOptions { get; } = new SubscriptionOptions(false); - async Task> ITickerSocketClient.SubscribeToTickerUpdatesAsync(SubscribeTickerRequest request, Action> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> ITickerSocketClient.SubscribeToTickerUpdatesAsync(SubscribeTickerRequest request, Action> handler, CancellationToken ct) { - var validationError = ((ITickerSocketClient)this).SubscribeTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ITickerSocketClient)this).SubscribeTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -40,18 +40,18 @@ async Task> ITickerSocketClient.SubscribeToTi #region Tickers client - SubscriptionOptions ITickersSocketClient.SubscribeAllTickersOptions { get; } = new SubscriptionOptions("SubscribeTickersRequest", false); - async Task> ITickersSocketClient.SubscribeToAllTickersUpdatesAsync(Action>> handler, ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + SubscriptionOptions ITickersSocketClient.SubscribeAllTickersOptions { get; } = new SubscriptionOptions(false); + async Task> ITickersSocketClient.SubscribeToAllTickersUpdatesAsync(SubscribeAllTickersRequest request, Action>> handler, CancellationToken ct) { - var validationError = ((ITickersSocketClient)this).SubscribeAllTickersOptions.ValidateRequest(Exchange, exchangeParameters, apiType, SupportedApiTypes); + var validationError = ((ITickersSocketClient)this).SubscribeAllTickersOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); var result = await SubscribeToAllTickerUpdatesAsync(update => { var data = update.Data; - if (apiType != null) - data = data.Where(x => apiType == ApiType.PerpetualLinear ? !x.Symbol.Contains("_") : x.Symbol.Contains("_")); + if (request.ApiType != null) + data = data.Where(x => request.ApiType == ApiType.PerpetualLinear ? !x.Symbol.Contains("_") : x.Symbol.Contains("_")); if (!data.Any()) return; @@ -67,9 +67,9 @@ async Task> ITickersSocketClient.SubscribeToA #region Trade client SubscriptionOptions ITradeSocketClient.SubscribeTradeOptions { get; } = new SubscriptionOptions(false); - async Task> ITradeSocketClient.SubscribeToTradeUpdatesAsync(SubscribeTradeRequest request, Action>> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> ITradeSocketClient.SubscribeToTradeUpdatesAsync(SubscribeTradeRequest request, Action>> handler, CancellationToken ct) { - var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -84,9 +84,9 @@ async Task> ITradeSocketClient.SubscribeToTra #region Book Ticker client SubscriptionOptions IBookTickerSocketClient.SubscribeBookTickerOptions { get; } = new SubscriptionOptions(false); - async Task> IBookTickerSocketClient.SubscribeToBookTickerUpdatesAsync(SubscribeBookTickerRequest request, Action> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IBookTickerSocketClient.SubscribeToBookTickerUpdatesAsync(SubscribeBookTickerRequest request, Action> handler, CancellationToken ct) { - var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -106,9 +106,9 @@ async Task> IBookTickerSocketClient.Subscribe new ParameterDescription(nameof(SubscribeBalancesRequest.ListenKey), typeof(string), "The listenkey for starting the user stream", "123123123") } }; - async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(SubscribeBalancesRequest request, Action>> handler, ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(SubscribeBalancesRequest request, Action>> handler, CancellationToken ct) { - var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, request, exchangeParameters, apiType, SupportedApiTypes); + var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -130,9 +130,9 @@ async Task> IBalanceSocketClient.SubscribeToB new ParameterDescription(nameof(SubscribeFuturesOrderRequest.ListenKey), typeof(string), "The listenkey for starting the user stream", "123123123") } }; - async Task> IFuturesOrderSocketClient.SubscribeToFuturesOrderUpdatesAsync(SubscribeFuturesOrderRequest request, Action>> handler, ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IFuturesOrderSocketClient.SubscribeToFuturesOrderUpdatesAsync(SubscribeFuturesOrderRequest request, Action>> handler, CancellationToken ct) { - var validationError = ((IFuturesOrderSocketClient)this).SubscribeFuturesOrderOptions.ValidateRequest(Exchange, request, exchangeParameters, apiType, SupportedApiTypes); + var validationError = ((IFuturesOrderSocketClient)this).SubscribeFuturesOrderOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -171,13 +171,13 @@ async Task> IFuturesOrderSocketClient.Subscri #region Kline client SubscribeKlineOptions IKlineSocketClient.SubscribeKlineOptions { get; } = new SubscribeKlineOptions(false); - async Task> IKlineSocketClient.SubscribeToKlineUpdatesAsync(SubscribeKlineRequest request, Action> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IKlineSocketClient.SubscribeToKlineUpdatesAsync(SubscribeKlineRequest request, Action> handler, CancellationToken ct) { var interval = (Enums.KlineInterval)request.Interval; if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeResult(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -190,9 +190,9 @@ async Task> IKlineSocketClient.SubscribeToKli #region Order Book client SubscribeOrderBookOptions IOrderBookSocketClient.SubscribeOrderBookOptions { get; } = new SubscribeOrderBookOptions(false, new[] { 5, 10, 20 }); - async Task> IOrderBookSocketClient.SubscribeToOrderBookUpdatesAsync(SubscribeOrderBookRequest request, Action> handler, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IOrderBookSocketClient.SubscribeToOrderBookUpdatesAsync(SubscribeOrderBookRequest request, Action> handler, CancellationToken ct) { - var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, exchangeParameters, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -211,9 +211,9 @@ async Task> IOrderBookSocketClient.SubscribeT new ParameterDescription(nameof(SubscribePositionRequest.ListenKey), typeof(string), "The listenkey for starting the user stream", "123123123") } }; - async Task> IPositionSocketClient.SubscribeToPositionUpdatesAsync(SubscribePositionRequest request, Action>> handler, ApiType? apiType, ExchangeParameters? exchangeParameters, CancellationToken ct) + async Task> IPositionSocketClient.SubscribeToPositionUpdatesAsync(SubscribePositionRequest request, Action>> handler, CancellationToken ct) { - var validationError = ((IPositionSocketClient)this).SubscribePositionOptions.ValidateRequest(Exchange, request, exchangeParameters, apiType, SupportedApiTypes); + var validationError = ((IPositionSocketClient)this).SubscribePositionOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); From 546541c6a277d84f5baa39cf63f8f719e47fbfc3 Mon Sep 17 00:00:00 2001 From: JKorf Date: Sun, 15 Sep 2024 21:32:58 +0200 Subject: [PATCH 38/54] wip --- .../Clients/SpotApi/BinanceRestClientSpotApiShared.cs | 5 +---- .../UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs | 4 ++-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index b0329a632..82c9749e4 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -44,9 +44,6 @@ async Task>> IKlineRestClient.GetKlin if (startTime == null || startTime < endTime) { var offset = (int)interval * limit; - if (request.EndTime == null && pageToken is null) - offset = (int)interval * (limit - 1); - startTime = endTime.AddSeconds(-offset); } @@ -71,7 +68,7 @@ async Task>> IKlineRestClient.GetKlin { var minOpenTime = result.Data.Min(x => x.OpenTime); if (request.StartTime == null || minOpenTime > request.StartTime.Value) - nextToken = new DateTimeToken(minOpenTime.AddSeconds(-(int)interval)); + nextToken = new DateTimeToken(minOpenTime.AddSeconds(-(int)(interval - 1))); } return result.AsExchangeResult>(Exchange, result.Data.Reverse().Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)).ToArray(), nextToken); diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs index 47fb7e23a..d87552486 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -817,7 +817,7 @@ async Task>> IBalanceRestClient.Get GetPositionModeOptions IPositionModeRestClient.GetPositionModeOptions { get; } = new GetPositionModeOptions(false); async Task> IPositionModeRestClient.GetPositionModeAsync(GetPositionModeRequest request, CancellationToken ct) { - var validationError = ((IPositionModeRestClient)this).GetPositionModeOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.ApiType!.Value, SupportedApiTypes); + var validationError = ((IPositionModeRestClient)this).GetPositionModeOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -831,7 +831,7 @@ async Task> IPositionModeRestClient. SetPositionModeOptions IPositionModeRestClient.SetPositionModeOptions { get; } = new SetPositionModeOptions(true, true, false); async Task> IPositionModeRestClient.SetPositionModeAsync(SetPositionModeRequest request, CancellationToken ct) { - var validationError = ((IPositionModeRestClient)this).SetPositionModeOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.ApiType!.Value, SupportedApiTypes); + var validationError = ((IPositionModeRestClient)this).SetPositionModeOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.ApiType, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); From 59297efa4b469ac900693d8b92ef60db4d646ca1 Mon Sep 17 00:00:00 2001 From: Jkorf Date: Tue, 17 Sep 2024 16:41:29 +0200 Subject: [PATCH 39/54] wip --- .../CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs | 3 +++ .../Clients/SpotApi/BinanceRestClientSpotApiShared.cs | 5 ++++- .../UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs | 3 +++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs index 0579695d0..31fb4e858 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -210,6 +210,9 @@ async Task>> IRecentTradeRestClient.G SharedQuantityType.Contracts, SharedQuantityType.Contracts)); + SharedFeeDeductionType IFuturesOrderRestClient.FuturesFeeDeductionType => SharedFeeDeductionType.AddToCost; + SharedFeeAssetType IFuturesOrderRestClient.FuturesFeeAssetType => SharedFeeAssetType.QuoteAsset; + async Task> IFuturesOrderRestClient.PlaceFuturesOrderAsync(PlaceFuturesOrderRequest request, CancellationToken ct) { var validationError = ((IFuturesOrderRestClient)this).PlaceFuturesOrderOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index 82c9749e4..628a464b0 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -247,6 +247,9 @@ async Task>> IBalanceRestClient.Get SharedQuantityType.BaseAndQuoteAsset, SharedQuantityType.BaseAndQuoteAsset)); + SharedFeeDeductionType ISpotOrderRestClient.SpotFeeDeductionType => SharedFeeDeductionType.DeductFromTrade; + SharedFeeAssetType ISpotOrderRestClient.SpotFeeAssetType => SharedFeeAssetType.OutputAsset; + async Task> ISpotOrderRestClient.PlaceSpotOrderAsync(PlaceSpotOrderRequest request, CancellationToken ct) { var validationError = ((ISpotOrderRestClient)this).PlaceSpotOrderOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); @@ -584,7 +587,7 @@ async Task>> IDepositRestCli return depositAddresses.AsExchangeResult>(Exchange, new[] { new SharedDepositAddress(depositAddresses.Data.Asset, depositAddresses.Data.Address) { - Tag = depositAddresses.Data.Tag + TagOrMemo = depositAddresses.Data.Tag } }); } diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs index d87552486..b936ab142 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -271,6 +271,9 @@ async Task>> IRecentTradeRestClient.G SharedQuantityType.BaseAsset, SharedQuantityType.BaseAsset)); + SharedFeeDeductionType IFuturesOrderRestClient.FuturesFeeDeductionType => SharedFeeDeductionType.AddToCost; + SharedFeeAssetType IFuturesOrderRestClient.FuturesFeeAssetType => SharedFeeAssetType.QuoteAsset; + async Task> IFuturesOrderRestClient.PlaceFuturesOrderAsync(PlaceFuturesOrderRequest request, CancellationToken ct) { var validationError = ((IFuturesOrderRestClient)this).PlaceFuturesOrderOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); From b14f929283a6227d979586b8d7e3d4f8aac3b2ee Mon Sep 17 00:00:00 2001 From: Jkorf Date: Wed, 18 Sep 2024 16:12:31 +0200 Subject: [PATCH 40/54] wip --- .../CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs | 3 +++ .../BinanceSocketClientCoinFuturesApiShared.cs | 3 +++ .../Clients/SpotApi/BinanceRestClientSpotApiShared.cs | 6 +++++- .../Clients/SpotApi/BinanceSocketClientSpotApiShared.cs | 3 +++ .../UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs | 4 +++- .../UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs | 3 +++ 6 files changed, 20 insertions(+), 2 deletions(-) diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs index 31fb4e858..e93888c83 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -19,6 +19,9 @@ internal partial class BinanceRestClientCoinFuturesApi : IBinanceRestClientCoinF public ApiType[] SupportedApiTypes => new[] { ApiType.DeliveryInverse, ApiType.PerpetualInverse }; + public void SetDefaultExchangeParameter(string key, object value) => ExchangeParameters.SetStaticParameter(Exchange, key, value); + public void ResetDefaultExchangeParameters() => ExchangeParameters.ResetStaticParameters(); + #region Klines client GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(SharedPaginationType.Descending, false) diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs index da67980e5..8f5769b21 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs @@ -21,6 +21,9 @@ internal partial class BinanceSocketClientCoinFuturesApi : IBinanceSocketClientC public string Exchange => BinanceExchange.ExchangeName; public ApiType[] SupportedApiTypes => new[] { ApiType.DeliveryInverse, ApiType.PerpetualInverse }; + public void SetDefaultExchangeParameter(string key, object value) => ExchangeParameters.SetStaticParameter(Exchange, key, value); + public void ResetDefaultExchangeParameters() => ExchangeParameters.ResetStaticParameters(); + #region Ticker client SubscriptionOptions ITickerSocketClient.SubscribeTickerOptions { get; } = new SubscriptionOptions(false); diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index 628a464b0..b89c02823 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -8,6 +8,7 @@ using CryptoExchange.Net.SharedApis.Models.FilterOptions; using CryptoExchange.Net.SharedApis.Models; using CryptoExchange.Net.SharedApis.Interfaces.Rest.Spot; +using CryptoExchange.Net.SharedApis; namespace Binance.Net.Clients.SpotApi { @@ -16,6 +17,9 @@ internal partial class BinanceRestClientSpotApi : IBinanceRestClientSpotApiShare public string Exchange => BinanceExchange.ExchangeName; public ApiType[] SupportedApiTypes => new[] { ApiType.Spot }; + public void SetDefaultExchangeParameter(string key, object value) => ExchangeParameters.SetStaticParameter(Exchange, key, value); + public void ResetDefaultExchangeParameters() => ExchangeParameters.ResetStaticParameters(); + #region Klines Client GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(SharedPaginationType.Descending, false) @@ -247,7 +251,7 @@ async Task>> IBalanceRestClient.Get SharedQuantityType.BaseAndQuoteAsset, SharedQuantityType.BaseAndQuoteAsset)); - SharedFeeDeductionType ISpotOrderRestClient.SpotFeeDeductionType => SharedFeeDeductionType.DeductFromTrade; + SharedFeeDeductionType ISpotOrderRestClient.SpotFeeDeductionType => SharedFeeDeductionType.DeductFromOutput; SharedFeeAssetType ISpotOrderRestClient.SpotFeeAssetType => SharedFeeAssetType.OutputAsset; async Task> ISpotOrderRestClient.PlaceSpotOrderAsync(PlaceSpotOrderRequest request, CancellationToken ct) diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs index 9bf2aa276..4d9949aad 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs @@ -19,6 +19,9 @@ internal partial class BinanceSocketClientSpotApi : IBinanceSocketClientSpotApiS public string Exchange => BinanceExchange.ExchangeName; public ApiType[] SupportedApiTypes => new[] { ApiType.Spot }; + public void SetDefaultExchangeParameter(string key, object value) => ExchangeParameters.SetStaticParameter(Exchange, key, value); + public void ResetDefaultExchangeParameters() => ExchangeParameters.ResetStaticParameters(); + #region Tickers client SubscriptionOptions ITickersSocketClient.SubscribeAllTickersOptions { get; } = new SubscriptionOptions(false); async Task> ITickersSocketClient.SubscribeToAllTickersUpdatesAsync(SubscribeAllTickersRequest request, Action>> handler, CancellationToken ct) diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs index b936ab142..8c96897ed 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -20,7 +20,9 @@ internal partial class BinanceRestClientUsdFuturesApi : IBinanceRestClientUsdFut { public string Exchange => BinanceExchange.ExchangeName; - public ApiType[] SupportedApiTypes => new[] { ApiType.DeliveryLinear, ApiType.PerpetualLinear }; + public ApiType[] SupportedApiTypes => new[] { ApiType.DeliveryLinear, ApiType.PerpetualLinear }; + public void SetDefaultExchangeParameter(string key, object value) => ExchangeParameters.SetStaticParameter(Exchange, key, value); + public void ResetDefaultExchangeParameters() => ExchangeParameters.ResetStaticParameters(); #region Klines client diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs index 37db8d977..d65521035 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs @@ -21,6 +21,9 @@ internal partial class BinanceSocketClientUsdFuturesApi : IBinanceSocketClientUs public string Exchange => BinanceExchange.ExchangeName; public ApiType[] SupportedApiTypes => new[] { ApiType.DeliveryLinear, ApiType.PerpetualLinear }; + public void SetDefaultExchangeParameter(string key, object value) => ExchangeParameters.SetStaticParameter(Exchange, key, value); + public void ResetDefaultExchangeParameters() => ExchangeParameters.ResetStaticParameters(); + #region Ticker client SubscriptionOptions ITickerSocketClient.SubscribeTickerOptions { get; } = new SubscriptionOptions(false); From d84b62f9d529fcde8ef98e4bf491d14fd721d825 Mon Sep 17 00:00:00 2001 From: Jkorf Date: Thu, 19 Sep 2024 16:34:28 +0200 Subject: [PATCH 41/54] wip --- .../CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs | 4 ++-- .../UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs index e93888c83..4def12d54 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -828,7 +828,7 @@ async Task> IPositionModeRestClient. if (!result) return result.AsExchangeResult(Exchange, default); - return result.AsExchangeResult(Exchange, new SharedPositionModeResult(result.Data.IsHedgeMode ? SharedPositionMode.LongShort : SharedPositionMode.OneWay)); + return result.AsExchangeResult(Exchange, new SharedPositionModeResult(result.Data.IsHedgeMode ? SharedPositionMode.HedgeMode : SharedPositionMode.OneWay)); } SetPositionModeOptions IPositionModeRestClient.SetPositionModeOptions { get; } = new SetPositionModeOptions(true, true, false); @@ -838,7 +838,7 @@ async Task> IPositionModeRestClient. if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var result = await Account.ModifyPositionModeAsync(request.Mode == SharedPositionMode.LongShort, ct: ct).ConfigureAwait(false); + var result = await Account.ModifyPositionModeAsync(request.Mode == SharedPositionMode.HedgeMode, ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs index 8c96897ed..2c337857b 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -830,7 +830,7 @@ async Task> IPositionModeRestClient. if (!result) return result.AsExchangeResult(Exchange, default); - return result.AsExchangeResult(Exchange, new SharedPositionModeResult(result.Data.IsHedgeMode ? SharedPositionMode.LongShort : SharedPositionMode.OneWay)); + return result.AsExchangeResult(Exchange, new SharedPositionModeResult(result.Data.IsHedgeMode ? SharedPositionMode.HedgeMode : SharedPositionMode.OneWay)); } SetPositionModeOptions IPositionModeRestClient.SetPositionModeOptions { get; } = new SetPositionModeOptions(true, true, false); @@ -840,7 +840,7 @@ async Task> IPositionModeRestClient. if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var result = await Account.ModifyPositionModeAsync(request.Mode == SharedPositionMode.LongShort, ct: ct).ConfigureAwait(false); + var result = await Account.ModifyPositionModeAsync(request.Mode == SharedPositionMode.HedgeMode, ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, default); From 09c6f0ed8e2dc4f49aa2d624384bb1ea4578881b Mon Sep 17 00:00:00 2001 From: Jkorf Date: Fri, 20 Sep 2024 16:34:33 +0200 Subject: [PATCH 42/54] wip --- Binance.Net/Binance.Net.xml | 14 +- .../BinanceRestClientCoinFuturesApi.cs | 2 +- .../BinanceRestClientCoinFuturesApiShared.cs | 134 ++++++++--------- .../BinanceSocketClientCoinFuturesApi.cs | 2 +- ...BinanceSocketClientCoinFuturesApiShared.cs | 4 +- .../GeneralApi/BinanceRestClientGeneralApi.cs | 2 +- .../SpotApi/BinanceRestClientSpotApi.cs | 2 +- .../SpotApi/BinanceRestClientSpotApiShared.cs | 142 +++++++++--------- .../SpotApi/BinanceSocketClientSpotApi.cs | 2 +- .../BinanceSocketClientSpotApiShared.cs | 4 +- .../BinanceRestClientUsdFuturesApi.cs | 2 +- .../BinanceRestClientUsdFuturesApiShared.cs | 126 ++++++++-------- .../BinanceSocketClientUsdFuturesApi.cs | 2 +- .../BinanceSocketClientUsdFuturesApiShared.cs | 4 +- 14 files changed, 220 insertions(+), 222 deletions(-) diff --git a/Binance.Net/Binance.Net.xml b/Binance.Net/Binance.Net.xml index 3d03795e9..ae0d06172 100644 --- a/Binance.Net/Binance.Net.xml +++ b/Binance.Net/Binance.Net.xml @@ -265,7 +265,7 @@ - + @@ -466,7 +466,7 @@ - + @@ -625,7 +625,7 @@ - + @@ -1130,7 +1130,7 @@ - + @@ -1670,7 +1670,7 @@ - + @@ -1905,7 +1905,7 @@ Event triggered when an order is canceled via this client. Note that this does not trigger when using CancelAllOrdersAsync. Only available for Spot orders - + @@ -2218,7 +2218,7 @@ - + diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs index d54fe6be5..3119f3f32 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs @@ -75,7 +75,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(); /// - public override string FormatSymbol(string baseAsset, string quoteAsset, ApiType apiType, DateTime? deliverTime = null) + public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode apiType, DateTime? deliverTime = null) { return baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + (deliverTime == null ? "_PERP" : "_" + deliverTime.Value.ToString("yyMMdd")); } diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs index 4def12d54..0eb92234f 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -17,7 +17,7 @@ internal partial class BinanceRestClientCoinFuturesApi : IBinanceRestClientCoinF { public string Exchange => BinanceExchange.ExchangeName; - public ApiType[] SupportedApiTypes => new[] { ApiType.DeliveryInverse, ApiType.PerpetualInverse }; + public TradingMode[] SupportedApiTypes => new[] { TradingMode.DeliveryInverse, TradingMode.PerpetualInverse }; public void SetDefaultExchangeParameter(string key, object value) => ExchangeParameters.SetStaticParameter(Exchange, key, value); public void ResetDefaultExchangeParameters() => ExchangeParameters.ResetStaticParameters(); @@ -65,7 +65,7 @@ async Task>> IKlineRestClient.GetKlin ct: ct ).ConfigureAwait(false); if (!result) - return result.AsExchangeResult>(Exchange, default); + return result.AsExchangeResult>(Exchange, null, default); // Get next token DateTimeToken? nextToken = null; @@ -76,7 +76,7 @@ async Task>> IKlineRestClient.GetKlin nextToken = new DateTimeToken(minOpenTime.AddSeconds(-(int)interval)); } - return result.AsExchangeResult>(Exchange, result.Data.Reverse().Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)).ToArray(), nextToken); + return result.AsExchangeResult>(Exchange, request.Symbol.ApiType, result.Data.Reverse().Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)).ToArray(), nextToken); } #endregion @@ -92,12 +92,12 @@ async Task>> IFuturesSymbolRe var result = await ExchangeData.GetExchangeInfoAsync(ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult>(Exchange, default); + return result.AsExchangeResult>(Exchange, null, default); var data = result.Data.Symbols.Where(x => x.ContractType != null); if (request.ApiType != null) - data = data.Where(x => request.ApiType == ApiType.PerpetualInverse ? x.ContractType == ContractType.Perpetual : (x.ContractType != ContractType.Perpetual && x.ContractType != ContractType.PerpetualDelivering)); - return result.AsExchangeResult>(Exchange, data.Select(s => new SharedFuturesSymbol(s.ContractType == ContractType.Perpetual ? SharedSymbolType.PerpetualInverse : SharedSymbolType.DeliveryInverse, s.BaseAsset, s.QuoteAsset, s.Name, s.Status == SymbolStatus.Trading) + data = data.Where(x => request.ApiType == TradingMode.PerpetualInverse ? x.ContractType == ContractType.Perpetual : (x.ContractType != ContractType.Perpetual && x.ContractType != ContractType.PerpetualDelivering)); + return result.AsExchangeResult>(Exchange, request.ApiType == null ? SupportedApiTypes : new[] { request.ApiType.Value }, data.Select(s => new SharedFuturesSymbol(s.ContractType == ContractType.Perpetual ? SharedSymbolType.PerpetualInverse : SharedSymbolType.DeliveryInverse, s.BaseAsset, s.QuoteAsset, s.Name, s.Status == SymbolStatus.Trading) { MinTradeQuantity = s.LotSizeFilter?.MinQuantity, MaxTradeQuantity = s.LotSizeFilter?.MaxQuantity, @@ -123,9 +123,9 @@ async Task> IFuturesTickerRestClient.GetF var resultMarkPrice = ExchangeData.GetMarkPricesAsync(request.Symbol.GetSymbol(FormatSymbol), ct: ct); await Task.WhenAll(resultTicker, resultMarkPrice).ConfigureAwait(false); if (!resultTicker.Result) - return resultTicker.Result.AsExchangeResult(Exchange, default); + return resultTicker.Result.AsExchangeResult(Exchange, null, default); if (!resultMarkPrice.Result) - return resultMarkPrice.Result.AsExchangeResult(Exchange, default); + return resultMarkPrice.Result.AsExchangeResult(Exchange, null, default); var ticker = resultTicker.Result.Data.SingleOrDefault(); var mark = resultMarkPrice.Result.Data.SingleOrDefault(); @@ -133,7 +133,7 @@ async Task> IFuturesTickerRestClient.GetF if (ticker == null || mark == null) return resultTicker.Result.AsExchangeError(Exchange, new ServerError("Not found")); - return resultTicker.Result.AsExchangeResult(Exchange, new SharedFuturesTicker(ticker.Symbol, ticker.LastPrice, ticker.HighPrice, ticker.LowPrice, ticker.Volume, ticker.PriceChangePercent) + return resultTicker.Result.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedFuturesTicker(ticker.Symbol, ticker.LastPrice, ticker.HighPrice, ticker.LowPrice, ticker.Volume, ticker.PriceChangePercent) { IndexPrice = mark.IndexPrice, MarkPrice = mark.MarkPrice, @@ -153,11 +153,11 @@ async Task>> IFuturesTickerRe var resultMarkPrices = ExchangeData.GetMarkPricesAsync(ct: ct); await Task.WhenAll(resultTickers, resultMarkPrices).ConfigureAwait(false); if (!resultTickers.Result) - return resultTickers.Result.AsExchangeResult>(Exchange, default); + return resultTickers.Result.AsExchangeResult>(Exchange, null, default); if (!resultMarkPrices.Result) - return resultMarkPrices.Result.AsExchangeResult>(Exchange, default); + return resultMarkPrices.Result.AsExchangeResult>(Exchange, null, default); - return resultTickers.Result.AsExchangeResult>(Exchange, resultTickers.Result.Data.Select(x => + return resultTickers.Result.AsExchangeResult>(Exchange, SupportedApiTypes, resultTickers.Result.Data.Select(x => { var markPrice = resultMarkPrices.Result.Data.Single(p => p.Symbol == x.Symbol); return new SharedFuturesTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume, x.PriceChangePercent) @@ -186,9 +186,9 @@ async Task>> IRecentTradeRestClient.G limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult>(Exchange, default); + return result.AsExchangeResult>(Exchange, null, default); - return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedTrade(x.BaseQuantity, x.Price, x.TradeTime)).ToArray()); + return result.AsExchangeResult>(Exchange, request.Symbol.ApiType, result.Data.Select(x => new SharedTrade(x.BaseQuantity, x.Price, x.TradeTime)).ToArray()); } #endregion @@ -214,7 +214,7 @@ async Task>> IRecentTradeRestClient.G SharedQuantityType.Contracts)); SharedFeeDeductionType IFuturesOrderRestClient.FuturesFeeDeductionType => SharedFeeDeductionType.AddToCost; - SharedFeeAssetType IFuturesOrderRestClient.FuturesFeeAssetType => SharedFeeAssetType.QuoteAsset; + SharedFeeAssetType IFuturesOrderRestClient.FuturesFeeAssetType => SharedFeeAssetType.BaseAsset; async Task> IFuturesOrderRestClient.PlaceFuturesOrderAsync(PlaceFuturesOrderRequest request, CancellationToken ct) { @@ -235,9 +235,9 @@ async Task> IFuturesOrderRestClient.PlaceFuturesOrde ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult(Exchange, default); + return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, new SharedId(result.Data.Id.ToString())); + return result.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedId(result.Data.Id.ToString())); } EndpointOptions IFuturesOrderRestClient.GetFuturesOrderOptions { get; } = new EndpointOptions(true); @@ -252,9 +252,9 @@ async Task> IFuturesOrderRestClient.GetFut var order = await Trading.GetOrderAsync(request.Symbol.GetSymbol(FormatSymbol), orderId, ct: ct).ConfigureAwait(false); if (!order) - return order.AsExchangeResult(Exchange, default); + return order.AsExchangeResult(Exchange, null, default); - return order.AsExchangeResult(Exchange, new SharedFuturesOrder( + return order.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedFuturesOrder( order.Data.Symbol, order.Data.Id.ToString(), ParseOrderType(order.Data.Type), @@ -285,9 +285,9 @@ async Task>> IFuturesOrderRest var symbol = request.Symbol?.GetSymbol(FormatSymbol); var orders = await Trading.GetOpenOrdersAsync(symbol, ct: ct).ConfigureAwait(false); if (!orders) - return orders.AsExchangeResult>(Exchange, default); + return orders.AsExchangeResult>(Exchange, null, default); - return orders.AsExchangeResult>(Exchange, orders.Data.Select(x => new SharedFuturesOrder( + return orders.AsExchangeResult>(Exchange, SupportedApiTypes, orders.Data.Select(x => new SharedFuturesOrder( x.Symbol, x.Id.ToString(), ParseOrderType(x.Type), @@ -322,19 +322,19 @@ async Task>> IFuturesOrderRest // Get data var orders = await Trading.GetOrdersAsync(request.Symbol.GetSymbol(FormatSymbol), - startTime: fromTimestamp ?? request.StartTime, - endTime: request.EndTime, + startTime: request.StartTime, + endTime: fromTimestamp ?? request.EndTime, limit: request.Limit ?? 100, ct: ct).ConfigureAwait(false); if (!orders) - return orders.AsExchangeResult>(Exchange, default); + return orders.AsExchangeResult>(Exchange, null, default); // Get next token DateTimeToken? nextToken = null; if (orders.Data.Count() == (request.Limit ?? 100)) - nextToken = new DateTimeToken(orders.Data.Max(o => o.CreateTime)); + nextToken = new DateTimeToken(orders.Data.Min(o => o.CreateTime).AddMilliseconds(-1)); - return orders.AsExchangeResult>(Exchange, orders.Data.Where(x => x.Status == OrderStatus.Filled || x.Status == OrderStatus.Canceled || x.Status == OrderStatus.Expired).Select(x => new SharedFuturesOrder( + return orders.AsExchangeResult>(Exchange, SupportedApiTypes, orders.Data.Where(x => x.Status == OrderStatus.Filled || x.Status == OrderStatus.Canceled || x.Status == OrderStatus.Expired).Select(x => new SharedFuturesOrder( x.Symbol, x.Id.ToString(), ParseOrderType(x.Type), @@ -367,9 +367,9 @@ async Task>> IFuturesOrderRestCli var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol(FormatSymbol), orderId: orderId, ct: ct).ConfigureAwait(false); if (!orders) - return orders.AsExchangeResult>(Exchange, default); + return orders.AsExchangeResult>(Exchange, null, default); - return orders.AsExchangeResult>(Exchange, orders.Data.Select(x => new SharedUserTrade( + return orders.AsExchangeResult>(Exchange, request.Symbol.ApiType, orders.Data.Select(x => new SharedUserTrade( x.Symbol, x.OrderId.ToString(), x.Id.ToString(), @@ -406,14 +406,14 @@ async Task>> IFuturesOrderRestCli ct: ct ).ConfigureAwait(false); if (!orders) - return orders.AsExchangeResult>(Exchange, default); + return orders.AsExchangeResult>(Exchange, null, default); // Get next token FromIdToken? nextToken = null; if (orders.Data.Count() == (request.Limit ?? 500)) nextToken = new FromIdToken(orders.Data.Max(o => o.Id).ToString()); - return orders.AsExchangeResult>(Exchange, orders.Data.Select(x => new SharedUserTrade( + return orders.AsExchangeResult>(Exchange, request.Symbol.ApiType, orders.Data.Select(x => new SharedUserTrade( x.Symbol, x.OrderId.ToString(), x.Id.ToString(), @@ -441,9 +441,9 @@ async Task> IFuturesOrderRestClient.CancelFuturesOrd var order = await Trading.CancelOrderAsync(request.Symbol.GetSymbol(FormatSymbol), orderId).ConfigureAwait(false); if (!order) - return order.AsExchangeResult(Exchange, default); + return order.AsExchangeResult(Exchange, null, default); - return order.AsExchangeResult(Exchange, new SharedId(order.Data.Id.ToString())); + return order.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedId(order.Data.Id.ToString())); } EndpointOptions IFuturesOrderRestClient.GetPositionsOptions { get; } = new EndpointOptions(true); @@ -456,9 +456,9 @@ async Task>> IFuturesOrderRestClie var symbol = request.Symbol?.GetSymbol(FormatSymbol); var result = await Account.GetPositionInformationAsync(pair: symbol?.Split('_')[0], ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult>(Exchange, default); + return result.AsExchangeResult>(Exchange, null, default); - return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedPosition(x.Symbol, Math.Abs(x.Quantity), x.UpdateTime) + return result.AsExchangeResult>(Exchange, request.Symbol == null ? SupportedApiTypes : new[] { request.Symbol.ApiType }, result.Data.Select(x => new SharedPosition(x.Symbol, Math.Abs(x.Quantity), x.UpdateTime) { UnrealizedPnl = x.UnrealizedPnl, LiquidationPrice = x.LiquidationPrice == 0 ? null : x.LiquidationPrice, @@ -485,7 +485,7 @@ async Task> IFuturesOrderRestClient.ClosePositionAsy var symbol = request.Symbol.GetSymbol(FormatSymbol); var positionMode = await Account.GetPositionModeAsync().ConfigureAwait(false); if (!positionMode) - return positionMode.AsExchangeResult(Exchange, default); + return positionMode.AsExchangeResult(Exchange, null, default); var result = await Trading.PlaceOrderAsync( symbol, @@ -496,9 +496,9 @@ async Task> IFuturesOrderRestClient.ClosePositionAsy reduceOnly: positionMode.Data.IsHedgeMode ? null : true, ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult(Exchange, default); + return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, new SharedId(result.Data.Id.ToString())); + return result.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedId(result.Data.Id.ToString())); } private TimeInForce? GetTimeInForce(SharedOrderType type, SharedTimeInForce? tif) @@ -549,13 +549,13 @@ async Task> ILeverageRestClient.GetLeverageAsy var symbol = request.Symbol.GetSymbol(FormatSymbol); var result = await Account.GetPositionInformationAsync(pair: symbol.Split('_')[0], ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult(Exchange, default); + return result.AsExchangeResult(Exchange, null, default); if (!result.Data.Any()) return result.AsExchangeError(Exchange, new ServerError("Not found")); var data = result.Data.Where(x => x.Symbol == symbol).ToList(); - return result.AsExchangeResult(Exchange, new SharedLeverage(data.First().Leverage) + return result.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedLeverage(data.First().Leverage) { Side = request.Side }); @@ -570,15 +570,15 @@ async Task> ILeverageRestClient.SetLeverageAsy var result = await Account.ChangeInitialLeverageAsync(symbol: request.Symbol.GetSymbol(FormatSymbol), (int)request.Leverage ,ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult(Exchange, default); + return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, new SharedLeverage(result.Data.Leverage)); + return result.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedLeverage(result.Data.Leverage)); } #endregion #region Mark Klines client - GetKlinesOptions IMarkPriceKlineRestClient.GetMarkPriceKlinesOptions { get; } = new GetKlinesOptions(SharedPaginationType.Ascending, false) + GetKlinesOptions IMarkPriceKlineRestClient.GetMarkPriceKlinesOptions { get; } = new GetKlinesOptions(SharedPaginationType.Descending, false) { MaxRequestDataPoints = 1000 }; @@ -619,7 +619,7 @@ async Task>> IMarkPriceKlineRestC ct: ct ).ConfigureAwait(false); if (!result) - return result.AsExchangeResult>(Exchange, default); + return result.AsExchangeResult>(Exchange, null, default); // Get next token DateTimeToken? nextToken = null; @@ -630,7 +630,7 @@ async Task>> IMarkPriceKlineRestC nextToken = new DateTimeToken(minOpenTime.AddSeconds(-(int)(interval - 1))); } - return result.AsExchangeResult>(Exchange, result.Data.Reverse().Select(x => new SharedMarkKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)).ToArray(), nextToken); + return result.AsExchangeResult>(Exchange, request.Symbol.ApiType, result.Data.Reverse().Select(x => new SharedMarkKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)).ToArray(), nextToken); } #endregion @@ -648,9 +648,9 @@ async Task> IOrderBookRestClient.GetOrderBook limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult(Exchange, default); + return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, new SharedOrderBook(result.Data.Asks, result.Data.Bids)); + return result.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedOrderBook(result.Data.Asks, result.Data.Bids)); } #endregion @@ -677,20 +677,20 @@ async Task>> ITradeHistoryRestClient. fromId: fromId, ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult>(Exchange, default); + return result.AsExchangeResult>(Exchange, null, default); FromIdToken? nextToken = null; if (result.Data.Any() && result.Data.Last().TradeTime < request.EndTime) nextToken = new FromIdToken(result.Data.Max(x => x.Id).ToString()); // Return - return result.AsExchangeResult>(Exchange, 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.ApiType, result.Data.Where(x => x.TradeTime < request.EndTime).Select(x => new SharedTrade(x.Quantity, x.Price, x.TradeTime)).ToArray(), nextToken); } #endregion #region Index Klines client - GetKlinesOptions IIndexPriceKlineRestClient.GetIndexPriceKlinesOptions { get; } = new GetKlinesOptions(SharedPaginationType.Ascending, false) + GetKlinesOptions IIndexPriceKlineRestClient.GetIndexPriceKlinesOptions { get; } = new GetKlinesOptions(SharedPaginationType.Descending, false) { MaxRequestDataPoints = 1000 }; @@ -731,7 +731,7 @@ async Task>> IIndexPriceKlineRest ct: ct ).ConfigureAwait(false); if (!result) - return result.AsExchangeResult>(Exchange, default); + return result.AsExchangeResult>(Exchange, null, default); // Get next token DateTimeToken? nextToken = null; @@ -742,7 +742,7 @@ async Task>> IIndexPriceKlineRest nextToken = new DateTimeToken(minOpenTime.AddSeconds(-(int)(interval - 1))); } - return result.AsExchangeResult>(Exchange, result.Data.Reverse().Select(x => new SharedMarkKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)).ToArray(), nextToken); + return result.AsExchangeResult>(Exchange, request.Symbol.ApiType, result.Data.Reverse().Select(x => new SharedMarkKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)).ToArray(), nextToken); } #endregion @@ -758,9 +758,9 @@ async Task> IOpenInterestRestClient.GetOpe var result = await ExchangeData.GetOpenInterestAsync(request.Symbol.GetSymbol(FormatSymbol), ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult(Exchange, default); + return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, new SharedOpenInterest(result.Data.OpenInterest)); + return result.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedOpenInterest(result.Data.OpenInterest)); } #endregion @@ -786,14 +786,14 @@ async Task>> IFundingRateRestCl limit: request.Limit ?? 1000, ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult>(Exchange, default); + return result.AsExchangeResult>(Exchange, null, default); DateTimeToken? nextToken = null; if (result.Data.Count() == (request.Limit ?? 1000)) nextToken = new DateTimeToken(result.Data.Max(x => x.FundingTime)); // Return - return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedFundingRate(x.FundingRate, x.FundingTime)).ToArray(), nextToken); + return result.AsExchangeResult>(Exchange, request.Symbol.ApiType, result.Data.Select(x => new SharedFundingRate(x.FundingRate, x.FundingTime)).ToArray(), nextToken); } #endregion @@ -808,9 +808,9 @@ async Task>> IBalanceRestClient.Get var result = await Account.GetBalancesAsync(ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult>(Exchange, default); + return result.AsExchangeResult>(Exchange, null, default); - return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedBalance(x.Asset, x.AvailableBalance, x.WalletBalance)).ToArray()); + return result.AsExchangeResult>(Exchange, SupportedApiTypes, result.Data.Select(x => new SharedBalance(x.Asset, x.AvailableBalance, x.WalletBalance)).ToArray()); } #endregion @@ -826,9 +826,9 @@ async Task> IPositionModeRestClient. var result = await Account.GetPositionModeAsync(ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult(Exchange, default); + return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, new SharedPositionModeResult(result.Data.IsHedgeMode ? SharedPositionMode.HedgeMode : SharedPositionMode.OneWay)); + return result.AsExchangeResult(Exchange, SupportedApiTypes, new SharedPositionModeResult(result.Data.IsHedgeMode ? SharedPositionMode.HedgeMode : SharedPositionMode.OneWay)); } SetPositionModeOptions IPositionModeRestClient.SetPositionModeOptions { get; } = new SetPositionModeOptions(true, true, false); @@ -840,9 +840,9 @@ async Task> IPositionModeRestClient. var result = await Account.ModifyPositionModeAsync(request.Mode == SharedPositionMode.HedgeMode, ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult(Exchange, default); + return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, new SharedPositionModeResult(request.Mode)); + return result.AsExchangeResult(Exchange, SupportedApiTypes, new SharedPositionModeResult(request.Mode)); } #endregion @@ -858,9 +858,9 @@ async Task> IListenKeyRestClient.StartListenKeyAsync(S // Get data var result = await Account.StartUserStreamAsync(ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult(Exchange, default); + return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, result.Data); + return result.AsExchangeResult(Exchange, SupportedApiTypes, result.Data); } EndpointOptions IListenKeyRestClient.KeepAliveOptions { get; } = new EndpointOptions(true); async Task> IListenKeyRestClient.KeepAliveListenKeyAsync(KeepAliveListenKeyRequest request, CancellationToken ct) @@ -872,9 +872,9 @@ async Task> IListenKeyRestClient.KeepAliveListenKeyAsy // Get data var result = await Account.KeepAliveUserStreamAsync(request.ListenKey, ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult(Exchange, default); + return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, request.ListenKey); + return result.AsExchangeResult(Exchange, SupportedApiTypes, request.ListenKey); } EndpointOptions IListenKeyRestClient.StopOptions { get; } = new EndpointOptions(true); @@ -887,9 +887,9 @@ async Task> IListenKeyRestClient.StopListenKeyAsync(St // Get data var result = await Account.StopUserStreamAsync(request.ListenKey, ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult(Exchange, default); + return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, request.ListenKey); + return result.AsExchangeResult(Exchange, SupportedApiTypes, request.ListenKey); } #endregion } diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs index e42ddf547..9c7916eab 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs @@ -69,7 +69,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden public IBinanceSocketClientCoinFuturesApiShared SharedClient => this; /// - public override string FormatSymbol(string baseAsset, string quoteAsset, ApiType apiType, DateTime? deliverTime = null) + public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode apiType, DateTime? deliverTime = null) { return baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + (deliverTime == null ? "_PERP" : "_" + deliverTime.Value.ToString("yyMMdd")); } diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs index 8f5769b21..98051482b 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs @@ -19,7 +19,7 @@ namespace Binance.Net.Clients.CoinFuturesApi internal partial class BinanceSocketClientCoinFuturesApi : IBinanceSocketClientCoinFuturesApiShared { public string Exchange => BinanceExchange.ExchangeName; - public ApiType[] SupportedApiTypes => new[] { ApiType.DeliveryInverse, ApiType.PerpetualInverse }; + public TradingMode[] SupportedApiTypes => new[] { TradingMode.DeliveryInverse, TradingMode.PerpetualInverse }; public void SetDefaultExchangeParameter(string key, object value) => ExchangeParameters.SetStaticParameter(Exchange, key, value); public void ResetDefaultExchangeParameters() => ExchangeParameters.ResetStaticParameters(); @@ -54,7 +54,7 @@ async Task> ITickersSocketClient.SubscribeToA { var data = update.Data; if (request.ApiType != null) - data = update.Data.Where(x => request.ApiType == ApiType.PerpetualInverse ? x.Symbol.EndsWith("_PERP") : !x.Symbol.Contains("_PERP")); + data = update.Data.Where(x => request.ApiType == TradingMode.PerpetualInverse ? x.Symbol.EndsWith("_PERP") : !x.Symbol.Contains("_PERP")); if (!data.Any()) return; diff --git a/Binance.Net/Clients/GeneralApi/BinanceRestClientGeneralApi.cs b/Binance.Net/Clients/GeneralApi/BinanceRestClientGeneralApi.cs index 435a2942f..4055323c8 100644 --- a/Binance.Net/Clients/GeneralApi/BinanceRestClientGeneralApi.cs +++ b/Binance.Net/Clients/GeneralApi/BinanceRestClientGeneralApi.cs @@ -74,7 +74,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(); /// - public override string FormatSymbol(string baseAsset, string quoteAsset, ApiType apiType, DateTime? deliverTime = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); + public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode apiType, DateTime? deliverTime = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); 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 bdf368c8e..968fc6713 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApi.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApi.cs @@ -76,7 +76,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(); /// - public override string FormatSymbol(string baseAsset, string quoteAsset, ApiType apiType, DateTime? deliverTime) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); + public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode apiType, DateTime? deliverTime) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); #region helpers diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index b89c02823..110e85148 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -15,7 +15,7 @@ namespace Binance.Net.Clients.SpotApi internal partial class BinanceRestClientSpotApi : IBinanceRestClientSpotApiShared { public string Exchange => BinanceExchange.ExchangeName; - public ApiType[] SupportedApiTypes => new[] { ApiType.Spot }; + public TradingMode[] SupportedApiTypes => new[] { TradingMode.Spot }; public void SetDefaultExchangeParameter(string key, object value) => ExchangeParameters.SetStaticParameter(Exchange, key, value); public void ResetDefaultExchangeParameters() => ExchangeParameters.ResetStaticParameters(); @@ -64,7 +64,7 @@ async Task>> IKlineRestClient.GetKlin ct: ct ).ConfigureAwait(false); if (!result) - return new ExchangeWebResult>(Exchange, result.As>(default)); + return new ExchangeWebResult>(Exchange, TradingMode.Spot, result.As>(default)); // Get next token DateTimeToken? nextToken = null; @@ -75,7 +75,7 @@ async Task>> IKlineRestClient.GetKlin nextToken = new DateTimeToken(minOpenTime.AddSeconds(-(int)(interval - 1))); } - return result.AsExchangeResult>(Exchange, result.Data.Reverse().Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)).ToArray(), nextToken); + return result.AsExchangeResult>(Exchange, request.Symbol.ApiType, result.Data.Reverse().Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)).ToArray(), nextToken); } #endregion @@ -85,15 +85,15 @@ async Task>> IKlineRestClient.GetKlin async Task>> ISpotSymbolRestClient.GetSpotSymbolsAsync(GetSymbolsRequest request, CancellationToken ct) { - var validationError = ((ISpotSymbolRestClient)this).GetSpotSymbolsOptions.ValidateRequest(Exchange, request, ApiType.Spot, SupportedApiTypes); + var validationError = ((ISpotSymbolRestClient)this).GetSpotSymbolsOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); var result = await ExchangeData.GetExchangeInfoAsync(ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult>(Exchange, default); + return result.AsExchangeResult>(Exchange, null, default); - return result.AsExchangeResult>(Exchange, result.Data.Symbols.Select(s => new SharedSpotSymbol(s.BaseAsset, s.QuoteAsset, s.Name, s.Status == SymbolStatus.Trading && s.IsSpotTradingAllowed) + return result.AsExchangeResult>(Exchange, TradingMode.Spot, result.Data.Symbols.Select(s => new SharedSpotSymbol(s.BaseAsset, s.QuoteAsset, s.Name, s.Status == SymbolStatus.Trading && s.IsSpotTradingAllowed) { MinTradeQuantity = s.LotSizeFilter?.MinQuantity, MaxTradeQuantity = s.LotSizeFilter?.MaxQuantity, @@ -116,23 +116,23 @@ async Task> ISpotTickerRestClient.GetSpotTic var result = await ExchangeData.GetTickerAsync(request.Symbol.GetSymbol(FormatSymbol), ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult(Exchange, default); + return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, new SharedSpotTicker(result.Data.Symbol, result.Data.LastPrice, result.Data.HighPrice, result.Data.LowPrice, result.Data.Volume, result.Data.PriceChangePercent)); + return result.AsExchangeResult(Exchange, TradingMode.Spot, new SharedSpotTicker(result.Data.Symbol, result.Data.LastPrice, result.Data.HighPrice, result.Data.LowPrice, result.Data.Volume, result.Data.PriceChangePercent)); } EndpointOptions ISpotTickerRestClient.GetSpotTickersOptions { get; } = new EndpointOptions(false); async Task>> ISpotTickerRestClient.GetSpotTickersAsync(GetTickersRequest request, CancellationToken ct) { - var validationError = ((ISpotTickerRestClient)this).GetSpotTickersOptions.ValidateRequest(Exchange, request, ApiType.Spot, SupportedApiTypes); + var validationError = ((ISpotTickerRestClient)this).GetSpotTickersOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); var result = await ExchangeData.GetTickersAsync(ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult>(Exchange, default); + return result.AsExchangeResult>(Exchange, null, default); - return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedSpotTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume, x.PriceChangePercent)).ToArray()); + return result.AsExchangeResult>(Exchange, TradingMode.Spot, result.Data.Select(x => new SharedSpotTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume, x.PriceChangePercent)).ToArray()); } #endregion @@ -152,10 +152,10 @@ async Task>> IRecentTradeRestClient.G limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult>(Exchange, default); + return result.AsExchangeResult>(Exchange, null, default); // Return - return result.AsExchangeResult>(Exchange, 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)).ToArray()); } #endregion @@ -181,14 +181,14 @@ async Task>> ITradeHistoryRestClient. fromId: fromId, ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult>(Exchange, default); + return result.AsExchangeResult>(Exchange, null, default); FromIdToken? nextToken = null; if (result.Data.Any() && result.Data.Last().TradeTime < request.EndTime) nextToken = new FromIdToken(result.Data.Max(x => x.Id).ToString()); // Return - return result.AsExchangeResult>(Exchange, 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)).ToArray(), nextToken); } #endregion @@ -205,9 +205,9 @@ async Task> IOrderBookRestClient.GetOrderBook limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult(Exchange, default); + return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, new SharedOrderBook(result.Data.Asks, result.Data.Bids)); + return result.AsExchangeResult(Exchange, TradingMode.Spot, new SharedOrderBook(result.Data.Asks, result.Data.Bids)); } #endregion @@ -223,9 +223,9 @@ async Task>> IBalanceRestClient.Get var result = await Account.GetBalancesAsync(ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult>(Exchange, default); + return result.AsExchangeResult>(Exchange, null, default); - return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedBalance(x.Asset, x.Available, x.Total)).ToArray()); + return result.AsExchangeResult>(Exchange, TradingMode.Spot, result.Data.Select(x => new SharedBalance(x.Asset, x.Available, x.Total)).ToArray()); } #endregion @@ -272,9 +272,9 @@ async Task> ISpotOrderRestClient.PlaceSpotOrderAsync ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult(Exchange, default); + return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, new SharedId(result.Data.Id.ToString())); + return result.AsExchangeResult(Exchange, TradingMode.Spot, new SharedId(result.Data.Id.ToString())); } EndpointOptions ISpotOrderRestClient.GetSpotOrderOptions { get; } = new EndpointOptions(true); @@ -289,9 +289,9 @@ async Task> ISpotOrderRestClient.GetSpotOrder var order = await Trading.GetOrderAsync(request.Symbol.GetSymbol(FormatSymbol), orderId, ct: ct).ConfigureAwait(false); if (!order) - return order.AsExchangeResult(Exchange, default); + return order.AsExchangeResult(Exchange, null, default); - return order.AsExchangeResult(Exchange, new SharedSpotOrder( + return order.AsExchangeResult(Exchange, TradingMode.Spot, new SharedSpotOrder( order.Data.Symbol, order.Data.Id.ToString(), ParseOrderType(order.Data.Type), @@ -321,9 +321,9 @@ async Task>> ISpotOrderRestClient var symbol = request.Symbol?.GetSymbol(FormatSymbol); var orders = await Trading.GetOpenOrdersAsync(symbol, ct: ct).ConfigureAwait(false); if (!orders) - return orders.AsExchangeResult>(Exchange, default); + return orders.AsExchangeResult>(Exchange, null, default); - return orders.AsExchangeResult>(Exchange, orders.Data.Select(x => new SharedSpotOrder( + return orders.AsExchangeResult>(Exchange, TradingMode.Spot, orders.Data.Select(x => new SharedSpotOrder( x.Symbol, x.Id.ToString(), ParseOrderType(x.Type), @@ -351,26 +351,25 @@ async Task>> ISpotOrderRestClient return new ExchangeWebResult>(Exchange, validationError); // Determine page token - long? fromId = null; - if (pageToken is FromIdToken fromIdToken) - fromId = long.Parse(fromIdToken.FromToken); + DateTime? fromTime = null; + if (pageToken is DateTimeToken dateTimeToken) + fromTime = dateTimeToken.LastTime; // Get data var orders = await Trading.GetOrdersAsync(request.Symbol.GetSymbol(FormatSymbol), - orderId: fromId, startTime: request.StartTime, - endTime: request.EndTime, + endTime: fromTime ?? request.EndTime, limit: request.Limit ?? 1000, ct: ct).ConfigureAwait(false); if (!orders) - return orders.AsExchangeResult>(Exchange, default); + return orders.AsExchangeResult>(Exchange, null, default); // Get next token - FromIdToken? nextToken = null; + DateTimeToken? nextToken = null; if (orders.Data.Any()) - nextToken = new FromIdToken(orders.Data.Max(o => o.Id + 1).ToString()); + nextToken = new DateTimeToken(orders.Data.Min(o => o.CreateTime).AddMilliseconds(-1)); - return orders.AsExchangeResult>(Exchange, orders.Data.Where(x => x.Status == OrderStatus.Filled || x.Status == OrderStatus.Canceled || x.Status == OrderStatus.Expired).Select(x => new SharedSpotOrder( + return orders.AsExchangeResult>(Exchange, TradingMode.Spot, orders.Data.Where(x => x.Status == OrderStatus.Filled || x.Status == OrderStatus.Canceled || x.Status == OrderStatus.Expired).Select(x => new SharedSpotOrder( x.Symbol, x.Id.ToString(), ParseOrderType(x.Type), @@ -402,9 +401,9 @@ async Task>> ISpotOrderRestClient var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol(FormatSymbol), orderId: orderId, ct: ct).ConfigureAwait(false); if (!orders) - return orders.AsExchangeResult>(Exchange, default); + return orders.AsExchangeResult>(Exchange, null, default); - return orders.AsExchangeResult>(Exchange, orders.Data.Select(x => new SharedUserTrade( + return orders.AsExchangeResult>(Exchange, TradingMode.Spot, orders.Data.Select(x => new SharedUserTrade( x.Symbol, x.OrderId.ToString(), x.Id.ToString(), @@ -418,7 +417,7 @@ async Task>> ISpotOrderRestClient }).ToArray()); } - PaginatedEndpointOptions ISpotOrderRestClient.GetSpotUserTradesOptions { get; } = new PaginatedEndpointOptions(SharedPaginationType.Ascending, true); + PaginatedEndpointOptions ISpotOrderRestClient.GetSpotUserTradesOptions { get; } = new PaginatedEndpointOptions(SharedPaginationType.Descending, true); async Task>> ISpotOrderRestClient.GetSpotUserTradesAsync(GetUserTradesRequest request, INextPageToken? pageToken, CancellationToken ct) { var validationError = ((ISpotOrderRestClient)this).GetSpotUserTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); @@ -426,27 +425,26 @@ async Task>> ISpotOrderRestClient return new ExchangeWebResult>(Exchange, validationError); // Determine page token - long? fromId = null; - if (pageToken is FromIdToken fromIdToken) - fromId = long.Parse(fromIdToken.FromToken); + DateTime? fromTimestamp = null; + if (pageToken is DateTimeToken dateTimeToken) + fromTimestamp = dateTimeToken.LastTime; // Get data var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol(FormatSymbol), startTime: request.StartTime, - endTime: request.EndTime, + endTime: fromTimestamp ?? request.EndTime, limit: request.Limit ?? 500, - fromId: fromId, ct: ct ).ConfigureAwait(false); if (!orders) - return orders.AsExchangeResult>(Exchange, default); + return orders.AsExchangeResult>(Exchange, null, default); // Get next token - FromIdToken? nextToken = null; + DateTimeToken? nextToken = null; if (orders.Data.Count() == (request.Limit ?? 500)) - nextToken = new FromIdToken(orders.Data.Max(o => o.Id).ToString()); + nextToken = new DateTimeToken(orders.Data.Min(o => o.Timestamp).AddMilliseconds(-1)); - return orders.AsExchangeResult>(Exchange, orders.Data.Select(x => new SharedUserTrade( + return orders.AsExchangeResult>(Exchange, TradingMode.Spot, orders.Data.Select(x => new SharedUserTrade( x.Symbol, x.OrderId.ToString(), x.Id.ToString(), @@ -472,9 +470,9 @@ async Task> ISpotOrderRestClient.CancelSpotOrderAsyn var order = await Trading.CancelOrderAsync(request.Symbol.GetSymbol(FormatSymbol), orderId, ct: ct).ConfigureAwait(false); if (!order) - return order.AsExchangeResult(Exchange, default); + return order.AsExchangeResult(Exchange, null, default); - return order.AsExchangeResult(Exchange, new SharedId(order.Data.Id.ToString())); + return order.AsExchangeResult(Exchange, TradingMode.Spot, new SharedId(order.Data.Id.ToString())); } private Enums.TimeInForce? GetTimeInForce(SharedTimeInForce? tif, SharedOrderType type) @@ -519,15 +517,15 @@ private SharedOrderType ParseOrderType(SpotOrderType type) async Task>> IAssetsRestClient.GetAssetsAsync(GetAssetsRequest request, CancellationToken ct) { - var validationError = ((IAssetsRestClient)this).GetAssetsOptions.ValidateRequest(Exchange, request, ApiType.Spot, SupportedApiTypes); + var validationError = ((IAssetsRestClient)this).GetAssetsOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); var assets = await Account.GetUserAssetsAsync(ct: ct).ConfigureAwait(false); if (!assets) - return assets.AsExchangeResult>(Exchange, default); + return assets.AsExchangeResult>(Exchange, null, default); - return assets.AsExchangeResult>(Exchange, assets.Data.Select(x => new SharedAsset(x.Asset) + return assets.AsExchangeResult>(Exchange, TradingMode.Spot, assets.Data.Select(x => new SharedAsset(x.Asset) { FullName = x.Name, Networks = x.NetworkList.Select(x => new SharedAssetNetwork(x.Network) @@ -546,19 +544,19 @@ async Task>> IAssetsRestClient.GetAss EndpointOptions IAssetsRestClient.GetAssetOptions { get; } = new EndpointOptions(false); async Task> IAssetsRestClient.GetAssetAsync(GetAssetRequest request, CancellationToken ct) { - var validationError = ((IAssetsRestClient)this).GetAssetOptions.ValidateRequest(Exchange, request, ApiType.Spot, SupportedApiTypes); + var validationError = ((IAssetsRestClient)this).GetAssetOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); var assets = await Account.GetUserAssetsAsync(ct: ct).ConfigureAwait(false); if (!assets) - return assets.AsExchangeResult(Exchange, default); + return assets.AsExchangeResult(Exchange, null, default); var asset = assets.Data.SingleOrDefault(x => x.Asset.Equals(request.Asset, StringComparison.InvariantCultureIgnoreCase)); if (asset == null) return assets.AsExchangeError(Exchange, new ServerError("Asset not found")); - return assets.AsExchangeResult(Exchange,new SharedAsset(asset.Asset) + return assets.AsExchangeResult(Exchange, TradingMode.Spot, new SharedAsset(asset.Asset) { FullName = asset.Name, Networks = asset.NetworkList.Select(x => new SharedAssetNetwork(x.Network) @@ -581,15 +579,15 @@ async Task> IAssetsRestClient.GetAssetAsync(GetAs EndpointOptions IDepositRestClient.GetDepositAddressesOptions { get; } = new EndpointOptions(true); async Task>> IDepositRestClient.GetDepositAddressesAsync(GetDepositAddressesRequest request, CancellationToken ct) { - var validationError = ((IDepositRestClient)this).GetDepositAddressesOptions.ValidateRequest(Exchange, request, ApiType.Spot, SupportedApiTypes); + var validationError = ((IDepositRestClient)this).GetDepositAddressesOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); var depositAddresses = await Account.GetDepositAddressAsync(request.Asset, request.Network, ct: ct).ConfigureAwait(false); if (!depositAddresses) - return depositAddresses.AsExchangeResult>(Exchange, default); + return depositAddresses.AsExchangeResult>(Exchange, null, default); - return depositAddresses.AsExchangeResult>(Exchange, new[] { new SharedDepositAddress(depositAddresses.Data.Asset, depositAddresses.Data.Address) + return depositAddresses.AsExchangeResult>(Exchange, TradingMode.Spot, new[] { new SharedDepositAddress(depositAddresses.Data.Asset, depositAddresses.Data.Address) { TagOrMemo = depositAddresses.Data.Tag } @@ -599,7 +597,7 @@ async Task>> IDepositRestCli GetDepositsOptions IDepositRestClient.GetDepositsOptions { get; } = new GetDepositsOptions(SharedPaginationType.Descending, true); async Task>> IDepositRestClient.GetDepositsAsync(GetDepositsRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((IDepositRestClient)this).GetDepositsOptions.ValidateRequest(Exchange, request, ApiType.Spot, SupportedApiTypes); + var validationError = ((IDepositRestClient)this).GetDepositsOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -617,14 +615,14 @@ async Task>> IDepositRestClient.Get offset: offset, ct: ct).ConfigureAwait(false); if (!deposits) - return deposits.AsExchangeResult>(Exchange, default); + return deposits.AsExchangeResult>(Exchange, null, default); // Determine next token OffsetToken? nextToken = null; if (deposits.Data.Count() == (request.Limit ?? 100)) nextToken = new OffsetToken((offset ?? 0) + deposits.Data.Count()); - return deposits.AsExchangeResult>(Exchange, deposits.Data.Select(x => new SharedDeposit(x.Asset, x.Quantity, x.Status == DepositStatus.Success, x.InsertTime) + return deposits.AsExchangeResult>(Exchange, TradingMode.Spot, deposits.Data.Select(x => new SharedDeposit(x.Asset, x.Quantity, x.Status == DepositStatus.Success, x.InsertTime) { Confirmations = x.Confirmations.Contains("/") ? int.Parse(x.Confirmations.Split(new[] { "/" }, StringSplitOptions.RemoveEmptyEntries)[0]) : null, Network = x.Network, @@ -641,7 +639,7 @@ async Task>> IDepositRestClient.Get GetWithdrawalsOptions IWithdrawalRestClient.GetWithdrawalsOptions { get; } = new GetWithdrawalsOptions(SharedPaginationType.Descending, true); async Task>> IWithdrawalRestClient.GetWithdrawalsAsync(GetWithdrawalsRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((IWithdrawalRestClient)this).GetWithdrawalsOptions.ValidateRequest(Exchange, request, ApiType.Spot, SupportedApiTypes); + var validationError = ((IWithdrawalRestClient)this).GetWithdrawalsOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -659,14 +657,14 @@ async Task>> IWithdrawalRestClie offset: offset, ct: ct).ConfigureAwait(false); if (!withdrawals) - return withdrawals.AsExchangeResult>(Exchange, default); + return withdrawals.AsExchangeResult>(Exchange, null, default); // Determine next token OffsetToken nextToken; if (withdrawals.Data.Count() == (request.Limit ?? 100)) nextToken = new OffsetToken((offset ?? 0) + withdrawals.Data.Count()); - return withdrawals.AsExchangeResult>(Exchange, withdrawals.Data.Select(x => new SharedWithdrawal(x.Asset, x.Address, x.Quantity, x.Status == WithdrawalStatus.Completed, x.ApplyTime) + return withdrawals.AsExchangeResult>(Exchange, TradingMode.Spot, withdrawals.Data.Select(x => new SharedWithdrawal(x.Asset, x.Address, x.Quantity, x.Status == WithdrawalStatus.Completed, x.ApplyTime) { Confirmations = x.ConfirmTimes, Network = x.Network, @@ -684,7 +682,7 @@ async Task>> IWithdrawalRestClie WithdrawOptions IWithdrawRestClient.WithdrawOptions { get; } = new WithdrawOptions(); async Task > IWithdrawRestClient.WithdrawAsync(WithdrawRequest request, CancellationToken ct) { - var validationError = ((IWithdrawRestClient)this).WithdrawOptions.ValidateRequest(Exchange, request, ApiType.Spot, SupportedApiTypes); + var validationError = ((IWithdrawRestClient)this).WithdrawOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedApiTypes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -697,9 +695,9 @@ async Task>> IWithdrawalRestClie addressTag: request.AddressTag, ct: ct).ConfigureAwait(false); if (!withdrawal) - return withdrawal.AsExchangeResult(Exchange, default); + return withdrawal.AsExchangeResult(Exchange, null, default); - return withdrawal.AsExchangeResult(Exchange, new SharedId(withdrawal.Data.Id)); + return withdrawal.AsExchangeResult(Exchange, TradingMode.Spot, new SharedId(withdrawal.Data.Id)); } #endregion @@ -716,9 +714,9 @@ async Task> IListenKeyRestClient.StartListenKeyAsync(S // Get data var result = await Account.StartUserStreamAsync(ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult(Exchange, default); + return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, result.Data); + return result.AsExchangeResult(Exchange, TradingMode.Spot, result.Data); } EndpointOptions IListenKeyRestClient.KeepAliveOptions { get; } = new EndpointOptions(true); async Task> IListenKeyRestClient.KeepAliveListenKeyAsync(KeepAliveListenKeyRequest request, CancellationToken ct) @@ -730,9 +728,9 @@ async Task> IListenKeyRestClient.KeepAliveListenKeyAsy // Get data var result = await Account.KeepAliveUserStreamAsync(request.ListenKey, ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult(Exchange, default); + return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, request.ListenKey); + return result.AsExchangeResult(Exchange, TradingMode.Spot, request.ListenKey); } EndpointOptions IListenKeyRestClient.StopOptions { get; } = new EndpointOptions(true); @@ -745,9 +743,9 @@ async Task> IListenKeyRestClient.StopListenKeyAsync(St // Get data var result = await Account.StopUserStreamAsync(request.ListenKey, ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult(Exchange, default); + return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, request.ListenKey); + return result.AsExchangeResult(Exchange, TradingMode.Spot, request.ListenKey); } #endregion } diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs index 7867e2f81..521c613dd 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs @@ -63,7 +63,7 @@ internal BinanceSocketClientSpotApi(ILogger logger, BinanceSocketOptions options public IBinanceSocketClientSpotApiShared SharedClient => this; /// - public override string FormatSymbol(string baseAsset, string quoteAsset, ApiType apiType, DateTime? deliverTime = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); + public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode apiType, DateTime? deliverTime = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); /// protected override AuthenticationProvider CreateAuthenticationProvider(ApiCredentials credentials) diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs index 4d9949aad..f471ebd04 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs @@ -17,7 +17,7 @@ namespace Binance.Net.Clients.SpotApi internal partial class BinanceSocketClientSpotApi : IBinanceSocketClientSpotApiShared { public string Exchange => BinanceExchange.ExchangeName; - public ApiType[] SupportedApiTypes => new[] { ApiType.Spot }; + public TradingMode[] SupportedApiTypes => new[] { TradingMode.Spot }; public void SetDefaultExchangeParameter(string key, object value) => ExchangeParameters.SetStaticParameter(Exchange, key, value); public void ResetDefaultExchangeParameters() => ExchangeParameters.ResetStaticParameters(); @@ -120,7 +120,7 @@ async Task> IBalanceSocketClient.SubscribeToB }; async Task> ISpotOrderSocketClient.SubscribeToSpotOrderUpdatesAsync(SubscribeSpotOrderRequest request, Action>> handler, CancellationToken ct) { - var validationError = ((ISpotOrderSocketClient)this).SubscribeSpotOrderOptions.ValidateRequest(Exchange, request, ApiType.Spot, SupportedApiTypes); + var validationError = ((ISpotOrderSocketClient)this).SubscribeSpotOrderOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedApiTypes); if (validationError != null) return new ExchangeResult(Exchange, validationError); diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs index 474f70032..0c235b1b1 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs @@ -49,7 +49,7 @@ internal partial class BinanceRestClientUsdFuturesApi : RestApiClient, IBinanceR public event Action? OnOrderCanceled; /// - public override string FormatSymbol(string baseAsset, string quoteAsset, ApiType apiType, DateTime? deliverTime = null) + public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode apiType, DateTime? deliverTime = null) { return baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + (deliverTime == null ? string.Empty : "_" + deliverTime.Value.ToString("yyMMdd")); } diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs index 2c337857b..2c22fe2f2 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -20,7 +20,7 @@ internal partial class BinanceRestClientUsdFuturesApi : IBinanceRestClientUsdFut { public string Exchange => BinanceExchange.ExchangeName; - public ApiType[] SupportedApiTypes => new[] { ApiType.DeliveryLinear, ApiType.PerpetualLinear }; + public TradingMode[] SupportedApiTypes => new[] { TradingMode.DeliveryLinear, TradingMode.PerpetualLinear }; public void SetDefaultExchangeParameter(string key, object value) => ExchangeParameters.SetStaticParameter(Exchange, key, value); public void ResetDefaultExchangeParameters() => ExchangeParameters.ResetStaticParameters(); @@ -67,7 +67,7 @@ async Task>> IKlineRestClient.GetKlin ct: ct ).ConfigureAwait(false); if (!result) - return result.AsExchangeResult>(Exchange, default); + return result.AsExchangeResult>(Exchange, null, default); // Get next token DateTimeToken? nextToken = null; @@ -78,7 +78,7 @@ async Task>> IKlineRestClient.GetKlin nextToken = new DateTimeToken(minOpenTime.AddSeconds(-(int)(interval - 1))); } - return result.AsExchangeResult>(Exchange, result.Data.Reverse().Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)).ToArray(), nextToken); + return result.AsExchangeResult>(Exchange, request.Symbol.ApiType, result.Data.Reverse().Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)).ToArray(), nextToken); } #endregion @@ -126,7 +126,7 @@ async Task>> IMarkPriceKlineRestC ct: ct ).ConfigureAwait(false); if (!result) - return result.AsExchangeResult>(Exchange, default); + return result.AsExchangeResult>(Exchange, null, default); // Get next token DateTimeToken? nextToken = null; @@ -137,7 +137,7 @@ async Task>> IMarkPriceKlineRestC nextToken = new DateTimeToken(minOpenTime.AddSeconds(-(int)(interval - 1))); } - return result.AsExchangeResult>(Exchange, result.Data.Reverse().Select(x => new SharedMarkKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)).ToArray(), nextToken); + return result.AsExchangeResult>(Exchange, request.Symbol.ApiType, result.Data.Reverse().Select(x => new SharedMarkKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)).ToArray(), nextToken); } #endregion @@ -153,12 +153,12 @@ async Task>> IFuturesSymbolRe var result = await ExchangeData.GetExchangeInfoAsync(ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult< IEnumerable>(Exchange, default); + return result.AsExchangeResult>(Exchange, null, default); var data = result.Data.Symbols.Where(x => x.ContractType != null); if (request.ApiType != null) - data = data.Where(x => request.ApiType == ApiType.PerpetualLinear ? x.ContractType == ContractType.Perpetual : (x.ContractType != ContractType.Perpetual && x.ContractType != ContractType.PerpetualDelivering)); - return result.AsExchangeResult>(Exchange, data.Select(s => new SharedFuturesSymbol(s.ContractType == ContractType.Perpetual ? SharedSymbolType.PerpetualLinear : SharedSymbolType.DeliveryLinear, s.BaseAsset, s.QuoteAsset, s.Name, s.Status == SymbolStatus.Trading) + data = data.Where(x => request.ApiType == TradingMode.PerpetualLinear ? x.ContractType == ContractType.Perpetual : (x.ContractType != ContractType.Perpetual && x.ContractType != ContractType.PerpetualDelivering)); + return result.AsExchangeResult>(Exchange, request.ApiType == null ? SupportedApiTypes : new[] { request.ApiType.Value }, data.Select(s => new SharedFuturesSymbol(s.ContractType == ContractType.Perpetual ? SharedSymbolType.PerpetualLinear : SharedSymbolType.DeliveryLinear, s.BaseAsset, s.QuoteAsset, s.Name, s.Status == SymbolStatus.Trading) { MinTradeQuantity = s.LotSizeFilter?.MinQuantity, MaxTradeQuantity = s.LotSizeFilter?.MaxQuantity, @@ -185,11 +185,11 @@ async Task> IFuturesTickerRestClient.GetF await Task.WhenAll(resultTicker, resultMarkPrice).ConfigureAwait(false); if (!resultTicker.Result) - return resultTicker.Result.AsExchangeResult(Exchange, default); + return resultTicker.Result.AsExchangeResult(Exchange, null, default); if (!resultMarkPrice.Result) - return resultMarkPrice.Result.AsExchangeResult(Exchange, default); + return resultMarkPrice.Result.AsExchangeResult(Exchange, null, default); - return resultTicker.Result.AsExchangeResult(Exchange, new SharedFuturesTicker(resultTicker.Result.Data.Symbol, resultTicker.Result.Data.LastPrice, resultTicker.Result.Data.HighPrice, resultTicker.Result.Data.LowPrice, resultTicker.Result.Data.Volume, resultTicker.Result.Data.PriceChangePercent) + return resultTicker.Result.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedFuturesTicker(resultTicker.Result.Data.Symbol, resultTicker.Result.Data.LastPrice, resultTicker.Result.Data.HighPrice, resultTicker.Result.Data.LowPrice, resultTicker.Result.Data.Volume, resultTicker.Result.Data.PriceChangePercent) { MarkPrice = resultMarkPrice.Result.Data.MarkPrice, IndexPrice = resultMarkPrice.Result.Data.IndexPrice, @@ -209,15 +209,15 @@ async Task>> IFuturesTickerRe var resultMarkPrices = ExchangeData.GetMarkPricesAsync(ct: ct); await Task.WhenAll(resultTickers, resultMarkPrices).ConfigureAwait(false); if (!resultTickers.Result) - return resultTickers.Result.AsExchangeResult>(Exchange, default); + return resultTickers.Result.AsExchangeResult>(Exchange, null, default); if (!resultMarkPrices.Result) - return resultMarkPrices.Result.AsExchangeResult>(Exchange, default); + return resultMarkPrices.Result.AsExchangeResult>(Exchange, null, default); var data = resultTickers.Result.Data; if (request.ApiType.HasValue) - data = data.Where(x => (request.ApiType == ApiType.DeliveryLinear ? x.Symbol.Contains("_") : !x.Symbol.Contains("_"))); + data = data.Where(x => (request.ApiType == TradingMode.DeliveryLinear ? x.Symbol.Contains("_") : !x.Symbol.Contains("_"))); - return resultTickers.Result.AsExchangeResult>(Exchange, data.Select(x => + return resultTickers.Result.AsExchangeResult>(Exchange, request.ApiType == null ? SupportedApiTypes : new[] { request.ApiType.Value }, data.Select(x => { var markPrice = resultMarkPrices.Result.Data.Single(p => p.Symbol == x.Symbol); return new SharedFuturesTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume, x.PriceChangePercent) @@ -246,9 +246,9 @@ async Task>> IRecentTradeRestClient.G limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult>(Exchange, default); + return result.AsExchangeResult>(Exchange, null, default); - return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedTrade(x.BaseQuantity, x.Price, x.TradeTime)).ToArray()); + return result.AsExchangeResult>(Exchange, request.Symbol.ApiType, result.Data.Select(x => new SharedTrade(x.BaseQuantity, x.Price, x.TradeTime)).ToArray()); } #endregion @@ -295,9 +295,9 @@ async Task> IFuturesOrderRestClient.PlaceFuturesOrde ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult(Exchange, default); + return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, new SharedId(result.Data.Id.ToString())); + return result.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedId(result.Data.Id.ToString())); } EndpointOptions IFuturesOrderRestClient.GetFuturesOrderOptions { get; } = new EndpointOptions(true); @@ -312,9 +312,9 @@ async Task> IFuturesOrderRestClient.GetFut var order = await Trading.GetOrderAsync(request.Symbol.GetSymbol(FormatSymbol), orderId, ct: ct).ConfigureAwait(false); if (!order) - return order.AsExchangeResult(Exchange, default); + return order.AsExchangeResult(Exchange, null, default); - return order.AsExchangeResult(Exchange, new SharedFuturesOrder( + return order.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedFuturesOrder( order.Data.Symbol, order.Data.Id.ToString(), ParseOrderType(order.Data.Type), @@ -345,9 +345,9 @@ async Task>> IFuturesOrderRest var symbol = request.Symbol?.GetSymbol(FormatSymbol); var orders = await Trading.GetOpenOrdersAsync(symbol, ct: ct).ConfigureAwait(false); if (!orders) - return orders.AsExchangeResult>(Exchange, default); + return orders.AsExchangeResult>(Exchange, null, default); - return orders.AsExchangeResult>(Exchange, orders.Data.Select(x => new SharedFuturesOrder( + return orders.AsExchangeResult>(Exchange, SupportedApiTypes, orders.Data.Select(x => new SharedFuturesOrder( x.Symbol, x.Id.ToString(), ParseOrderType(x.Type), @@ -387,14 +387,14 @@ async Task>> IFuturesOrderRest limit: request.Limit ?? 1000, ct: ct).ConfigureAwait(false); if (!orders) - return orders.AsExchangeResult>(Exchange, default); + return orders.AsExchangeResult>(Exchange, null, default); // Get next token DateTimeToken? nextToken = null; if (orders.Data.Count() == (request.Limit ?? 1000)) nextToken = new DateTimeToken(orders.Data.Max(o => o.CreateTime)); - return orders.AsExchangeResult>(Exchange, orders.Data.Where(x => x.Status == OrderStatus.Filled || x.Status == OrderStatus.Canceled || x.Status == OrderStatus.Expired).Select(x => new SharedFuturesOrder( + return orders.AsExchangeResult>(Exchange, request.Symbol.ApiType, orders.Data.Where(x => x.Status == OrderStatus.Filled || x.Status == OrderStatus.Canceled || x.Status == OrderStatus.Expired).Select(x => new SharedFuturesOrder( x.Symbol, x.Id.ToString(), ParseOrderType(x.Type), @@ -427,9 +427,9 @@ async Task>> IFuturesOrderRestCli var orders = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol(FormatSymbol), orderId: orderId, ct: ct).ConfigureAwait(false); if (!orders) - return orders.AsExchangeResult>(Exchange, default); + return orders.AsExchangeResult>(Exchange, null, default); - return orders.AsExchangeResult>(Exchange, orders.Data.Select(x => new SharedUserTrade( + return orders.AsExchangeResult>(Exchange, request.Symbol.ApiType, orders.Data.Select(x => new SharedUserTrade( x.Symbol, x.OrderId.ToString(), x.Id.ToString(), @@ -466,14 +466,14 @@ async Task>> IFuturesOrderRestCli ct: ct ).ConfigureAwait(false); if (!orders) - return orders.AsExchangeResult>(Exchange, default); + return orders.AsExchangeResult>(Exchange, null, default); // Get next token FromIdToken? nextToken = null; if (orders.Data.Count() == (request.Limit ?? 500)) nextToken = new FromIdToken(orders.Data.Max(o => o.Id).ToString()); - return orders.AsExchangeResult>(Exchange, orders.Data.Select(x => new SharedUserTrade( + return orders.AsExchangeResult>(Exchange, request.Symbol.ApiType, orders.Data.Select(x => new SharedUserTrade( x.Symbol, x.OrderId.ToString(), x.Id.ToString(), @@ -501,9 +501,9 @@ async Task> IFuturesOrderRestClient.CancelFuturesOrd var order = await Trading.CancelOrderAsync(request.Symbol.GetSymbol(FormatSymbol), orderId, ct: ct).ConfigureAwait(false); if (!order) - return order.AsExchangeResult(Exchange, default); + return order.AsExchangeResult(Exchange, null, default); - return order.AsExchangeResult(Exchange, new SharedId(order.Data.Id.ToString())); + return order.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedId(order.Data.Id.ToString())); } EndpointOptions IFuturesOrderRestClient.GetPositionsOptions { get; } = new EndpointOptions(true); @@ -515,13 +515,13 @@ async Task>> IFuturesOrderRestClie var result = await Account.GetPositionInformationAsync(symbol: request.Symbol?.GetSymbol(FormatSymbol), ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult>(Exchange, default); + return result.AsExchangeResult>(Exchange, null, default); var data = result.Data; if (request.ApiType.HasValue) - data = data.Where(x => request.ApiType == ApiType.DeliveryLinear ? x.Symbol.Contains("_") : !x.Symbol.Contains("_")); + data = data.Where(x => request.ApiType == TradingMode.DeliveryLinear ? x.Symbol.Contains("_") : !x.Symbol.Contains("_")); - return result.AsExchangeResult>(Exchange, data.Select(x => new SharedPosition(x.Symbol, Math.Abs(x.Quantity), x.UpdateTime) + return result.AsExchangeResult>(Exchange, request.Symbol == null ? SupportedApiTypes : new[] { request.Symbol.ApiType }, data.Select(x => new SharedPosition(x.Symbol, Math.Abs(x.Quantity), x.UpdateTime) { UnrealizedPnl = x.UnrealizedPnl, LiquidationPrice = x.LiquidationPrice == 0 ? null: x.LiquidationPrice, @@ -548,7 +548,7 @@ async Task> IFuturesOrderRestClient.ClosePositionAsy var symbol = request.Symbol.GetSymbol(FormatSymbol); var positionMode = await Account.GetPositionModeAsync().ConfigureAwait(false); if (!positionMode) - return positionMode.AsExchangeResult(Exchange, default); + return positionMode.AsExchangeResult(Exchange, null, default); var result = await Trading.PlaceOrderAsync( symbol, @@ -559,9 +559,9 @@ async Task> IFuturesOrderRestClient.ClosePositionAsy reduceOnly: positionMode.Data.IsHedgeMode ? null : true, ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult(Exchange, default); + return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, new SharedId(result.Data.Id.ToString())); + return result.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedId(result.Data.Id.ToString())); } private TimeInForce? GetTimeInForce(SharedOrderType type, SharedTimeInForce? tif) @@ -611,12 +611,12 @@ async Task> ILeverageRestClient.GetLeverageAsy var result = await Account.GetPositionInformationAsync(symbol: request.Symbol.GetSymbol(FormatSymbol), ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult(Exchange, default); + return result.AsExchangeResult(Exchange, null, default); if (!result.Data.Any()) return result.AsExchangeError(Exchange, new ServerError("Not found")); - return result.AsExchangeResult(Exchange, new SharedLeverage(result.Data.First().Leverage) + return result.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedLeverage(result.Data.First().Leverage) { Side = request.Side }); @@ -631,9 +631,9 @@ async Task> ILeverageRestClient.SetLeverageAsy var result = await Account.ChangeInitialLeverageAsync(symbol: request.Symbol.GetSymbol(FormatSymbol), (int)request.Leverage, ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult(Exchange, default); + return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, new SharedLeverage(result.Data.Leverage)); + return result.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedLeverage(result.Data.Leverage)); } #endregion @@ -650,9 +650,9 @@ async Task> IOrderBookRestClient.GetOrderBook limit: request.Limit, ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult(Exchange, default); + return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, new SharedOrderBook(result.Data.Asks, result.Data.Bids)); + return result.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedOrderBook(result.Data.Asks, result.Data.Bids)); } #endregion @@ -679,14 +679,14 @@ async Task>> ITradeHistoryRestClient. fromId: fromId, ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult>(Exchange, default); + return result.AsExchangeResult>(Exchange, null, default); FromIdToken? nextToken = null; if (result.Data.Any() && result.Data.Last().TradeTime < request.EndTime) nextToken = new FromIdToken(result.Data.Max(x => x.Id).ToString()); // Return - return result.AsExchangeResult>(Exchange, 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.ApiType, result.Data.Where(x => x.TradeTime < request.EndTime).Select(x => new SharedTrade(x.Quantity, x.Price, x.TradeTime)).ToArray(), nextToken); } #endregion @@ -733,7 +733,7 @@ async Task>> IIndexPriceKlineRest ct: ct ).ConfigureAwait(false); if (!result) - return result.AsExchangeResult>(Exchange, default); + return result.AsExchangeResult>(Exchange, null, default); // Get next token DateTimeToken? nextToken = null; @@ -744,7 +744,7 @@ async Task>> IIndexPriceKlineRest nextToken = new DateTimeToken(minOpenTime.AddSeconds(-(int)(interval - 1))); } - return result.AsExchangeResult>(Exchange, result.Data.Reverse().Select(x => new SharedMarkKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)).ToArray(), nextToken); + return result.AsExchangeResult>(Exchange, request.Symbol.ApiType, result.Data.Reverse().Select(x => new SharedMarkKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)).ToArray(), nextToken); } #endregion @@ -760,9 +760,9 @@ async Task> IOpenInterestRestClient.GetOpe var result = await ExchangeData.GetOpenInterestAsync(request.Symbol.GetSymbol(FormatSymbol), ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult(Exchange, default); + return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, new SharedOpenInterest(result.Data.OpenInterest)); + return result.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedOpenInterest(result.Data.OpenInterest)); } #endregion @@ -788,14 +788,14 @@ async Task>> IFundingRateRestCl limit: request.Limit ?? 1000, ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult>(Exchange, default); + return result.AsExchangeResult>(Exchange, null, default); DateTimeToken? nextToken = null; if (result.Data.Count() == (request.Limit ?? 1000)) nextToken = new DateTimeToken(result.Data.Max(x => x.FundingTime)); // Return - return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedFundingRate(x.FundingRate, x.FundingTime)).ToArray(), nextToken); + return result.AsExchangeResult>(Exchange, request.Symbol.ApiType, result.Data.Select(x => new SharedFundingRate(x.FundingRate, x.FundingTime)).ToArray(), nextToken); } #endregion @@ -810,9 +810,9 @@ async Task>> IBalanceRestClient.Get var result = await Account.GetBalancesAsync(ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult>(Exchange, default); + return result.AsExchangeResult>(Exchange, null, default); - return result.AsExchangeResult>(Exchange, result.Data.Select(x => new SharedBalance(x.Asset, x.AvailableBalance, x.WalletBalance)).ToArray()); + return result.AsExchangeResult>(Exchange, SupportedApiTypes, result.Data.Select(x => new SharedBalance(x.Asset, x.AvailableBalance, x.WalletBalance)).ToArray()); } #endregion @@ -828,9 +828,9 @@ async Task> IPositionModeRestClient. var result = await Account.GetPositionModeAsync(ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult(Exchange, default); + return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, new SharedPositionModeResult(result.Data.IsHedgeMode ? SharedPositionMode.HedgeMode : SharedPositionMode.OneWay)); + return result.AsExchangeResult(Exchange, SupportedApiTypes, new SharedPositionModeResult(result.Data.IsHedgeMode ? SharedPositionMode.HedgeMode : SharedPositionMode.OneWay)); } SetPositionModeOptions IPositionModeRestClient.SetPositionModeOptions { get; } = new SetPositionModeOptions(true, true, false); @@ -842,9 +842,9 @@ async Task> IPositionModeRestClient. var result = await Account.ModifyPositionModeAsync(request.Mode == SharedPositionMode.HedgeMode, ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult(Exchange, default); + return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, new SharedPositionModeResult(request.Mode)); + return result.AsExchangeResult(Exchange, SupportedApiTypes, new SharedPositionModeResult(request.Mode)); } #endregion @@ -860,9 +860,9 @@ async Task> IListenKeyRestClient.StartListenKeyAsync(S // Get data var result = await Account.StartUserStreamAsync(ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult(Exchange, default); + return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, result.Data); + return result.AsExchangeResult(Exchange, SupportedApiTypes, result.Data); } EndpointOptions IListenKeyRestClient.KeepAliveOptions { get; } = new EndpointOptions(true); async Task> IListenKeyRestClient.KeepAliveListenKeyAsync(KeepAliveListenKeyRequest request, CancellationToken ct) @@ -874,9 +874,9 @@ async Task> IListenKeyRestClient.KeepAliveListenKeyAsy // Get data var result = await Account.KeepAliveUserStreamAsync(request.ListenKey, ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult(Exchange, default); + return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, request.ListenKey); + return result.AsExchangeResult(Exchange, SupportedApiTypes, request.ListenKey); } EndpointOptions IListenKeyRestClient.StopOptions { get; } = new EndpointOptions(true); @@ -889,9 +889,9 @@ async Task> IListenKeyRestClient.StopListenKeyAsync(St // Get data var result = await Account.StopUserStreamAsync(request.ListenKey, ct: ct).ConfigureAwait(false); if (!result) - return result.AsExchangeResult(Exchange, default); + return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, request.ListenKey); + return result.AsExchangeResult(Exchange, SupportedApiTypes, request.ListenKey); } #endregion } diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs index 92e69805f..a8fd94b4e 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs @@ -66,7 +66,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden => new BinanceAuthenticationProvider(credentials); /// - public override string FormatSymbol(string baseAsset, string quoteAsset, ApiType apiType, DateTime? deliverTime = null) + public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode apiType, DateTime? deliverTime = null) { return baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant() + (deliverTime == null ? string.Empty: "_" + deliverTime.Value.ToString("yyMMdd")); } diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs index d65521035..71b10cb2b 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs @@ -19,7 +19,7 @@ namespace Binance.Net.Clients.UsdFuturesApi internal partial class BinanceSocketClientUsdFuturesApi : IBinanceSocketClientUsdFuturesApiShared { public string Exchange => BinanceExchange.ExchangeName; - public ApiType[] SupportedApiTypes => new[] { ApiType.DeliveryLinear, ApiType.PerpetualLinear }; + public TradingMode[] SupportedApiTypes => new[] { TradingMode.DeliveryLinear, TradingMode.PerpetualLinear }; public void SetDefaultExchangeParameter(string key, object value) => ExchangeParameters.SetStaticParameter(Exchange, key, value); public void ResetDefaultExchangeParameters() => ExchangeParameters.ResetStaticParameters(); @@ -54,7 +54,7 @@ async Task> ITickersSocketClient.SubscribeToA { var data = update.Data; if (request.ApiType != null) - data = data.Where(x => request.ApiType == ApiType.PerpetualLinear ? !x.Symbol.Contains("_") : x.Symbol.Contains("_")); + data = data.Where(x => request.ApiType == TradingMode.PerpetualLinear ? !x.Symbol.Contains("_") : x.Symbol.Contains("_")); if (!data.Any()) return; From 389e326bae94fb51a42a1fe3d053fb0514039ba1 Mon Sep 17 00:00:00 2001 From: JKorf Date: Sun, 22 Sep 2024 21:41:05 +0200 Subject: [PATCH 43/54] wip --- Binance.Net/Binance.Net.xml | 69 ++++++- .../BinanceRestClientCoinFuturesApiShared.cs | 177 ++++++++--------- ...BinanceSocketClientCoinFuturesApiShared.cs | 48 ++--- .../SpotApi/BinanceRestClientSpotApiShared.cs | 105 +++++----- .../BinanceSocketClientSpotApiShared.cs | 39 ++-- .../BinanceRestClientUsdFuturesApiShared.cs | 184 +++++++++--------- .../BinanceSocketClientUsdFuturesApiShared.cs | 48 ++--- .../IBinanceRestClientCoinFuturesApi.cs | 7 +- .../IBinanceRestClientCoinFuturesApiShared.cs | 5 +- .../IBinanceSocketClientCoinFuturesApi.cs | 3 + ...BinanceSocketClientCoinFuturesApiShared.cs | 3 + .../SpotApi/IBinanceRestClientSpotApi.cs | 6 +- .../IBinanceRestClientSpotApiShared.cs | 5 +- .../SpotApi/IBinanceSocketClientSpotApi.cs | 3 + .../IBinanceSocketClientSpotApiShared.cs | 4 + .../IBinanceRestClientUsdFuturesApi.cs | 6 +- .../IBinanceRestClientUsdFuturesApiShared.cs | 5 +- .../IBinanceSocketClientUsdFuturesApi.cs | 3 + ...IBinanceSocketClientUsdFuturesApiShared.cs | 3 + .../Models/Spot/BinanceWithdrawalPlaced.cs | 2 +- 20 files changed, 408 insertions(+), 317 deletions(-) diff --git a/Binance.Net/Binance.Net.xml b/Binance.Net/Binance.Net.xml index ae0d06172..bc0da712e 100644 --- a/Binance.Net/Binance.Net.xml +++ b/Binance.Net/Binance.Net.xml @@ -5488,9 +5488,13 @@ - Get the IFuturesClient for this client. This is a common interface which allows for some basic operations without knowing any details of the exchange. + DEPRECATED, use SharedClient instead + + + + + Get the shared rest requests client - @@ -5962,6 +5966,11 @@ Cancellation token List of prices + + + Shared interface for COIN-M Futures rest API usage + + Binance COIN-M futures trading endpoints, placing and mananging orders. @@ -6130,6 +6139,11 @@ Binance Coin futures streams + + + Get the shared socket subscription client + + Subscribes to the aggregated trades update stream for the provided symbol @@ -6520,6 +6534,11 @@ Cancellation token for closing this subscription A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected + + + Shared interface for COIN-M Futures socket API usage + + Binance general API endpoints @@ -8460,9 +8479,13 @@ - Get the ISpotClient for this client. This is a common interface which allows for some basic operations without knowing any details of the exchange. + DEPRECATED, use SharedClient instead + + + + + Get the shared rest requests client - @@ -9726,6 +9749,11 @@ Cancellation token + + + Shared interface for Spot rest API usage + + Binance Spot trading endpoints, placing and mananging orders. @@ -10460,6 +10488,11 @@ Trading data and queries + + + Get the shared socket subscription client + + Binance Spot Account socket requests and subscriptions @@ -10930,6 +10963,11 @@ Cancellation token for closing this subscription A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected + + + Shared interface for Spot socket API usage + + Binance Spot Trading socket requests @@ -11208,9 +11246,13 @@ - Get the IFuturesClient for this client. This is a common interface which allows for some basic operations without knowing any details of the exchange. + DEPRECATED, use SharedClient instead + + + + + Get the shared rest requests client - @@ -11865,6 +11907,11 @@ To asset Cancellation token + + + Shared interface for USD-M Futures rest API usage + + Binance USD-M futures trading endpoints, placing and mananging orders. @@ -12193,6 +12240,11 @@ Binance USD futures streams + + + Get the shared socket subscription client + + Subscribes to the aggregated trades update stream for the provided symbol @@ -12550,6 +12602,11 @@ Cancellation token for closing this subscription + + + Shared interface for USD-M Futures socket API usage + + 24 hour price stats diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs index 0eb92234f..93d16fe24 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -3,13 +3,13 @@ using CryptoExchange.Net.SharedApis.Enums; using CryptoExchange.Net.SharedApis.Interfaces; using CryptoExchange.Net.SharedApis.Models; -using CryptoExchange.Net.SharedApis.Models.FilterOptions; using CryptoExchange.Net.SharedApis.Models.Rest; -using CryptoExchange.Net.SharedApis.RequestModels; using CryptoExchange.Net.SharedApis.ResponseModels; using CryptoExchange.Net.SharedApis.Interfaces.Rest.Futures; using CryptoExchange.Net.SharedApis.Interfaces.Rest.Spot; -using CryptoExchange.Net.SharedApis.Models.EndpointOptions; +using CryptoExchange.Net.SharedApis.Models.Options.Endpoints; +using CryptoExchange.Net.SharedApis.Interfaces.Rest; +using CryptoExchange.Net.SharedApis.Models.Options; namespace Binance.Net.Clients.CoinFuturesApi { @@ -17,14 +17,14 @@ internal partial class BinanceRestClientCoinFuturesApi : IBinanceRestClientCoinF { public string Exchange => BinanceExchange.ExchangeName; - public TradingMode[] SupportedApiTypes => new[] { TradingMode.DeliveryInverse, TradingMode.PerpetualInverse }; + public TradingMode[] SupportedTradingModes => new[] { TradingMode.DeliveryInverse, TradingMode.PerpetualInverse }; public void SetDefaultExchangeParameter(string key, object value) => ExchangeParameters.SetStaticParameter(Exchange, key, value); public void ResetDefaultExchangeParameters() => ExchangeParameters.ResetStaticParameters(); #region Klines client - GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(SharedPaginationType.Descending, false) + GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(SharedPaginationSupport.Descending, false) { MaxRequestDataPoints = 1000 }; @@ -35,7 +35,7 @@ async Task>> IKlineRestClient.GetKlin if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -86,7 +86,7 @@ async Task>> IKlineRestClient.GetKlin EndpointOptions IFuturesSymbolRestClient.GetFuturesSymbolsOptions { get; } = new EndpointOptions(false); async Task>> IFuturesSymbolRestClient.GetFuturesSymbolsAsync(GetSymbolsRequest request, CancellationToken ct) { - var validationError = ((IFuturesSymbolRestClient)this).GetFuturesSymbolsOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((IFuturesSymbolRestClient)this).GetFuturesSymbolsOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -95,9 +95,9 @@ async Task>> IFuturesSymbolRe return result.AsExchangeResult>(Exchange, null, default); var data = result.Data.Symbols.Where(x => x.ContractType != null); - if (request.ApiType != null) - data = data.Where(x => request.ApiType == TradingMode.PerpetualInverse ? x.ContractType == ContractType.Perpetual : (x.ContractType != ContractType.Perpetual && x.ContractType != ContractType.PerpetualDelivering)); - return result.AsExchangeResult>(Exchange, request.ApiType == null ? SupportedApiTypes : new[] { request.ApiType.Value }, data.Select(s => new SharedFuturesSymbol(s.ContractType == ContractType.Perpetual ? SharedSymbolType.PerpetualInverse : SharedSymbolType.DeliveryInverse, s.BaseAsset, s.QuoteAsset, s.Name, s.Status == SymbolStatus.Trading) + if (request.TradingMode != null) + data = data.Where(x => request.TradingMode == TradingMode.PerpetualInverse ? x.ContractType == ContractType.Perpetual : (x.ContractType != ContractType.Perpetual && x.ContractType != ContractType.PerpetualDelivering)); + return result.AsExchangeResult>(Exchange, request.TradingMode == null ? SupportedTradingModes : new[] { request.TradingMode.Value }, data.Select(s => new SharedFuturesSymbol(s.ContractType == ContractType.Perpetual ? SharedSymbolType.PerpetualInverse : SharedSymbolType.DeliveryInverse, s.BaseAsset, s.QuoteAsset, s.Name, s.Status == SymbolStatus.Trading) { MinTradeQuantity = s.LotSizeFilter?.MinQuantity, MaxTradeQuantity = s.LotSizeFilter?.MaxQuantity, @@ -115,7 +115,7 @@ async Task>> IFuturesSymbolRe EndpointOptions IFuturesTickerRestClient.GetFuturesTickerOptions { get; } = new EndpointOptions(false); async Task> IFuturesTickerRestClient.GetFuturesTickerAsync(GetTickerRequest request, CancellationToken ct) { - var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -145,7 +145,7 @@ async Task> IFuturesTickerRestClient.GetF EndpointOptions IFuturesTickerRestClient.GetFuturesTickersOptions { get; } = new EndpointOptions(false); async Task>> IFuturesTickerRestClient.GetFuturesTickersAsync(GetTickersRequest request, CancellationToken ct) { - var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickersOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickersOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -157,7 +157,7 @@ async Task>> IFuturesTickerRe if (!resultMarkPrices.Result) return resultMarkPrices.Result.AsExchangeResult>(Exchange, null, default); - return resultTickers.Result.AsExchangeResult>(Exchange, SupportedApiTypes, resultTickers.Result.Data.Select(x => + return resultTickers.Result.AsExchangeResult>(Exchange, SupportedTradingModes, resultTickers.Result.Data.Select(x => { var markPrice = resultMarkPrices.Result.Data.Single(p => p.Symbol == x.Symbol); return new SharedFuturesTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume, x.PriceChangePercent) @@ -177,7 +177,7 @@ async Task>> IFuturesTickerRe GetRecentTradesOptions IRecentTradeRestClient.GetRecentTradesOptions { get; } = new GetRecentTradesOptions(1000, false); async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, CancellationToken ct) { - var validationError = ((IRecentTradeRestClient)this).GetRecentTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IRecentTradeRestClient)this).GetRecentTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -195,30 +195,28 @@ async Task>> IRecentTradeRestClient.G #region Futures Order Client - PlaceFuturesOrderOptions IFuturesOrderRestClient.PlaceFuturesOrderOptions { get; } = new PlaceFuturesOrderOptions( - new[] - { - SharedOrderType.Limit, - SharedOrderType.Market - }, - new[] - { - SharedTimeInForce.GoodTillCanceled, - SharedTimeInForce.ImmediateOrCancel, - SharedTimeInForce.FillOrKill - }, - new SharedQuantitySupport( - SharedQuantityType.Contracts, - SharedQuantityType.Contracts, - SharedQuantityType.Contracts, - SharedQuantityType.Contracts)); SharedFeeDeductionType IFuturesOrderRestClient.FuturesFeeDeductionType => SharedFeeDeductionType.AddToCost; SharedFeeAssetType IFuturesOrderRestClient.FuturesFeeAssetType => SharedFeeAssetType.BaseAsset; + IEnumerable IFuturesOrderRestClient.FuturesSupportedOrderType { get; } = new[] { SharedOrderType.Limit, SharedOrderType.Market }; + IEnumerable IFuturesOrderRestClient.FuturesSupportedTimeInForce { get; } = new[] { SharedTimeInForce.GoodTillCanceled, SharedTimeInForce.ImmediateOrCancel, SharedTimeInForce.FillOrKill }; + SharedQuantitySupport IFuturesOrderRestClient.FuturesSupportedOrderQuantity { get; } = new SharedQuantitySupport( + SharedQuantityType.Contracts, + SharedQuantityType.Contracts, + SharedQuantityType.Contracts, + SharedQuantityType.Contracts); + PlaceFuturesOrderOptions IFuturesOrderRestClient.PlaceFuturesOrderOptions { get; } = new PlaceFuturesOrderOptions(); async Task> IFuturesOrderRestClient.PlaceFuturesOrderAsync(PlaceFuturesOrderRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).PlaceFuturesOrderOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).PlaceFuturesOrderOptions.ValidateRequest( + Exchange, + request, + request.Symbol.ApiType, + SupportedTradingModes, + ((ISpotOrderRestClient)this).SpotSupportedOrderTypes, + ((ISpotOrderRestClient)this).SpotSupportedTimeInForce, + ((ISpotOrderRestClient)this).SpotSupportedOrderQuantity); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -243,7 +241,7 @@ async Task> IFuturesOrderRestClient.PlaceFuturesOrde EndpointOptions IFuturesOrderRestClient.GetFuturesOrderOptions { get; } = new EndpointOptions(true); async Task> IFuturesOrderRestClient.GetFuturesOrderAsync(GetOrderRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -264,7 +262,7 @@ async Task> IFuturesOrderRestClient.GetFut { ClientOrderId = order.Data.ClientOrderId, AveragePrice = order.Data.AveragePrice == 0 ? null : order.Data.AveragePrice, - Price = order.Data.Price == 0 ? null : order.Data.Price, + OrderPrice = order.Data.Price == 0 ? null : order.Data.Price, Quantity = order.Data.Quantity, QuantityFilled = order.Data.QuantityFilled, QuoteQuantityFilled = order.Data.QuoteQuantityFilled, @@ -278,7 +276,7 @@ async Task> IFuturesOrderRestClient.GetFut EndpointOptions IFuturesOrderRestClient.GetOpenFuturesOrdersOptions { get; } = new EndpointOptions(true); async Task>> IFuturesOrderRestClient.GetOpenFuturesOrdersAsync(GetOpenOrdersRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetOpenFuturesOrdersOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.ApiType!.Value, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetOpenFuturesOrdersOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.TradingMode!.Value, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -287,7 +285,7 @@ async Task>> IFuturesOrderRest if (!orders) return orders.AsExchangeResult>(Exchange, null, default); - return orders.AsExchangeResult>(Exchange, SupportedApiTypes, orders.Data.Select(x => new SharedFuturesOrder( + return orders.AsExchangeResult>(Exchange, SupportedTradingModes, orders.Data.Select(x => new SharedFuturesOrder( x.Symbol, x.Id.ToString(), ParseOrderType(x.Type), @@ -297,7 +295,7 @@ async Task>> IFuturesOrderRest { ClientOrderId = x.ClientOrderId, AveragePrice = x.AveragePrice == 0 ? null : x.AveragePrice, - Price = x.Price == 0 ? null : x.Price, + OrderPrice = x.Price == 0 ? null : x.Price, Quantity = x.Quantity, QuantityFilled = x.QuantityFilled, QuoteQuantityFilled = x.QuoteQuantityFilled, @@ -308,10 +306,10 @@ async Task>> IFuturesOrderRest }).ToArray()); } - PaginatedEndpointOptions IFuturesOrderRestClient.GetClosedFuturesOrdersOptions { get; } = new PaginatedEndpointOptions(SharedPaginationType.Descending, true); + PaginatedEndpointOptions IFuturesOrderRestClient.GetClosedFuturesOrdersOptions { get; } = new PaginatedEndpointOptions(SharedPaginationSupport.Descending, true); async Task>> IFuturesOrderRestClient.GetClosedFuturesOrdersAsync(GetClosedOrdersRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetClosedFuturesOrdersOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetClosedFuturesOrdersOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -334,7 +332,7 @@ async Task>> IFuturesOrderRest if (orders.Data.Count() == (request.Limit ?? 100)) nextToken = new DateTimeToken(orders.Data.Min(o => o.CreateTime).AddMilliseconds(-1)); - return orders.AsExchangeResult>(Exchange, SupportedApiTypes, orders.Data.Where(x => x.Status == OrderStatus.Filled || x.Status == OrderStatus.Canceled || x.Status == OrderStatus.Expired).Select(x => new SharedFuturesOrder( + return orders.AsExchangeResult>(Exchange, SupportedTradingModes, orders.Data.Where(x => x.Status == OrderStatus.Filled || x.Status == OrderStatus.Canceled || x.Status == OrderStatus.Expired).Select(x => new SharedFuturesOrder( x.Symbol, x.Id.ToString(), ParseOrderType(x.Type), @@ -344,7 +342,7 @@ async Task>> IFuturesOrderRest { ClientOrderId = x.ClientOrderId, AveragePrice = x.AveragePrice == 0 ? null : x.AveragePrice, - Price = x.Price == 0 ? null : x.Price, + OrderPrice = x.Price == 0 ? null : x.Price, Quantity = x.Quantity, QuantityFilled = x.QuantityFilled, QuoteQuantityFilled = x.QuoteQuantityFilled, @@ -358,7 +356,7 @@ async Task>> IFuturesOrderRest EndpointOptions IFuturesOrderRestClient.GetFuturesOrderTradesOptions { get; } = new EndpointOptions(true); async Task>> IFuturesOrderRestClient.GetFuturesOrderTradesAsync(GetOrderTradesRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -385,10 +383,10 @@ async Task>> IFuturesOrderRestCli }).ToArray()); } - PaginatedEndpointOptions IFuturesOrderRestClient.GetFuturesUserTradesOptions { get; } = new PaginatedEndpointOptions(SharedPaginationType.Descending, true); + PaginatedEndpointOptions IFuturesOrderRestClient.GetFuturesUserTradesOptions { get; } = new PaginatedEndpointOptions(SharedPaginationSupport.Descending, true); async Task>> IFuturesOrderRestClient.GetFuturesUserTradesAsync(GetUserTradesRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetFuturesUserTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetFuturesUserTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -432,7 +430,7 @@ async Task>> IFuturesOrderRestCli EndpointOptions IFuturesOrderRestClient.CancelFuturesOrderOptions { get; } = new EndpointOptions(true); async Task> IFuturesOrderRestClient.CancelFuturesOrderAsync(CancelOrderRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).CancelFuturesOrderOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).CancelFuturesOrderOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -449,7 +447,7 @@ async Task> IFuturesOrderRestClient.CancelFuturesOrd EndpointOptions IFuturesOrderRestClient.GetPositionsOptions { get; } = new EndpointOptions(true); async Task>> IFuturesOrderRestClient.GetPositionsAsync(GetPositionsRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetPositionsOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetPositionsOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -458,12 +456,12 @@ async Task>> IFuturesOrderRestClie if (!result) return result.AsExchangeResult>(Exchange, null, default); - return result.AsExchangeResult>(Exchange, request.Symbol == null ? SupportedApiTypes : new[] { request.Symbol.ApiType }, result.Data.Select(x => new SharedPosition(x.Symbol, Math.Abs(x.Quantity), x.UpdateTime) + return result.AsExchangeResult>(Exchange, request.Symbol == null ? SupportedTradingModes : new[] { request.Symbol.ApiType }, result.Data.Select(x => new SharedPosition(x.Symbol, Math.Abs(x.Quantity), x.UpdateTime) { UnrealizedPnl = x.UnrealizedPnl, LiquidationPrice = x.LiquidationPrice == 0 ? null : x.LiquidationPrice, Leverage = x.Leverage, - AverageEntryPrice = x.EntryPrice, + AverageOpenPrice = x.EntryPrice, PositionSide = x.PositionSide == PositionSide.Both ? (x.Quantity >= 0 ? SharedPositionSide.Long : SharedPositionSide.Short) : x.PositionSide == PositionSide.Short ? SharedPositionSide.Short : SharedPositionSide.Long }).ToArray()); } @@ -478,7 +476,7 @@ async Task>> IFuturesOrderRestClie }; async Task> IFuturesOrderRestClient.ClosePositionAsync(ClosePositionRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).ClosePositionOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).ClosePositionOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -538,11 +536,12 @@ private SharedOrderType ParseOrderType(FuturesOrderType type) #endregion #region Leverage client + SharedLeverageSettingMode ILeverageRestClient.LeverageSettingType => SharedLeverageSettingMode.PerSymbol; EndpointOptions ILeverageRestClient.GetLeverageOptions { get; } = new EndpointOptions(true); async Task> ILeverageRestClient.GetLeverageAsync(GetLeverageRequest request, CancellationToken ct) { - var validationError = ((ILeverageRestClient)this).GetLeverageOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ILeverageRestClient)this).GetLeverageOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -557,14 +556,14 @@ async Task> ILeverageRestClient.GetLeverageAsy var data = result.Data.Where(x => x.Symbol == symbol).ToList(); return result.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedLeverage(data.First().Leverage) { - Side = request.Side + Side = request.PositionSide }); } - SetLeverageOptions ILeverageRestClient.SetLeverageOptions { get; } = new SetLeverageOptions(true); + SetLeverageOptions ILeverageRestClient.SetLeverageOptions { get; } = new SetLeverageOptions(); async Task> ILeverageRestClient.SetLeverageAsync(SetLeverageRequest request, CancellationToken ct) { - var validationError = ((ILeverageRestClient)this).SetLeverageOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ILeverageRestClient)this).SetLeverageOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -578,20 +577,20 @@ async Task> ILeverageRestClient.SetLeverageAsy #region Mark Klines client - GetKlinesOptions IMarkPriceKlineRestClient.GetMarkPriceKlinesOptions { get; } = new GetKlinesOptions(SharedPaginationType.Descending, false) + GetKlinesOptions IMarkPriceKlineRestClient.GetMarkPriceKlinesOptions { get; } = new GetKlinesOptions(SharedPaginationSupport.Descending, false) { MaxRequestDataPoints = 1000 }; - async Task>> IMarkPriceKlineRestClient.GetMarkPriceKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, CancellationToken ct) + async Task>> IMarkPriceKlineRestClient.GetMarkPriceKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, CancellationToken ct) { var interval = (Enums.KlineInterval)request.Interval; if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) - return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); + return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IMarkPriceKlineRestClient)this).GetMarkPriceKlinesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IMarkPriceKlineRestClient)this).GetMarkPriceKlinesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) - return new ExchangeWebResult>(Exchange, validationError); + return new ExchangeWebResult>(Exchange, validationError); // Determine pagination // Data is normally returned oldest first, so to do newest first pagination we have to do some calc @@ -619,7 +618,7 @@ async Task>> IMarkPriceKlineRestC ct: ct ).ConfigureAwait(false); if (!result) - return result.AsExchangeResult>(Exchange, null, default); + return result.AsExchangeResult>(Exchange, null, default); // Get next token DateTimeToken? nextToken = null; @@ -630,7 +629,7 @@ async Task>> IMarkPriceKlineRestC nextToken = new DateTimeToken(minOpenTime.AddSeconds(-(int)(interval - 1))); } - return result.AsExchangeResult>(Exchange, request.Symbol.ApiType, result.Data.Reverse().Select(x => new SharedMarkKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)).ToArray(), nextToken); + return result.AsExchangeResult>(Exchange, request.Symbol.ApiType, result.Data.Reverse().Select(x => new SharedFuturesKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)).ToArray(), nextToken); } #endregion @@ -639,7 +638,7 @@ async Task>> IMarkPriceKlineRestC GetOrderBookOptions IOrderBookRestClient.GetOrderBookOptions { get; } = new GetOrderBookOptions(new[] { 5, 10, 20, 50, 100, 500, 1000 }, false); async Task> IOrderBookRestClient.GetOrderBookAsync(GetOrderBookRequest request, CancellationToken ct) { - var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -656,11 +655,11 @@ async Task> IOrderBookRestClient.GetOrderBook #endregion #region Trade History client - GetTradeHistoryOptions ITradeHistoryRestClient.GetTradeHistoryOptions { get; } = new GetTradeHistoryOptions(SharedPaginationType.Ascending, false); + GetTradeHistoryOptions ITradeHistoryRestClient.GetTradeHistoryOptions { get; } = new GetTradeHistoryOptions(SharedPaginationSupport.Ascending, false); async Task>> ITradeHistoryRestClient.GetTradeHistoryAsync(GetTradeHistoryRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((ITradeHistoryRestClient)this).GetTradeHistoryOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ITradeHistoryRestClient)this).GetTradeHistoryOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -690,20 +689,20 @@ async Task>> ITradeHistoryRestClient. #region Index Klines client - GetKlinesOptions IIndexPriceKlineRestClient.GetIndexPriceKlinesOptions { get; } = new GetKlinesOptions(SharedPaginationType.Descending, false) + GetKlinesOptions IIndexPriceKlineRestClient.GetIndexPriceKlinesOptions { get; } = new GetKlinesOptions(SharedPaginationSupport.Descending, false) { MaxRequestDataPoints = 1000 }; - async Task>> IIndexPriceKlineRestClient.GetIndexPriceKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, CancellationToken ct) + async Task>> IIndexPriceKlineRestClient.GetIndexPriceKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, CancellationToken ct) { var interval = (Enums.KlineInterval)request.Interval; if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) - return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); + return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IIndexPriceKlineRestClient)this).GetIndexPriceKlinesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IIndexPriceKlineRestClient)this).GetIndexPriceKlinesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) - return new ExchangeWebResult>(Exchange, validationError); + return new ExchangeWebResult>(Exchange, validationError); // Determine pagination // Data is normally returned oldest first, so to do newest first pagination we have to do some calc @@ -731,7 +730,7 @@ async Task>> IIndexPriceKlineRest ct: ct ).ConfigureAwait(false); if (!result) - return result.AsExchangeResult>(Exchange, null, default); + return result.AsExchangeResult>(Exchange, null, default); // Get next token DateTimeToken? nextToken = null; @@ -742,7 +741,7 @@ async Task>> IIndexPriceKlineRest nextToken = new DateTimeToken(minOpenTime.AddSeconds(-(int)(interval - 1))); } - return result.AsExchangeResult>(Exchange, request.Symbol.ApiType, result.Data.Reverse().Select(x => new SharedMarkKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)).ToArray(), nextToken); + return result.AsExchangeResult>(Exchange, request.Symbol.ApiType, result.Data.Reverse().Select(x => new SharedFuturesKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)).ToArray(), nextToken); } #endregion @@ -752,7 +751,7 @@ async Task>> IIndexPriceKlineRest EndpointOptions IOpenInterestRestClient.GetOpenInterestOptions { get; } = new EndpointOptions(false); async Task> IOpenInterestRestClient.GetOpenInterestAsync(GetOpenInterestRequest request, CancellationToken ct) { - var validationError = ((IOpenInterestRestClient)this).GetOpenInterestOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IOpenInterestRestClient)this).GetOpenInterestOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -766,11 +765,11 @@ async Task> IOpenInterestRestClient.GetOpe #endregion #region Funding Rate client - GetFundingRateHistoryOptions IFundingRateRestClient.GetFundingRateHistoryOptions { get; } = new GetFundingRateHistoryOptions(SharedPaginationType.Ascending, false); + GetFundingRateHistoryOptions IFundingRateRestClient.GetFundingRateHistoryOptions { get; } = new GetFundingRateHistoryOptions(SharedPaginationSupport.Ascending, false); async Task>> IFundingRateRestClient.GetFundingRateHistoryAsync(GetFundingRateHistoryRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((IFundingRateRestClient)this).GetFundingRateHistoryOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFundingRateRestClient)this).GetFundingRateHistoryOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -802,7 +801,7 @@ async Task>> IFundingRateRestCl async Task>> IBalanceRestClient.GetBalancesAsync(GetBalancesRequest request, CancellationToken ct) { - var validationError = ((IBalanceRestClient)this).GetBalancesOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((IBalanceRestClient)this).GetBalancesOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -810,17 +809,19 @@ async Task>> IBalanceRestClient.Get if (!result) return result.AsExchangeResult>(Exchange, null, default); - return result.AsExchangeResult>(Exchange, SupportedApiTypes, result.Data.Select(x => new SharedBalance(x.Asset, x.AvailableBalance, x.WalletBalance)).ToArray()); + return result.AsExchangeResult>(Exchange, SupportedTradingModes, result.Data.Select(x => new SharedBalance(x.Asset, x.AvailableBalance, x.WalletBalance)).ToArray()); } #endregion #region Position Mode client - GetPositionModeOptions IPositionModeRestClient.GetPositionModeOptions { get; } = new GetPositionModeOptions(false); + SharedPositionModeSelection IPositionModeRestClient.PositionModeSettingType => SharedPositionModeSelection.PerAccount; + + GetPositionModeOptions IPositionModeRestClient.GetPositionModeOptions { get; } = new GetPositionModeOptions(); async Task> IPositionModeRestClient.GetPositionModeAsync(GetPositionModeRequest request, CancellationToken ct) { - var validationError = ((IPositionModeRestClient)this).GetPositionModeOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.ApiType, SupportedApiTypes); + var validationError = ((IPositionModeRestClient)this).GetPositionModeOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -828,21 +829,21 @@ async Task> IPositionModeRestClient. if (!result) return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, SupportedApiTypes, new SharedPositionModeResult(result.Data.IsHedgeMode ? SharedPositionMode.HedgeMode : SharedPositionMode.OneWay)); + return result.AsExchangeResult(Exchange, SupportedTradingModes, new SharedPositionModeResult(result.Data.IsHedgeMode ? SharedPositionMode.HedgeMode : SharedPositionMode.OneWay)); } - SetPositionModeOptions IPositionModeRestClient.SetPositionModeOptions { get; } = new SetPositionModeOptions(true, true, false); + SetPositionModeOptions IPositionModeRestClient.SetPositionModeOptions { get; } = new SetPositionModeOptions(); async Task> IPositionModeRestClient.SetPositionModeAsync(SetPositionModeRequest request, CancellationToken ct) { - var validationError = ((IPositionModeRestClient)this).SetPositionModeOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.ApiType, SupportedApiTypes); + var validationError = ((IPositionModeRestClient)this).SetPositionModeOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var result = await Account.ModifyPositionModeAsync(request.Mode == SharedPositionMode.HedgeMode, ct: ct).ConfigureAwait(false); + var result = await Account.ModifyPositionModeAsync(request.PositionMode == SharedPositionMode.HedgeMode, ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, SupportedApiTypes, new SharedPositionModeResult(request.Mode)); + return result.AsExchangeResult(Exchange, SupportedTradingModes, new SharedPositionModeResult(request.PositionMode)); } #endregion @@ -851,7 +852,7 @@ async Task> IPositionModeRestClient. EndpointOptions IListenKeyRestClient.StartOptions { get; } = new EndpointOptions(true); async Task> IListenKeyRestClient.StartListenKeyAsync(StartListenKeyRequest request, CancellationToken ct) { - var validationError = ((IListenKeyRestClient)this).StartOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((IListenKeyRestClient)this).StartOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -860,12 +861,12 @@ async Task> IListenKeyRestClient.StartListenKeyAsync(S if (!result) return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, SupportedApiTypes, result.Data); + return result.AsExchangeResult(Exchange, SupportedTradingModes, result.Data); } EndpointOptions IListenKeyRestClient.KeepAliveOptions { get; } = new EndpointOptions(true); async Task> IListenKeyRestClient.KeepAliveListenKeyAsync(KeepAliveListenKeyRequest request, CancellationToken ct) { - var validationError = ((IListenKeyRestClient)this).KeepAliveOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((IListenKeyRestClient)this).KeepAliveOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -874,13 +875,13 @@ async Task> IListenKeyRestClient.KeepAliveListenKeyAsy if (!result) return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, SupportedApiTypes, request.ListenKey); + return result.AsExchangeResult(Exchange, SupportedTradingModes, request.ListenKey); } EndpointOptions IListenKeyRestClient.StopOptions { get; } = new EndpointOptions(true); async Task> IListenKeyRestClient.StopListenKeyAsync(StopListenKeyRequest request, CancellationToken ct) { - var validationError = ((IListenKeyRestClient)this).StopOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((IListenKeyRestClient)this).StopOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -889,7 +890,7 @@ async Task> IListenKeyRestClient.StopListenKeyAsync(St if (!result) return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, SupportedApiTypes, request.ListenKey); + return result.AsExchangeResult(Exchange, SupportedTradingModes, request.ListenKey); } #endregion } diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs index 98051482b..aa7a8a607 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs @@ -5,11 +5,11 @@ using CryptoExchange.Net.SharedApis.Interfaces.Socket; using CryptoExchange.Net.SharedApis.Interfaces.Socket.Futures; using CryptoExchange.Net.SharedApis.Models; -using CryptoExchange.Net.SharedApis.Models.FilterOptions; +using CryptoExchange.Net.SharedApis.Models.Options; +using CryptoExchange.Net.SharedApis.Models.Options.Endpoints; +using CryptoExchange.Net.SharedApis.Models.Options.Subscriptions; using CryptoExchange.Net.SharedApis.Models.Socket; -using CryptoExchange.Net.SharedApis.RequestModels; using CryptoExchange.Net.SharedApis.ResponseModels; -using CryptoExchange.Net.SharedApis.SubscribeModels; using System; using System.Collections.Generic; using System.Text; @@ -19,17 +19,17 @@ namespace Binance.Net.Clients.CoinFuturesApi internal partial class BinanceSocketClientCoinFuturesApi : IBinanceSocketClientCoinFuturesApiShared { public string Exchange => BinanceExchange.ExchangeName; - public TradingMode[] SupportedApiTypes => new[] { TradingMode.DeliveryInverse, TradingMode.PerpetualInverse }; + public TradingMode[] SupportedTradingModes => new[] { TradingMode.DeliveryInverse, TradingMode.PerpetualInverse }; public void SetDefaultExchangeParameter(string key, object value) => ExchangeParameters.SetStaticParameter(Exchange, key, value); public void ResetDefaultExchangeParameters() => ExchangeParameters.ResetStaticParameters(); #region Ticker client - SubscriptionOptions ITickerSocketClient.SubscribeTickerOptions { get; } = new SubscriptionOptions(false); + EndpointOptions ITickerSocketClient.SubscribeTickerOptions { get; } = new EndpointOptions(false); async Task> ITickerSocketClient.SubscribeToTickerUpdatesAsync(SubscribeTickerRequest request, Action> handler, CancellationToken ct) { - var validationError = ((ITickerSocketClient)this).SubscribeTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ITickerSocketClient)this).SubscribeTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -43,18 +43,18 @@ async Task> ITickerSocketClient.SubscribeToTi #region Tickers client - SubscriptionOptions ITickersSocketClient.SubscribeAllTickersOptions { get; } = new SubscriptionOptions(false); + EndpointOptions ITickersSocketClient.SubscribeAllTickersOptions { get; } = new EndpointOptions(false); async Task> ITickersSocketClient.SubscribeToAllTickersUpdatesAsync(SubscribeAllTickersRequest request, Action>> handler, CancellationToken ct) { - var validationError = ((ITickersSocketClient)this).SubscribeAllTickersOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((ITickersSocketClient)this).SubscribeAllTickersOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); var result = await SubscribeToAllTickerUpdatesAsync(update => { var data = update.Data; - if (request.ApiType != null) - data = update.Data.Where(x => request.ApiType == TradingMode.PerpetualInverse ? x.Symbol.EndsWith("_PERP") : !x.Symbol.Contains("_PERP")); + if (request.TradingMode != null) + data = update.Data.Where(x => request.TradingMode == TradingMode.PerpetualInverse ? x.Symbol.EndsWith("_PERP") : !x.Symbol.Contains("_PERP")); if (!data.Any()) return; @@ -69,10 +69,10 @@ async Task> ITickersSocketClient.SubscribeToA #region Trade client - SubscriptionOptions ITradeSocketClient.SubscribeTradeOptions { get; } = new SubscriptionOptions(false); + EndpointOptions ITradeSocketClient.SubscribeTradeOptions { get; } = new EndpointOptions(false); async Task> ITradeSocketClient.SubscribeToTradeUpdatesAsync(SubscribeTradeRequest request, Action>> handler, CancellationToken ct) { - var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -86,10 +86,10 @@ async Task> ITradeSocketClient.SubscribeToTra #region Book Ticker client - SubscriptionOptions IBookTickerSocketClient.SubscribeBookTickerOptions { get; } = new SubscriptionOptions(false); + EndpointOptions IBookTickerSocketClient.SubscribeBookTickerOptions { get; } = new EndpointOptions(false); async Task> IBookTickerSocketClient.SubscribeToBookTickerUpdatesAsync(SubscribeBookTickerRequest request, Action> handler, CancellationToken ct) { - var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -109,7 +109,7 @@ async Task> IKlineSocketClient.SubscribeToKli if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeResult(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -124,7 +124,7 @@ async Task> IKlineSocketClient.SubscribeToKli SubscribeOrderBookOptions IOrderBookSocketClient.SubscribeOrderBookOptions { get; } = new SubscribeOrderBookOptions(false, new[] { 5, 10, 20 }); async Task> IOrderBookSocketClient.SubscribeToOrderBookUpdatesAsync(SubscribeOrderBookRequest request, Action> handler, CancellationToken ct) { - var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -136,7 +136,7 @@ async Task> IOrderBookSocketClient.SubscribeT #endregion #region Balance client - SubscriptionOptions IBalanceSocketClient.SubscribeBalanceOptions { get; } = new SubscriptionOptions(false) + EndpointOptions IBalanceSocketClient.SubscribeBalanceOptions { get; } = new EndpointOptions(false) { RequiredOptionalParameters = new List { @@ -145,7 +145,7 @@ async Task> IOrderBookSocketClient.SubscribeT }; async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(SubscribeBalancesRequest request, Action>> handler, CancellationToken ct) { - var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -159,7 +159,7 @@ async Task> IBalanceSocketClient.SubscribeToB #endregion #region Position client - SubscriptionOptions IPositionSocketClient.SubscribePositionOptions { get; } = new SubscriptionOptions(false) + EndpointOptions IPositionSocketClient.SubscribePositionOptions { get; } = new EndpointOptions(false) { RequiredOptionalParameters = new List { @@ -168,14 +168,14 @@ async Task> IBalanceSocketClient.SubscribeToB }; async Task> IPositionSocketClient.SubscribeToPositionUpdatesAsync(SubscribePositionRequest request, Action>> handler, CancellationToken ct) { - var validationError = ((IPositionSocketClient)this).SubscribePositionOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((IPositionSocketClient)this).SubscribePositionOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); var result = await SubscribeToUserDataUpdatesAsync(request.ListenKey!, onAccountUpdate: update => handler(update.AsExchangeEvent>(Exchange, update.Data.UpdateData.Positions.Select(x => new SharedPosition(x.Symbol, x.Quantity, update.Data.EventTime) { - AverageEntryPrice = x.EntryPrice, + AverageOpenPrice = x.EntryPrice, PositionSide = x.PositionSide == Enums.PositionSide.Both ? (x.Quantity >= 0 ? SharedPositionSide.Long : SharedPositionSide.Short) : x.PositionSide == Enums.PositionSide.Short ? SharedPositionSide.Short : SharedPositionSide.Long, UnrealizedPnl = x.UnrealizedPnl }).ToArray())), @@ -188,7 +188,7 @@ async Task> IPositionSocketClient.SubscribeTo #region Futures Order client - SubscriptionOptions IFuturesOrderSocketClient.SubscribeFuturesOrderOptions { get; } = new SubscriptionOptions(false) + EndpointOptions IFuturesOrderSocketClient.SubscribeFuturesOrderOptions { get; } = new EndpointOptions(false) { RequiredOptionalParameters = new List { @@ -198,7 +198,7 @@ async Task> IPositionSocketClient.SubscribeTo async Task> IFuturesOrderSocketClient.SubscribeToFuturesOrderUpdatesAsync(SubscribeFuturesOrderRequest request, Action>> handler, CancellationToken ct) { - var validationError = ((IFuturesOrderSocketClient)this).SubscribeFuturesOrderOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderSocketClient)this).SubscribeFuturesOrderOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -213,7 +213,7 @@ async Task> IFuturesOrderSocketClient.Subscri update.Data.UpdateData.UpdateTime) { ClientOrderId = update.Data.UpdateData.ClientOrderId, - Price = update.Data.UpdateData.Price, + OrderPrice = update.Data.UpdateData.Price, Quantity = update.Data.UpdateData.Quantity, QuantityFilled = update.Data.UpdateData.AccumulatedQuantityOfFilledTrades, UpdateTime = update.Data.UpdateData.UpdateTime, diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index 110e85148..7ca8d0f87 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -2,27 +2,27 @@ using CryptoExchange.Net.SharedApis.Enums; using CryptoExchange.Net.SharedApis.Interfaces; using CryptoExchange.Net.SharedApis.Models.Rest; -using CryptoExchange.Net.SharedApis.RequestModels; using CryptoExchange.Net.SharedApis.ResponseModels; using Binance.Net.Enums; -using CryptoExchange.Net.SharedApis.Models.FilterOptions; using CryptoExchange.Net.SharedApis.Models; using CryptoExchange.Net.SharedApis.Interfaces.Rest.Spot; using CryptoExchange.Net.SharedApis; +using CryptoExchange.Net.SharedApis.Models.Options.Endpoints; +using CryptoExchange.Net.SharedApis.Interfaces.Rest; namespace Binance.Net.Clients.SpotApi { internal partial class BinanceRestClientSpotApi : IBinanceRestClientSpotApiShared { public string Exchange => BinanceExchange.ExchangeName; - public TradingMode[] SupportedApiTypes => new[] { TradingMode.Spot }; + public TradingMode[] SupportedTradingModes => new[] { TradingMode.Spot }; public void SetDefaultExchangeParameter(string key, object value) => ExchangeParameters.SetStaticParameter(Exchange, key, value); public void ResetDefaultExchangeParameters() => ExchangeParameters.ResetStaticParameters(); #region Klines Client - GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(SharedPaginationType.Descending, false) + GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(SharedPaginationSupport.Descending, false) { MaxRequestDataPoints = 1000 }; @@ -33,7 +33,7 @@ async Task>> IKlineRestClient.GetKlin if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -85,7 +85,7 @@ async Task>> IKlineRestClient.GetKlin async Task>> ISpotSymbolRestClient.GetSpotSymbolsAsync(GetSymbolsRequest request, CancellationToken ct) { - var validationError = ((ISpotSymbolRestClient)this).GetSpotSymbolsOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedApiTypes); + var validationError = ((ISpotSymbolRestClient)this).GetSpotSymbolsOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -110,7 +110,7 @@ async Task>> ISpotSymbolRestClie EndpointOptions ISpotTickerRestClient.GetSpotTickerOptions { get; } = new EndpointOptions(false); async Task> ISpotTickerRestClient.GetSpotTickerAsync(GetTickerRequest request, CancellationToken ct) { - var validationError = ((ISpotTickerRestClient)this).GetSpotTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ISpotTickerRestClient)this).GetSpotTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -124,7 +124,7 @@ async Task> ISpotTickerRestClient.GetSpotTic EndpointOptions ISpotTickerRestClient.GetSpotTickersOptions { get; } = new EndpointOptions(false); async Task>> ISpotTickerRestClient.GetSpotTickersAsync(GetTickersRequest request, CancellationToken ct) { - var validationError = ((ISpotTickerRestClient)this).GetSpotTickersOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedApiTypes); + var validationError = ((ISpotTickerRestClient)this).GetSpotTickersOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -142,7 +142,7 @@ async Task>> ISpotTickerRestClie async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, CancellationToken ct) { - var validationError = ((IRecentTradeRestClient)this).GetRecentTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IRecentTradeRestClient)this).GetRecentTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -160,11 +160,11 @@ async Task>> IRecentTradeRestClient.G #endregion #region Trade History client - GetTradeHistoryOptions ITradeHistoryRestClient.GetTradeHistoryOptions { get; } = new GetTradeHistoryOptions(SharedPaginationType.Ascending, false); + GetTradeHistoryOptions ITradeHistoryRestClient.GetTradeHistoryOptions { get; } = new GetTradeHistoryOptions(SharedPaginationSupport.Ascending, false); async Task>> ITradeHistoryRestClient.GetTradeHistoryAsync(GetTradeHistoryRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((ITradeHistoryRestClient)this).GetTradeHistoryOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ITradeHistoryRestClient)this).GetTradeHistoryOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -196,7 +196,7 @@ async Task>> ITradeHistoryRestClient. GetOrderBookOptions IOrderBookRestClient.GetOrderBookOptions { get; } = new GetOrderBookOptions(1, 5000, false); async Task> IOrderBookRestClient.GetOrderBookAsync(GetOrderBookRequest request, CancellationToken ct) { - var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -217,7 +217,7 @@ async Task> IOrderBookRestClient.GetOrderBook async Task>> IBalanceRestClient.GetBalancesAsync(GetBalancesRequest request, CancellationToken ct) { - var validationError = ((IBalanceRestClient)this).GetBalancesOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((IBalanceRestClient)this).GetBalancesOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -232,31 +232,28 @@ async Task>> IBalanceRestClient.Get #region Spot Order Client - PlaceSpotOrderOptions ISpotOrderRestClient.PlaceSpotOrderOptions { get; } = new PlaceSpotOrderOptions( - new[] - { - SharedOrderType.Limit, - SharedOrderType.Market, - SharedOrderType.LimitMaker - }, - new[] - { - SharedTimeInForce.GoodTillCanceled, - SharedTimeInForce.ImmediateOrCancel, - SharedTimeInForce.FillOrKill - }, - new SharedQuantitySupport( - SharedQuantityType.BaseAsset, - SharedQuantityType.BaseAsset, - SharedQuantityType.BaseAndQuoteAsset, - SharedQuantityType.BaseAndQuoteAsset)); SharedFeeDeductionType ISpotOrderRestClient.SpotFeeDeductionType => SharedFeeDeductionType.DeductFromOutput; SharedFeeAssetType ISpotOrderRestClient.SpotFeeAssetType => SharedFeeAssetType.OutputAsset; + IEnumerable ISpotOrderRestClient.SpotSupportedOrderTypes { get; } = new[] { SharedOrderType.Limit, SharedOrderType.Market, SharedOrderType.LimitMaker }; + IEnumerable ISpotOrderRestClient.SpotSupportedTimeInForce { get; } = new[] { SharedTimeInForce.GoodTillCanceled, SharedTimeInForce.ImmediateOrCancel, SharedTimeInForce.FillOrKill }; + SharedQuantitySupport ISpotOrderRestClient.SpotSupportedOrderQuantity { get; } = new SharedQuantitySupport( + SharedQuantityType.BaseAsset, + SharedQuantityType.BaseAsset, + SharedQuantityType.BaseAndQuoteAsset, + SharedQuantityType.BaseAndQuoteAsset); + PlaceSpotOrderOptions ISpotOrderRestClient.PlaceSpotOrderOptions { get; } = new PlaceSpotOrderOptions(); async Task> ISpotOrderRestClient.PlaceSpotOrderAsync(PlaceSpotOrderRequest request, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).PlaceSpotOrderOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ISpotOrderRestClient)this).PlaceSpotOrderOptions.ValidateRequest( + Exchange, + request, + request.Symbol.ApiType, + SupportedTradingModes, + ((ISpotOrderRestClient)this).SpotSupportedOrderTypes, + ((ISpotOrderRestClient)this).SpotSupportedTimeInForce, + ((ISpotOrderRestClient)this).SpotSupportedOrderQuantity); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -280,7 +277,7 @@ async Task> ISpotOrderRestClient.PlaceSpotOrderAsync EndpointOptions ISpotOrderRestClient.GetSpotOrderOptions { get; } = new EndpointOptions(true); async Task> ISpotOrderRestClient.GetSpotOrderAsync(GetOrderRequest request, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetSpotOrderOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ISpotOrderRestClient)this).GetSpotOrderOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -301,7 +298,7 @@ async Task> ISpotOrderRestClient.GetSpotOrder { ClientOrderId = order.Data.ClientOrderId, AveragePrice = order.Data.AverageFillPrice, - Price = order.Data.Price, + OrderPrice = order.Data.Price, Quantity = order.Data.Quantity, QuantityFilled = order.Data.QuantityFilled, QuoteQuantity = order.Data.QuoteQuantity, @@ -314,7 +311,7 @@ async Task> ISpotOrderRestClient.GetSpotOrder EndpointOptions ISpotOrderRestClient.GetOpenSpotOrdersOptions { get; } = new EndpointOptions(true); async Task>> ISpotOrderRestClient.GetOpenSpotOrdersAsync(GetOpenOrdersRequest request, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetOpenSpotOrdersOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.ApiType!.Value, SupportedApiTypes); + var validationError = ((ISpotOrderRestClient)this).GetOpenSpotOrdersOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.TradingMode!.Value, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -333,7 +330,7 @@ async Task>> ISpotOrderRestClient { ClientOrderId = x.ClientOrderId, AveragePrice = x.AverageFillPrice, - Price = x.Price, + OrderPrice = x.Price, Quantity = x.Quantity, QuantityFilled = x.QuantityFilled, QuoteQuantity = x.QuoteQuantity, @@ -343,10 +340,10 @@ async Task>> ISpotOrderRestClient }).ToArray()); } - PaginatedEndpointOptions ISpotOrderRestClient.GetClosedSpotOrdersOptions { get; } = new PaginatedEndpointOptions(SharedPaginationType.Ascending, true); + PaginatedEndpointOptions ISpotOrderRestClient.GetClosedSpotOrdersOptions { get; } = new PaginatedEndpointOptions(SharedPaginationSupport.Ascending, true); async Task>> ISpotOrderRestClient.GetClosedSpotOrdersAsync(GetClosedOrdersRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetClosedSpotOrdersOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ISpotOrderRestClient)this).GetClosedSpotOrdersOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -379,7 +376,7 @@ async Task>> ISpotOrderRestClient { ClientOrderId = x.ClientOrderId, AveragePrice = x.AverageFillPrice, - Price = x.Price, + OrderPrice = x.Price, Quantity = x.Quantity, QuantityFilled = x.QuantityFilled, QuoteQuantity = x.QuoteQuantity, @@ -392,7 +389,7 @@ async Task>> ISpotOrderRestClient EndpointOptions ISpotOrderRestClient.GetSpotOrderTradesOptions { get; } = new EndpointOptions(true); async Task>> ISpotOrderRestClient.GetSpotOrderTradesAsync(GetOrderTradesRequest request, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetSpotOrderTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ISpotOrderRestClient)this).GetSpotOrderTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -417,10 +414,10 @@ async Task>> ISpotOrderRestClient }).ToArray()); } - PaginatedEndpointOptions ISpotOrderRestClient.GetSpotUserTradesOptions { get; } = new PaginatedEndpointOptions(SharedPaginationType.Descending, true); + PaginatedEndpointOptions ISpotOrderRestClient.GetSpotUserTradesOptions { get; } = new PaginatedEndpointOptions(SharedPaginationSupport.Descending, true); async Task>> ISpotOrderRestClient.GetSpotUserTradesAsync(GetUserTradesRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetSpotUserTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ISpotOrderRestClient)this).GetSpotUserTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -461,7 +458,7 @@ async Task>> ISpotOrderRestClient EndpointOptions ISpotOrderRestClient.CancelSpotOrderOptions { get; } = new EndpointOptions(true); async Task> ISpotOrderRestClient.CancelSpotOrderAsync(CancelOrderRequest request, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).CancelSpotOrderOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ISpotOrderRestClient)this).CancelSpotOrderOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -517,7 +514,7 @@ private SharedOrderType ParseOrderType(SpotOrderType type) async Task>> IAssetsRestClient.GetAssetsAsync(GetAssetsRequest request, CancellationToken ct) { - var validationError = ((IAssetsRestClient)this).GetAssetsOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedApiTypes); + var validationError = ((IAssetsRestClient)this).GetAssetsOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -544,7 +541,7 @@ async Task>> IAssetsRestClient.GetAss EndpointOptions IAssetsRestClient.GetAssetOptions { get; } = new EndpointOptions(false); async Task> IAssetsRestClient.GetAssetAsync(GetAssetRequest request, CancellationToken ct) { - var validationError = ((IAssetsRestClient)this).GetAssetOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedApiTypes); + var validationError = ((IAssetsRestClient)this).GetAssetOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -579,7 +576,7 @@ async Task> IAssetsRestClient.GetAssetAsync(GetAs EndpointOptions IDepositRestClient.GetDepositAddressesOptions { get; } = new EndpointOptions(true); async Task>> IDepositRestClient.GetDepositAddressesAsync(GetDepositAddressesRequest request, CancellationToken ct) { - var validationError = ((IDepositRestClient)this).GetDepositAddressesOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedApiTypes); + var validationError = ((IDepositRestClient)this).GetDepositAddressesOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -594,10 +591,10 @@ async Task>> IDepositRestCli }); } - GetDepositsOptions IDepositRestClient.GetDepositsOptions { get; } = new GetDepositsOptions(SharedPaginationType.Descending, true); + GetDepositsOptions IDepositRestClient.GetDepositsOptions { get; } = new GetDepositsOptions(SharedPaginationSupport.Descending, true); async Task>> IDepositRestClient.GetDepositsAsync(GetDepositsRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((IDepositRestClient)this).GetDepositsOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedApiTypes); + var validationError = ((IDepositRestClient)this).GetDepositsOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -636,10 +633,10 @@ async Task>> IDepositRestClient.Get #region Withdrawal client - GetWithdrawalsOptions IWithdrawalRestClient.GetWithdrawalsOptions { get; } = new GetWithdrawalsOptions(SharedPaginationType.Descending, true); + GetWithdrawalsOptions IWithdrawalRestClient.GetWithdrawalsOptions { get; } = new GetWithdrawalsOptions(SharedPaginationSupport.Descending, true); async Task>> IWithdrawalRestClient.GetWithdrawalsAsync(GetWithdrawalsRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((IWithdrawalRestClient)this).GetWithdrawalsOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedApiTypes); + var validationError = ((IWithdrawalRestClient)this).GetWithdrawalsOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -682,7 +679,7 @@ async Task>> IWithdrawalRestClie WithdrawOptions IWithdrawRestClient.WithdrawOptions { get; } = new WithdrawOptions(); async Task > IWithdrawRestClient.WithdrawAsync(WithdrawRequest request, CancellationToken ct) { - var validationError = ((IWithdrawRestClient)this).WithdrawOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedApiTypes); + var validationError = ((IWithdrawRestClient)this).WithdrawOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -707,7 +704,7 @@ async Task>> IWithdrawalRestClie EndpointOptions IListenKeyRestClient.StartOptions { get; } = new EndpointOptions(true); async Task> IListenKeyRestClient.StartListenKeyAsync(StartListenKeyRequest request, CancellationToken ct) { - var validationError = ((IListenKeyRestClient)this).StartOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((IListenKeyRestClient)this).StartOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -721,7 +718,7 @@ async Task> IListenKeyRestClient.StartListenKeyAsync(S EndpointOptions IListenKeyRestClient.KeepAliveOptions { get; } = new EndpointOptions(true); async Task> IListenKeyRestClient.KeepAliveListenKeyAsync(KeepAliveListenKeyRequest request, CancellationToken ct) { - var validationError = ((IListenKeyRestClient)this).KeepAliveOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((IListenKeyRestClient)this).KeepAliveOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -736,7 +733,7 @@ async Task> IListenKeyRestClient.KeepAliveListenKeyAsy EndpointOptions IListenKeyRestClient.StopOptions { get; } = new EndpointOptions(true); async Task> IListenKeyRestClient.StopListenKeyAsync(StopListenKeyRequest request, CancellationToken ct) { - var validationError = ((IListenKeyRestClient)this).StopOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((IListenKeyRestClient)this).StopOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs index f471ebd04..0f1d313a4 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs @@ -2,12 +2,13 @@ using CryptoExchange.Net.Objects.Sockets; using CryptoExchange.Net.SharedApis.Enums; using CryptoExchange.Net.SharedApis.Interfaces.Socket; +using CryptoExchange.Net.SharedApis.Interfaces.Socket.Spot; using CryptoExchange.Net.SharedApis.Models; -using CryptoExchange.Net.SharedApis.Models.FilterOptions; +using CryptoExchange.Net.SharedApis.Models.Options; +using CryptoExchange.Net.SharedApis.Models.Options.Endpoints; +using CryptoExchange.Net.SharedApis.Models.Options.Subscriptions; using CryptoExchange.Net.SharedApis.Models.Socket; -using CryptoExchange.Net.SharedApis.RequestModels; using CryptoExchange.Net.SharedApis.ResponseModels; -using CryptoExchange.Net.SharedApis.SubscribeModels; using System; using System.Collections.Generic; using System.Text; @@ -17,16 +18,16 @@ namespace Binance.Net.Clients.SpotApi internal partial class BinanceSocketClientSpotApi : IBinanceSocketClientSpotApiShared { public string Exchange => BinanceExchange.ExchangeName; - public TradingMode[] SupportedApiTypes => new[] { TradingMode.Spot }; + public TradingMode[] SupportedTradingModes => new[] { TradingMode.Spot }; public void SetDefaultExchangeParameter(string key, object value) => ExchangeParameters.SetStaticParameter(Exchange, key, value); public void ResetDefaultExchangeParameters() => ExchangeParameters.ResetStaticParameters(); #region Tickers client - SubscriptionOptions ITickersSocketClient.SubscribeAllTickersOptions { get; } = new SubscriptionOptions(false); + EndpointOptions ITickersSocketClient.SubscribeAllTickersOptions { get; } = new EndpointOptions(false); async Task> ITickersSocketClient.SubscribeToAllTickersUpdatesAsync(SubscribeAllTickersRequest request, Action>> handler, CancellationToken ct) { - var validationError = ((ITickersSocketClient)this).SubscribeAllTickersOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((ITickersSocketClient)this).SubscribeAllTickersOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -38,10 +39,10 @@ async Task> ITickersSocketClient.SubscribeToA #endregion #region Ticker client - SubscriptionOptions ITickerSocketClient.SubscribeTickerOptions { get; } = new SubscriptionOptions(false); + EndpointOptions ITickerSocketClient.SubscribeTickerOptions { get; } = new EndpointOptions(false); async Task> ITickerSocketClient.SubscribeToTickerUpdatesAsync(SubscribeTickerRequest request, Action> handler, CancellationToken ct) { - var validationError = ((ITickerSocketClient)this).SubscribeTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ITickerSocketClient)this).SubscribeTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -54,10 +55,10 @@ async Task> ITickerSocketClient.SubscribeToTi #region Trade client - SubscriptionOptions ITradeSocketClient.SubscribeTradeOptions { get; } = new SubscriptionOptions(false); + EndpointOptions ITradeSocketClient.SubscribeTradeOptions { get; } = new EndpointOptions(false); async Task> ITradeSocketClient.SubscribeToTradeUpdatesAsync(SubscribeTradeRequest request, Action>> handler, CancellationToken ct) { - var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -71,10 +72,10 @@ async Task> ITradeSocketClient.SubscribeToTra #region Book Ticker client - SubscriptionOptions IBookTickerSocketClient.SubscribeBookTickerOptions { get; } = new SubscriptionOptions(false); + EndpointOptions IBookTickerSocketClient.SubscribeBookTickerOptions { get; } = new EndpointOptions(false); async Task> IBookTickerSocketClient.SubscribeToBookTickerUpdatesAsync(SubscribeBookTickerRequest request, Action> handler, CancellationToken ct) { - var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -87,7 +88,7 @@ async Task> IBookTickerSocketClient.Subscribe #endregion #region Balance client - SubscriptionOptions IBalanceSocketClient.SubscribeBalanceOptions { get; } = new SubscriptionOptions(false) + EndpointOptions IBalanceSocketClient.SubscribeBalanceOptions { get; } = new EndpointOptions(false) { RequiredOptionalParameters = new List { @@ -96,7 +97,7 @@ async Task> IBookTickerSocketClient.Subscribe }; async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(SubscribeBalancesRequest request, Action>> handler, CancellationToken ct) { - var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -111,7 +112,7 @@ async Task> IBalanceSocketClient.SubscribeToB #region Spot Order client - SubscriptionOptions ISpotOrderSocketClient.SubscribeSpotOrderOptions { get; } = new SubscriptionOptions(false) + EndpointOptions ISpotOrderSocketClient.SubscribeSpotOrderOptions { get; } = new EndpointOptions(false) { RequiredOptionalParameters = new List { @@ -120,7 +121,7 @@ async Task> IBalanceSocketClient.SubscribeToB }; async Task> ISpotOrderSocketClient.SubscribeToSpotOrderUpdatesAsync(SubscribeSpotOrderRequest request, Action>> handler, CancellationToken ct) { - var validationError = ((ISpotOrderSocketClient)this).SubscribeSpotOrderOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedApiTypes); + var validationError = ((ISpotOrderSocketClient)this).SubscribeSpotOrderOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -135,7 +136,7 @@ async Task> ISpotOrderSocketClient.SubscribeT update.Data.CreateTime) { ClientOrderId = update.Data.ClientOrderId, - Price = update.Data.Price, + OrderPrice = update.Data.Price, Quantity = update.Data.Quantity, QuantityFilled = update.Data.QuantityFilled, QuoteQuantity = update.Data.QuoteQuantity, @@ -164,7 +165,7 @@ async Task> IKlineSocketClient.SubscribeToKli if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeResult(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -179,7 +180,7 @@ async Task> IKlineSocketClient.SubscribeToKli SubscribeOrderBookOptions IOrderBookSocketClient.SubscribeOrderBookOptions { get; } = new SubscribeOrderBookOptions(false, new[] { 5, 10, 20 }); async Task> IOrderBookSocketClient.SubscribeToOrderBookUpdatesAsync(SubscribeOrderBookRequest request, Action> handler, CancellationToken ct) { - var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs index 2c22fe2f2..ca7a1d618 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -2,13 +2,13 @@ using Binance.Net.Interfaces.Clients.UsdFuturesApi; using CryptoExchange.Net.SharedApis.Enums; using CryptoExchange.Net.SharedApis.Interfaces; +using CryptoExchange.Net.SharedApis.Interfaces.Rest; using CryptoExchange.Net.SharedApis.Interfaces.Rest.Futures; using CryptoExchange.Net.SharedApis.Interfaces.Rest.Spot; using CryptoExchange.Net.SharedApis.Models; -using CryptoExchange.Net.SharedApis.Models.EndpointOptions; -using CryptoExchange.Net.SharedApis.Models.FilterOptions; +using CryptoExchange.Net.SharedApis.Models.Options; +using CryptoExchange.Net.SharedApis.Models.Options.Endpoints; using CryptoExchange.Net.SharedApis.Models.Rest; -using CryptoExchange.Net.SharedApis.RequestModels; using CryptoExchange.Net.SharedApis.ResponseModels; using System; using System.Collections.Generic; @@ -20,13 +20,13 @@ internal partial class BinanceRestClientUsdFuturesApi : IBinanceRestClientUsdFut { public string Exchange => BinanceExchange.ExchangeName; - public TradingMode[] SupportedApiTypes => new[] { TradingMode.DeliveryLinear, TradingMode.PerpetualLinear }; + public TradingMode[] SupportedTradingModes => new[] { TradingMode.DeliveryLinear, TradingMode.PerpetualLinear }; public void SetDefaultExchangeParameter(string key, object value) => ExchangeParameters.SetStaticParameter(Exchange, key, value); public void ResetDefaultExchangeParameters() => ExchangeParameters.ResetStaticParameters(); #region Klines client - GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(SharedPaginationType.Descending, false) + GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(SharedPaginationSupport.Descending, false) { MaxRequestDataPoints = 1000 }; @@ -37,7 +37,7 @@ async Task>> IKlineRestClient.GetKlin if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -85,20 +85,20 @@ async Task>> IKlineRestClient.GetKlin #region Mark Klines client - GetKlinesOptions IMarkPriceKlineRestClient.GetMarkPriceKlinesOptions { get; } = new GetKlinesOptions(SharedPaginationType.Descending, false) + GetKlinesOptions IMarkPriceKlineRestClient.GetMarkPriceKlinesOptions { get; } = new GetKlinesOptions(SharedPaginationSupport.Descending, false) { MaxRequestDataPoints = 1000 }; - async Task>> IMarkPriceKlineRestClient.GetMarkPriceKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, CancellationToken ct) + async Task>> IMarkPriceKlineRestClient.GetMarkPriceKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, CancellationToken ct) { var interval = (Enums.KlineInterval)request.Interval; if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) - return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); + return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IMarkPriceKlineRestClient)this).GetMarkPriceKlinesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IMarkPriceKlineRestClient)this).GetMarkPriceKlinesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) - return new ExchangeWebResult>(Exchange, validationError); + return new ExchangeWebResult>(Exchange, validationError); // Determine pagination // Data is normally returned oldest first, so to do newest first pagination we have to do some calc @@ -126,7 +126,7 @@ async Task>> IMarkPriceKlineRestC ct: ct ).ConfigureAwait(false); if (!result) - return result.AsExchangeResult>(Exchange, null, default); + return result.AsExchangeResult>(Exchange, null, default); // Get next token DateTimeToken? nextToken = null; @@ -137,7 +137,7 @@ async Task>> IMarkPriceKlineRestC nextToken = new DateTimeToken(minOpenTime.AddSeconds(-(int)(interval - 1))); } - return result.AsExchangeResult>(Exchange, request.Symbol.ApiType, result.Data.Reverse().Select(x => new SharedMarkKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)).ToArray(), nextToken); + return result.AsExchangeResult>(Exchange, request.Symbol.ApiType, result.Data.Reverse().Select(x => new SharedFuturesKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)).ToArray(), nextToken); } #endregion @@ -147,7 +147,7 @@ async Task>> IMarkPriceKlineRestC EndpointOptions IFuturesSymbolRestClient.GetFuturesSymbolsOptions { get; } = new EndpointOptions(false); async Task>> IFuturesSymbolRestClient.GetFuturesSymbolsAsync(GetSymbolsRequest request, CancellationToken ct) { - var validationError = ((IFuturesSymbolRestClient)this).GetFuturesSymbolsOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((IFuturesSymbolRestClient)this).GetFuturesSymbolsOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -156,9 +156,9 @@ async Task>> IFuturesSymbolRe return result.AsExchangeResult>(Exchange, null, default); var data = result.Data.Symbols.Where(x => x.ContractType != null); - if (request.ApiType != null) - data = data.Where(x => request.ApiType == TradingMode.PerpetualLinear ? x.ContractType == ContractType.Perpetual : (x.ContractType != ContractType.Perpetual && x.ContractType != ContractType.PerpetualDelivering)); - return result.AsExchangeResult>(Exchange, request.ApiType == null ? SupportedApiTypes : new[] { request.ApiType.Value }, data.Select(s => new SharedFuturesSymbol(s.ContractType == ContractType.Perpetual ? SharedSymbolType.PerpetualLinear : SharedSymbolType.DeliveryLinear, s.BaseAsset, s.QuoteAsset, s.Name, s.Status == SymbolStatus.Trading) + if (request.TradingMode != null) + data = data.Where(x => request.TradingMode == TradingMode.PerpetualLinear ? x.ContractType == ContractType.Perpetual : (x.ContractType != ContractType.Perpetual && x.ContractType != ContractType.PerpetualDelivering)); + return result.AsExchangeResult>(Exchange, request.TradingMode == null ? SupportedTradingModes : new[] { request.TradingMode.Value }, data.Select(s => new SharedFuturesSymbol(s.ContractType == ContractType.Perpetual ? SharedSymbolType.PerpetualLinear : SharedSymbolType.DeliveryLinear, s.BaseAsset, s.QuoteAsset, s.Name, s.Status == SymbolStatus.Trading) { MinTradeQuantity = s.LotSizeFilter?.MinQuantity, MaxTradeQuantity = s.LotSizeFilter?.MaxQuantity, @@ -176,7 +176,7 @@ async Task>> IFuturesSymbolRe EndpointOptions IFuturesTickerRestClient.GetFuturesTickerOptions { get; } = new EndpointOptions(false); async Task> IFuturesTickerRestClient.GetFuturesTickerAsync(GetTickerRequest request, CancellationToken ct) { - var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -201,7 +201,7 @@ async Task> IFuturesTickerRestClient.GetF EndpointOptions IFuturesTickerRestClient.GetFuturesTickersOptions { get; } = new EndpointOptions(false); async Task>> IFuturesTickerRestClient.GetFuturesTickersAsync(GetTickersRequest request, CancellationToken ct) { - var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickersOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickersOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -214,10 +214,10 @@ async Task>> IFuturesTickerRe return resultMarkPrices.Result.AsExchangeResult>(Exchange, null, default); var data = resultTickers.Result.Data; - if (request.ApiType.HasValue) - data = data.Where(x => (request.ApiType == TradingMode.DeliveryLinear ? x.Symbol.Contains("_") : !x.Symbol.Contains("_"))); + if (request.TradingMode.HasValue) + data = data.Where(x => (request.TradingMode == TradingMode.DeliveryLinear ? x.Symbol.Contains("_") : !x.Symbol.Contains("_"))); - return resultTickers.Result.AsExchangeResult>(Exchange, request.ApiType == null ? SupportedApiTypes : new[] { request.ApiType.Value }, data.Select(x => + return resultTickers.Result.AsExchangeResult>(Exchange, request.TradingMode == null ? SupportedTradingModes : new[] { request.TradingMode.Value }, data.Select(x => { var markPrice = resultMarkPrices.Result.Data.Single(p => p.Symbol == x.Symbol); return new SharedFuturesTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume, x.PriceChangePercent) @@ -237,7 +237,7 @@ async Task>> IFuturesTickerRe GetRecentTradesOptions IRecentTradeRestClient.GetRecentTradesOptions { get; } = new GetRecentTradesOptions(1000, false); async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, CancellationToken ct) { - var validationError = ((IRecentTradeRestClient)this).GetRecentTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IRecentTradeRestClient)this).GetRecentTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -255,30 +255,28 @@ async Task>> IRecentTradeRestClient.G #region Futures Order Client - PlaceFuturesOrderOptions IFuturesOrderRestClient.PlaceFuturesOrderOptions { get; } = new PlaceFuturesOrderOptions( - new[] - { - SharedOrderType.Limit, - SharedOrderType.Market - }, - new[] - { - SharedTimeInForce.GoodTillCanceled, - SharedTimeInForce.ImmediateOrCancel, - SharedTimeInForce.FillOrKill - }, - new SharedQuantitySupport( - SharedQuantityType.BaseAsset, - SharedQuantityType.BaseAsset, - SharedQuantityType.BaseAsset, - SharedQuantityType.BaseAsset)); - SharedFeeDeductionType IFuturesOrderRestClient.FuturesFeeDeductionType => SharedFeeDeductionType.AddToCost; SharedFeeAssetType IFuturesOrderRestClient.FuturesFeeAssetType => SharedFeeAssetType.QuoteAsset; + IEnumerable IFuturesOrderRestClient.FuturesSupportedOrderType { get; } = new[] { SharedOrderType.Limit, SharedOrderType.Market }; + IEnumerable IFuturesOrderRestClient.FuturesSupportedTimeInForce { get; } = new[] { SharedTimeInForce.GoodTillCanceled, SharedTimeInForce.ImmediateOrCancel, SharedTimeInForce.FillOrKill }; + SharedQuantitySupport IFuturesOrderRestClient.FuturesSupportedOrderQuantity { get; } = new SharedQuantitySupport( + SharedQuantityType.Contracts, + SharedQuantityType.Contracts, + SharedQuantityType.Contracts, + SharedQuantityType.Contracts); + + PlaceFuturesOrderOptions IFuturesOrderRestClient.PlaceFuturesOrderOptions { get; } = new PlaceFuturesOrderOptions(); async Task> IFuturesOrderRestClient.PlaceFuturesOrderAsync(PlaceFuturesOrderRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).PlaceFuturesOrderOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).PlaceFuturesOrderOptions.ValidateRequest( + Exchange, + request, + request.Symbol.ApiType, + SupportedTradingModes, + ((ISpotOrderRestClient)this).SpotSupportedOrderTypes, + ((ISpotOrderRestClient)this).SpotSupportedTimeInForce, + ((ISpotOrderRestClient)this).SpotSupportedOrderQuantity); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -303,7 +301,7 @@ async Task> IFuturesOrderRestClient.PlaceFuturesOrde EndpointOptions IFuturesOrderRestClient.GetFuturesOrderOptions { get; } = new EndpointOptions(true); async Task> IFuturesOrderRestClient.GetFuturesOrderAsync(GetOrderRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -324,7 +322,7 @@ async Task> IFuturesOrderRestClient.GetFut { ClientOrderId = order.Data.ClientOrderId, AveragePrice = order.Data.AveragePrice == 0 ? null : order.Data.AveragePrice, - Price = order.Data.Price == 0 ? null : order.Data.Price, + OrderPrice = order.Data.Price == 0 ? null : order.Data.Price, Quantity = order.Data.Quantity, QuantityFilled = order.Data.QuantityFilled, QuoteQuantityFilled = order.Data.QuoteQuantityFilled, @@ -338,7 +336,7 @@ async Task> IFuturesOrderRestClient.GetFut EndpointOptions IFuturesOrderRestClient.GetOpenFuturesOrdersOptions { get; } = new EndpointOptions(true); async Task>> IFuturesOrderRestClient.GetOpenFuturesOrdersAsync(GetOpenOrdersRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetOpenFuturesOrdersOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.ApiType!.Value, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetOpenFuturesOrdersOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.TradingMode!.Value, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -347,7 +345,7 @@ async Task>> IFuturesOrderRest if (!orders) return orders.AsExchangeResult>(Exchange, null, default); - return orders.AsExchangeResult>(Exchange, SupportedApiTypes, orders.Data.Select(x => new SharedFuturesOrder( + return orders.AsExchangeResult>(Exchange, SupportedTradingModes, orders.Data.Select(x => new SharedFuturesOrder( x.Symbol, x.Id.ToString(), ParseOrderType(x.Type), @@ -357,7 +355,7 @@ async Task>> IFuturesOrderRest { ClientOrderId = x.ClientOrderId, AveragePrice = x.AveragePrice == 0 ? null : x.AveragePrice, - Price = x.Price == 0 ? null : x.Price, + OrderPrice = x.Price == 0 ? null : x.Price, Quantity = x.Quantity, QuantityFilled = x.QuantityFilled, QuoteQuantityFilled = x.QuoteQuantityFilled, @@ -368,10 +366,10 @@ async Task>> IFuturesOrderRest }).ToArray()); } - PaginatedEndpointOptions IFuturesOrderRestClient.GetClosedFuturesOrdersOptions { get; } = new PaginatedEndpointOptions(SharedPaginationType.Descending, true); + PaginatedEndpointOptions IFuturesOrderRestClient.GetClosedFuturesOrdersOptions { get; } = new PaginatedEndpointOptions(SharedPaginationSupport.Descending, true); async Task>> IFuturesOrderRestClient.GetClosedFuturesOrdersAsync(GetClosedOrdersRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetClosedFuturesOrdersOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetClosedFuturesOrdersOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -404,7 +402,7 @@ async Task>> IFuturesOrderRest { ClientOrderId = x.ClientOrderId, AveragePrice = x.AveragePrice == 0 ? null : x.AveragePrice, - Price = x.Price == 0 ? null : x.Price, + OrderPrice = x.Price == 0 ? null : x.Price, Quantity = x.Quantity, QuantityFilled = x.QuantityFilled, QuoteQuantityFilled = x.QuoteQuantityFilled, @@ -418,7 +416,7 @@ async Task>> IFuturesOrderRest EndpointOptions IFuturesOrderRestClient.GetFuturesOrderTradesOptions { get; } = new EndpointOptions(true); async Task>> IFuturesOrderRestClient.GetFuturesOrderTradesAsync(GetOrderTradesRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -445,10 +443,10 @@ async Task>> IFuturesOrderRestCli }).ToArray()); } - PaginatedEndpointOptions IFuturesOrderRestClient.GetFuturesUserTradesOptions { get; } = new PaginatedEndpointOptions(SharedPaginationType.Descending, true); + PaginatedEndpointOptions IFuturesOrderRestClient.GetFuturesUserTradesOptions { get; } = new PaginatedEndpointOptions(SharedPaginationSupport.Descending, true); async Task>> IFuturesOrderRestClient.GetFuturesUserTradesAsync(GetUserTradesRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetFuturesUserTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetFuturesUserTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -492,7 +490,7 @@ async Task>> IFuturesOrderRestCli EndpointOptions IFuturesOrderRestClient.CancelFuturesOrderOptions { get; } = new EndpointOptions(true); async Task> IFuturesOrderRestClient.CancelFuturesOrderAsync(CancelOrderRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).CancelFuturesOrderOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).CancelFuturesOrderOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -509,7 +507,7 @@ async Task> IFuturesOrderRestClient.CancelFuturesOrd EndpointOptions IFuturesOrderRestClient.GetPositionsOptions { get; } = new EndpointOptions(true); async Task>> IFuturesOrderRestClient.GetPositionsAsync(GetPositionsRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetPositionsOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).GetPositionsOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -518,15 +516,15 @@ async Task>> IFuturesOrderRestClie return result.AsExchangeResult>(Exchange, null, default); var data = result.Data; - if (request.ApiType.HasValue) - data = data.Where(x => request.ApiType == TradingMode.DeliveryLinear ? x.Symbol.Contains("_") : !x.Symbol.Contains("_")); + if (request.TradingMode.HasValue) + data = data.Where(x => request.TradingMode == TradingMode.DeliveryLinear ? x.Symbol.Contains("_") : !x.Symbol.Contains("_")); - return result.AsExchangeResult>(Exchange, request.Symbol == null ? SupportedApiTypes : new[] { request.Symbol.ApiType }, data.Select(x => new SharedPosition(x.Symbol, Math.Abs(x.Quantity), x.UpdateTime) + return result.AsExchangeResult>(Exchange, request.Symbol == null ? SupportedTradingModes : new[] { request.Symbol.ApiType }, data.Select(x => new SharedPosition(x.Symbol, Math.Abs(x.Quantity), x.UpdateTime) { UnrealizedPnl = x.UnrealizedPnl, LiquidationPrice = x.LiquidationPrice == 0 ? null: x.LiquidationPrice, Leverage = x.Leverage, - AverageEntryPrice = x.EntryPrice, + AverageOpenPrice = x.EntryPrice, PositionSide = x.PositionSide == PositionSide.Both ? (x.Quantity >= 0 ? SharedPositionSide.Long : SharedPositionSide.Short) : x.PositionSide == PositionSide.Short ? SharedPositionSide.Short : SharedPositionSide.Long }).ToArray()); } @@ -541,7 +539,7 @@ async Task>> IFuturesOrderRestClie }; async Task> IFuturesOrderRestClient.ClosePositionAsync(ClosePositionRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).ClosePositionOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderRestClient)this).ClosePositionOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -601,11 +599,12 @@ private SharedOrderType ParseOrderType(FuturesOrderType type) #endregion #region Leverage client + SharedLeverageSettingMode ILeverageRestClient.LeverageSettingType => SharedLeverageSettingMode.PerSymbol; EndpointOptions ILeverageRestClient.GetLeverageOptions { get; } = new EndpointOptions(true); async Task> ILeverageRestClient.GetLeverageAsync(GetLeverageRequest request, CancellationToken ct) { - var validationError = ((ILeverageRestClient)this).GetLeverageOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ILeverageRestClient)this).GetLeverageOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -618,14 +617,14 @@ async Task> ILeverageRestClient.GetLeverageAsy return result.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedLeverage(result.Data.First().Leverage) { - Side = request.Side + Side = request.PositionSide }); } - SetLeverageOptions ILeverageRestClient.SetLeverageOptions { get; } = new SetLeverageOptions(false); + SetLeverageOptions ILeverageRestClient.SetLeverageOptions { get; } = new SetLeverageOptions(); async Task> ILeverageRestClient.SetLeverageAsync(SetLeverageRequest request, CancellationToken ct) { - var validationError = ((ILeverageRestClient)this).SetLeverageOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ILeverageRestClient)this).SetLeverageOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -641,7 +640,7 @@ async Task> ILeverageRestClient.SetLeverageAsy GetOrderBookOptions IOrderBookRestClient.GetOrderBookOptions { get; } = new GetOrderBookOptions(new[] { 5, 10, 20, 50, 100, 500, 1000 }, false); async Task> IOrderBookRestClient.GetOrderBookAsync(GetOrderBookRequest request, CancellationToken ct) { - var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -658,11 +657,11 @@ async Task> IOrderBookRestClient.GetOrderBook #endregion #region Trade History client - GetTradeHistoryOptions ITradeHistoryRestClient.GetTradeHistoryOptions { get; } = new GetTradeHistoryOptions(SharedPaginationType.Ascending, false); + GetTradeHistoryOptions ITradeHistoryRestClient.GetTradeHistoryOptions { get; } = new GetTradeHistoryOptions(SharedPaginationSupport.Ascending, false); async Task>> ITradeHistoryRestClient.GetTradeHistoryAsync(GetTradeHistoryRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((ITradeHistoryRestClient)this).GetTradeHistoryOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ITradeHistoryRestClient)this).GetTradeHistoryOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -692,20 +691,20 @@ async Task>> ITradeHistoryRestClient. #region Index Klines client - GetKlinesOptions IIndexPriceKlineRestClient.GetIndexPriceKlinesOptions { get; } = new GetKlinesOptions(SharedPaginationType.Descending, false) + GetKlinesOptions IIndexPriceKlineRestClient.GetIndexPriceKlinesOptions { get; } = new GetKlinesOptions(SharedPaginationSupport.Descending, false) { MaxRequestDataPoints = 1000 }; - async Task>> IIndexPriceKlineRestClient.GetIndexPriceKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, CancellationToken ct) + async Task>> IIndexPriceKlineRestClient.GetIndexPriceKlinesAsync(GetKlinesRequest request, INextPageToken? pageToken, CancellationToken ct) { var interval = (Enums.KlineInterval)request.Interval; if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) - return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); + return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IIndexPriceKlineRestClient)this).GetIndexPriceKlinesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IIndexPriceKlineRestClient)this).GetIndexPriceKlinesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) - return new ExchangeWebResult>(Exchange, validationError); + return new ExchangeWebResult>(Exchange, validationError); // Determine pagination // Data is normally returned oldest first, so to do newest first pagination we have to do some calc @@ -733,7 +732,7 @@ async Task>> IIndexPriceKlineRest ct: ct ).ConfigureAwait(false); if (!result) - return result.AsExchangeResult>(Exchange, null, default); + return result.AsExchangeResult>(Exchange, null, default); // Get next token DateTimeToken? nextToken = null; @@ -744,7 +743,7 @@ async Task>> IIndexPriceKlineRest nextToken = new DateTimeToken(minOpenTime.AddSeconds(-(int)(interval - 1))); } - return result.AsExchangeResult>(Exchange, request.Symbol.ApiType, result.Data.Reverse().Select(x => new SharedMarkKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)).ToArray(), nextToken); + return result.AsExchangeResult>(Exchange, request.Symbol.ApiType, result.Data.Reverse().Select(x => new SharedFuturesKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)).ToArray(), nextToken); } #endregion @@ -754,7 +753,7 @@ async Task>> IIndexPriceKlineRest EndpointOptions IOpenInterestRestClient.GetOpenInterestOptions { get; } = new EndpointOptions(true); async Task> IOpenInterestRestClient.GetOpenInterestAsync(GetOpenInterestRequest request, CancellationToken ct) { - var validationError = ((IOpenInterestRestClient)this).GetOpenInterestOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IOpenInterestRestClient)this).GetOpenInterestOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -768,11 +767,11 @@ async Task> IOpenInterestRestClient.GetOpe #endregion #region Funding Rate client - GetFundingRateHistoryOptions IFundingRateRestClient.GetFundingRateHistoryOptions { get; } = new GetFundingRateHistoryOptions(SharedPaginationType.Ascending, false); + GetFundingRateHistoryOptions IFundingRateRestClient.GetFundingRateHistoryOptions { get; } = new GetFundingRateHistoryOptions(SharedPaginationSupport.Ascending, false); async Task>> IFundingRateRestClient.GetFundingRateHistoryAsync(GetFundingRateHistoryRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((IFundingRateRestClient)this).GetFundingRateHistoryOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IFundingRateRestClient)this).GetFundingRateHistoryOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -804,7 +803,7 @@ async Task>> IFundingRateRestCl async Task>> IBalanceRestClient.GetBalancesAsync(GetBalancesRequest request, CancellationToken ct) { - var validationError = ((IBalanceRestClient)this).GetBalancesOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((IBalanceRestClient)this).GetBalancesOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -812,17 +811,18 @@ async Task>> IBalanceRestClient.Get if (!result) return result.AsExchangeResult>(Exchange, null, default); - return result.AsExchangeResult>(Exchange, SupportedApiTypes, result.Data.Select(x => new SharedBalance(x.Asset, x.AvailableBalance, x.WalletBalance)).ToArray()); + return result.AsExchangeResult>(Exchange, SupportedTradingModes, result.Data.Select(x => new SharedBalance(x.Asset, x.AvailableBalance, x.WalletBalance)).ToArray()); } #endregion #region Position Mode client + SharedPositionModeSelection IPositionModeRestClient.PositionModeSettingType => SharedPositionModeSelection.PerAccount; - GetPositionModeOptions IPositionModeRestClient.GetPositionModeOptions { get; } = new GetPositionModeOptions(false); + GetPositionModeOptions IPositionModeRestClient.GetPositionModeOptions { get; } = new GetPositionModeOptions(); async Task> IPositionModeRestClient.GetPositionModeAsync(GetPositionModeRequest request, CancellationToken ct) { - var validationError = ((IPositionModeRestClient)this).GetPositionModeOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.ApiType, SupportedApiTypes); + var validationError = ((IPositionModeRestClient)this).GetPositionModeOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -830,21 +830,21 @@ async Task> IPositionModeRestClient. if (!result) return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, SupportedApiTypes, new SharedPositionModeResult(result.Data.IsHedgeMode ? SharedPositionMode.HedgeMode : SharedPositionMode.OneWay)); + return result.AsExchangeResult(Exchange, SupportedTradingModes, new SharedPositionModeResult(result.Data.IsHedgeMode ? SharedPositionMode.HedgeMode : SharedPositionMode.OneWay)); } - SetPositionModeOptions IPositionModeRestClient.SetPositionModeOptions { get; } = new SetPositionModeOptions(true, true, false); + SetPositionModeOptions IPositionModeRestClient.SetPositionModeOptions { get; } = new SetPositionModeOptions(); async Task> IPositionModeRestClient.SetPositionModeAsync(SetPositionModeRequest request, CancellationToken ct) { - var validationError = ((IPositionModeRestClient)this).SetPositionModeOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.ApiType, SupportedApiTypes); + var validationError = ((IPositionModeRestClient)this).SetPositionModeOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); - var result = await Account.ModifyPositionModeAsync(request.Mode == SharedPositionMode.HedgeMode, ct: ct).ConfigureAwait(false); + var result = await Account.ModifyPositionModeAsync(request.PositionMode == SharedPositionMode.HedgeMode, ct: ct).ConfigureAwait(false); if (!result) return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, SupportedApiTypes, new SharedPositionModeResult(request.Mode)); + return result.AsExchangeResult(Exchange, SupportedTradingModes, new SharedPositionModeResult(request.PositionMode)); } #endregion @@ -853,7 +853,7 @@ async Task> IPositionModeRestClient. EndpointOptions IListenKeyRestClient.StartOptions { get; } = new EndpointOptions(true); async Task> IListenKeyRestClient.StartListenKeyAsync(StartListenKeyRequest request, CancellationToken ct) { - var validationError = ((IListenKeyRestClient)this).StartOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((IListenKeyRestClient)this).StartOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -862,12 +862,12 @@ async Task> IListenKeyRestClient.StartListenKeyAsync(S if (!result) return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, SupportedApiTypes, result.Data); + return result.AsExchangeResult(Exchange, SupportedTradingModes, result.Data); } EndpointOptions IListenKeyRestClient.KeepAliveOptions { get; } = new EndpointOptions(true); async Task> IListenKeyRestClient.KeepAliveListenKeyAsync(KeepAliveListenKeyRequest request, CancellationToken ct) { - var validationError = ((IListenKeyRestClient)this).KeepAliveOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((IListenKeyRestClient)this).KeepAliveOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -876,13 +876,13 @@ async Task> IListenKeyRestClient.KeepAliveListenKeyAsy if (!result) return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, SupportedApiTypes, request.ListenKey); + return result.AsExchangeResult(Exchange, SupportedTradingModes, request.ListenKey); } EndpointOptions IListenKeyRestClient.StopOptions { get; } = new EndpointOptions(true); async Task> IListenKeyRestClient.StopListenKeyAsync(StopListenKeyRequest request, CancellationToken ct) { - var validationError = ((IListenKeyRestClient)this).StopOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((IListenKeyRestClient)this).StopOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -891,7 +891,7 @@ async Task> IListenKeyRestClient.StopListenKeyAsync(St if (!result) return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, SupportedApiTypes, request.ListenKey); + return result.AsExchangeResult(Exchange, SupportedTradingModes, request.ListenKey); } #endregion } diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs index 71b10cb2b..6d71df401 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs @@ -5,11 +5,11 @@ using CryptoExchange.Net.SharedApis.Interfaces.Socket; using CryptoExchange.Net.SharedApis.Interfaces.Socket.Futures; using CryptoExchange.Net.SharedApis.Models; -using CryptoExchange.Net.SharedApis.Models.FilterOptions; +using CryptoExchange.Net.SharedApis.Models.Options; +using CryptoExchange.Net.SharedApis.Models.Options.Endpoints; +using CryptoExchange.Net.SharedApis.Models.Options.Subscriptions; using CryptoExchange.Net.SharedApis.Models.Socket; -using CryptoExchange.Net.SharedApis.RequestModels; using CryptoExchange.Net.SharedApis.ResponseModels; -using CryptoExchange.Net.SharedApis.SubscribeModels; using System; using System.Collections.Generic; using System.Text; @@ -19,17 +19,17 @@ namespace Binance.Net.Clients.UsdFuturesApi internal partial class BinanceSocketClientUsdFuturesApi : IBinanceSocketClientUsdFuturesApiShared { public string Exchange => BinanceExchange.ExchangeName; - public TradingMode[] SupportedApiTypes => new[] { TradingMode.DeliveryLinear, TradingMode.PerpetualLinear }; + public TradingMode[] SupportedTradingModes => new[] { TradingMode.DeliveryLinear, TradingMode.PerpetualLinear }; public void SetDefaultExchangeParameter(string key, object value) => ExchangeParameters.SetStaticParameter(Exchange, key, value); public void ResetDefaultExchangeParameters() => ExchangeParameters.ResetStaticParameters(); #region Ticker client - SubscriptionOptions ITickerSocketClient.SubscribeTickerOptions { get; } = new SubscriptionOptions(false); + EndpointOptions ITickerSocketClient.SubscribeTickerOptions { get; } = new EndpointOptions(false); async Task> ITickerSocketClient.SubscribeToTickerUpdatesAsync(SubscribeTickerRequest request, Action> handler, CancellationToken ct) { - var validationError = ((ITickerSocketClient)this).SubscribeTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ITickerSocketClient)this).SubscribeTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -43,18 +43,18 @@ async Task> ITickerSocketClient.SubscribeToTi #region Tickers client - SubscriptionOptions ITickersSocketClient.SubscribeAllTickersOptions { get; } = new SubscriptionOptions(false); + EndpointOptions ITickersSocketClient.SubscribeAllTickersOptions { get; } = new EndpointOptions(false); async Task> ITickersSocketClient.SubscribeToAllTickersUpdatesAsync(SubscribeAllTickersRequest request, Action>> handler, CancellationToken ct) { - var validationError = ((ITickersSocketClient)this).SubscribeAllTickersOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((ITickersSocketClient)this).SubscribeAllTickersOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); var result = await SubscribeToAllTickerUpdatesAsync(update => { var data = update.Data; - if (request.ApiType != null) - data = data.Where(x => request.ApiType == TradingMode.PerpetualLinear ? !x.Symbol.Contains("_") : x.Symbol.Contains("_")); + if (request.TradingMode != null) + data = data.Where(x => request.TradingMode == TradingMode.PerpetualLinear ? !x.Symbol.Contains("_") : x.Symbol.Contains("_")); if (!data.Any()) return; @@ -69,10 +69,10 @@ async Task> ITickersSocketClient.SubscribeToA #region Trade client - SubscriptionOptions ITradeSocketClient.SubscribeTradeOptions { get; } = new SubscriptionOptions(false); + EndpointOptions ITradeSocketClient.SubscribeTradeOptions { get; } = new EndpointOptions(false); async Task> ITradeSocketClient.SubscribeToTradeUpdatesAsync(SubscribeTradeRequest request, Action>> handler, CancellationToken ct) { - var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -86,10 +86,10 @@ async Task> ITradeSocketClient.SubscribeToTra #region Book Ticker client - SubscriptionOptions IBookTickerSocketClient.SubscribeBookTickerOptions { get; } = new SubscriptionOptions(false); + EndpointOptions IBookTickerSocketClient.SubscribeBookTickerOptions { get; } = new EndpointOptions(false); async Task> IBookTickerSocketClient.SubscribeToBookTickerUpdatesAsync(SubscribeBookTickerRequest request, Action> handler, CancellationToken ct) { - var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -102,7 +102,7 @@ async Task> IBookTickerSocketClient.Subscribe #endregion #region Balance client - SubscriptionOptions IBalanceSocketClient.SubscribeBalanceOptions { get; } = new SubscriptionOptions(false) + EndpointOptions IBalanceSocketClient.SubscribeBalanceOptions { get; } = new EndpointOptions(false) { RequiredOptionalParameters = new List { @@ -111,7 +111,7 @@ async Task> IBookTickerSocketClient.Subscribe }; async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(SubscribeBalancesRequest request, Action>> handler, CancellationToken ct) { - var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -126,7 +126,7 @@ async Task> IBalanceSocketClient.SubscribeToB #region Futures Order client - SubscriptionOptions IFuturesOrderSocketClient.SubscribeFuturesOrderOptions { get; } = new SubscriptionOptions(false) + EndpointOptions IFuturesOrderSocketClient.SubscribeFuturesOrderOptions { get; } = new EndpointOptions(false) { RequiredOptionalParameters = new List { @@ -135,7 +135,7 @@ async Task> IBalanceSocketClient.SubscribeToB }; async Task> IFuturesOrderSocketClient.SubscribeToFuturesOrderUpdatesAsync(SubscribeFuturesOrderRequest request, Action>> handler, CancellationToken ct) { - var validationError = ((IFuturesOrderSocketClient)this).SubscribeFuturesOrderOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((IFuturesOrderSocketClient)this).SubscribeFuturesOrderOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -150,7 +150,7 @@ async Task> IFuturesOrderSocketClient.Subscri update.Data.UpdateData.UpdateTime) { ClientOrderId = update.Data.UpdateData.ClientOrderId, - Price = update.Data.UpdateData.Price, + OrderPrice = update.Data.UpdateData.Price, Quantity = update.Data.UpdateData.Quantity, QuantityFilled = update.Data.UpdateData.AccumulatedQuantityOfFilledTrades, UpdateTime = update.Data.UpdateData.UpdateTime, @@ -180,7 +180,7 @@ async Task> IKlineSocketClient.SubscribeToKli if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeResult(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -195,7 +195,7 @@ async Task> IKlineSocketClient.SubscribeToKli SubscribeOrderBookOptions IOrderBookSocketClient.SubscribeOrderBookOptions { get; } = new SubscribeOrderBookOptions(false, new[] { 5, 10, 20 }); async Task> IOrderBookSocketClient.SubscribeToOrderBookUpdatesAsync(SubscribeOrderBookRequest request, Action> handler, CancellationToken ct) { - var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedApiTypes); + var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -207,7 +207,7 @@ async Task> IOrderBookSocketClient.SubscribeT #endregion #region Position client - SubscriptionOptions IPositionSocketClient.SubscribePositionOptions { get; } = new SubscriptionOptions(false) + EndpointOptions IPositionSocketClient.SubscribePositionOptions { get; } = new EndpointOptions(false) { RequiredOptionalParameters = new List { @@ -216,14 +216,14 @@ async Task> IOrderBookSocketClient.SubscribeT }; async Task> IPositionSocketClient.SubscribeToPositionUpdatesAsync(SubscribePositionRequest request, Action>> handler, CancellationToken ct) { - var validationError = ((IPositionSocketClient)this).SubscribePositionOptions.ValidateRequest(Exchange, request, request.ApiType, SupportedApiTypes); + var validationError = ((IPositionSocketClient)this).SubscribePositionOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); var result = await SubscribeToUserDataUpdatesAsync(request.ListenKey!, onAccountUpdate: update => handler(update.AsExchangeEvent>(Exchange, update.Data.UpdateData.Positions.Select(x => new SharedPosition(x.Symbol, x.Quantity, update.Data.EventTime) { - AverageEntryPrice = x.EntryPrice, + AverageOpenPrice = x.EntryPrice, PositionSide = x.PositionSide == Enums.PositionSide.Both ? (x.Quantity > 0 ? SharedPositionSide.Long : SharedPositionSide.Short) : x.PositionSide == Enums.PositionSide.Short ? SharedPositionSide.Short : SharedPositionSide.Long, UnrealizedPnl = x.UnrealizedPnl }).ToArray())), diff --git a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApi.cs b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApi.cs index 9caf69f05..4661e5c38 100644 --- a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApi.cs +++ b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApi.cs @@ -24,10 +24,13 @@ public interface IBinanceRestClientCoinFuturesApi : IRestApiClient, IDisposable public IBinanceRestClientCoinFuturesApiTrading Trading { get; } /// - /// Get the IFuturesClient for this client. This is a common interface which allows for some basic operations without knowing any details of the exchange. + /// DEPRECATED, use SharedClient instead /// - /// public IFuturesClient CommonFuturesClient { get; } + + /// + /// Get the shared rest requests client + /// public IBinanceRestClientCoinFuturesApiShared SharedClient { get; } } diff --git a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs index f9b2f4e4a..9f25ff325 100644 --- a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs @@ -1,4 +1,4 @@ -using CryptoExchange.Net.SharedApis.Interfaces; +using CryptoExchange.Net.SharedApis.Interfaces.Rest; using CryptoExchange.Net.SharedApis.Interfaces.Rest.Futures; using CryptoExchange.Net.SharedApis.Interfaces.Rest.Spot; using System; @@ -7,6 +7,9 @@ namespace Binance.Net.Interfaces.Clients.CoinFuturesApi { + /// + /// Shared interface for COIN-M Futures rest API usage + /// public interface IBinanceRestClientCoinFuturesApiShared : IFuturesTickerRestClient, IFuturesSymbolRestClient, diff --git a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceSocketClientCoinFuturesApi.cs b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceSocketClientCoinFuturesApi.cs index 6fb9333cb..3ffccebc0 100644 --- a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceSocketClientCoinFuturesApi.cs +++ b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceSocketClientCoinFuturesApi.cs @@ -11,6 +11,9 @@ namespace Binance.Net.Interfaces.Clients.CoinFuturesApi /// public interface IBinanceSocketClientCoinFuturesApi : ISocketApiClient, IDisposable { + /// + /// Get the shared socket subscription client + /// IBinanceSocketClientCoinFuturesApiShared SharedClient { get; } /// diff --git a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceSocketClientCoinFuturesApiShared.cs b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceSocketClientCoinFuturesApiShared.cs index 423e50746..b4145505e 100644 --- a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceSocketClientCoinFuturesApiShared.cs +++ b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceSocketClientCoinFuturesApiShared.cs @@ -6,6 +6,9 @@ namespace Binance.Net.Interfaces.Clients.CoinFuturesApi { + /// + /// Shared interface for COIN-M Futures socket API usage + /// public interface IBinanceSocketClientCoinFuturesApiShared : ITickerSocketClient, ITickersSocketClient, diff --git a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApi.cs b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApi.cs index ef10cbb30..bf6b1594c 100644 --- a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApi.cs +++ b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApi.cs @@ -23,11 +23,13 @@ public interface IBinanceRestClientSpotApi : IRestApiClient, IDisposable public IBinanceRestClientSpotApiTrading Trading { get; } /// - /// Get the ISpotClient for this client. This is a common interface which allows for some basic operations without knowing any details of the exchange. + /// DEPRECATED, use SharedClient instead /// - /// public ISpotClient CommonSpotClient { get; } + /// + /// Get the shared rest requests client + /// public IBinanceRestClientSpotApiShared SharedClient { get; } } } diff --git a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs index 888f32d37..5d0907ce1 100644 --- a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs @@ -1,4 +1,4 @@ -using CryptoExchange.Net.SharedApis.Interfaces; +using CryptoExchange.Net.SharedApis.Interfaces.Rest; using CryptoExchange.Net.SharedApis.Interfaces.Rest.Spot; using System; using System.Collections.Generic; @@ -6,6 +6,9 @@ namespace Binance.Net.Interfaces.Clients.SpotApi { + /// + /// Shared interface for Spot rest API usage + /// public interface IBinanceRestClientSpotApiShared: IAssetsRestClient, IBalanceRestClient, diff --git a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApi.cs b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApi.cs index 431bf0982..52217187d 100644 --- a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApi.cs +++ b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApi.cs @@ -20,6 +20,9 @@ public interface IBinanceSocketClientSpotApi : ISocketApiClient /// IBinanceSocketClientSpotApiTrading Trading { get; } + /// + /// Get the shared socket subscription client + /// IBinanceSocketClientSpotApiShared SharedClient { get; } } } \ No newline at end of file diff --git a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApiShared.cs b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApiShared.cs index 9c196a209..84182ab78 100644 --- a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApiShared.cs +++ b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApiShared.cs @@ -1,10 +1,14 @@ using CryptoExchange.Net.SharedApis.Interfaces.Socket; +using CryptoExchange.Net.SharedApis.Interfaces.Socket.Spot; using System; using System.Collections.Generic; using System.Text; namespace Binance.Net.Interfaces.Clients.SpotApi { + /// + /// Shared interface for Spot socket API usage + /// public interface IBinanceSocketClientSpotApiShared : ITickerSocketClient, ITickersSocketClient, diff --git a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApi.cs b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApi.cs index 9ead0abb9..6380fd16f 100644 --- a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApi.cs +++ b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApi.cs @@ -23,11 +23,13 @@ public interface IBinanceRestClientUsdFuturesApi : IRestApiClient, IDisposable public IBinanceRestClientUsdFuturesApiTrading Trading { get; } /// - /// Get the IFuturesClient for this client. This is a common interface which allows for some basic operations without knowing any details of the exchange. + /// DEPRECATED, use SharedClient instead /// - /// public IFuturesClient CommonFuturesClient { get; } + /// + /// Get the shared rest requests client + /// public IBinanceRestClientUsdFuturesApiShared SharedClient { get; } } } diff --git a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs index 10ffe48ca..fc2a53fd9 100644 --- a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs @@ -1,4 +1,4 @@ -using CryptoExchange.Net.SharedApis.Interfaces; +using CryptoExchange.Net.SharedApis.Interfaces.Rest; using CryptoExchange.Net.SharedApis.Interfaces.Rest.Futures; using CryptoExchange.Net.SharedApis.Interfaces.Rest.Spot; using System; @@ -7,6 +7,9 @@ namespace Binance.Net.Interfaces.Clients.UsdFuturesApi { + /// + /// Shared interface for USD-M Futures rest API usage + /// public interface IBinanceRestClientUsdFuturesApiShared : IBalanceRestClient, IFuturesTickerRestClient, diff --git a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceSocketClientUsdFuturesApi.cs b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceSocketClientUsdFuturesApi.cs index ef1518191..3084a797f 100644 --- a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceSocketClientUsdFuturesApi.cs +++ b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceSocketClientUsdFuturesApi.cs @@ -11,6 +11,9 @@ namespace Binance.Net.Interfaces.Clients.UsdFuturesApi /// public interface IBinanceSocketClientUsdFuturesApi : ISocketApiClient, IDisposable { + /// + /// Get the shared socket subscription client + /// IBinanceSocketClientUsdFuturesApiShared SharedClient { get; } /// diff --git a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceSocketClientUsdFuturesApiShared.cs b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceSocketClientUsdFuturesApiShared.cs index 1c4ad4afe..bed9efcf0 100644 --- a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceSocketClientUsdFuturesApiShared.cs +++ b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceSocketClientUsdFuturesApiShared.cs @@ -6,6 +6,9 @@ namespace Binance.Net.Interfaces.Clients.UsdFuturesApi { + /// + /// Shared interface for USD-M Futures socket API usage + /// public interface IBinanceSocketClientUsdFuturesApiShared: ITickerSocketClient, ITickersSocketClient, diff --git a/Binance.Net/Objects/Models/Spot/BinanceWithdrawalPlaced.cs b/Binance.Net/Objects/Models/Spot/BinanceWithdrawalPlaced.cs index cff1f5b2b..a00b89b84 100644 --- a/Binance.Net/Objects/Models/Spot/BinanceWithdrawalPlaced.cs +++ b/Binance.Net/Objects/Models/Spot/BinanceWithdrawalPlaced.cs @@ -9,6 +9,6 @@ public record BinanceWithdrawalPlaced /// The id /// [JsonPropertyName("id")] - public string Id { get; set; } + public string Id { get; set; } = string.Empty; } } From 241f052ef7b7c96cf1d5aed2f1f46f3321a2192e Mon Sep 17 00:00:00 2001 From: Jkorf Date: Mon, 23 Sep 2024 15:47:14 +0200 Subject: [PATCH 44/54] wip --- .../BinanceRestClientCoinFuturesApiShared.cs | 90 ++++++++++--------- ...BinanceSocketClientCoinFuturesApiShared.cs | 12 +-- .../SpotApi/BinanceRestClientSpotApiShared.cs | 26 +++--- .../BinanceSocketClientSpotApiShared.cs | 12 +-- .../BinanceRestClientUsdFuturesApiShared.cs | 89 +++++++++--------- .../BinanceSocketClientUsdFuturesApiShared.cs | 16 ++-- 6 files changed, 125 insertions(+), 120 deletions(-) diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs index 93d16fe24..f2bf15929 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -35,7 +35,7 @@ async Task>> IKlineRestClient.GetKlin if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -76,7 +76,7 @@ async Task>> IKlineRestClient.GetKlin nextToken = new DateTimeToken(minOpenTime.AddSeconds(-(int)interval)); } - return result.AsExchangeResult>(Exchange, request.Symbol.ApiType, result.Data.Reverse().Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)).ToArray(), nextToken); + return result.AsExchangeResult>(Exchange, request.Symbol.TradingMode, result.Data.Reverse().Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)).ToArray(), nextToken); } #endregion @@ -115,7 +115,7 @@ async Task>> IFuturesSymbolRe EndpointOptions IFuturesTickerRestClient.GetFuturesTickerOptions { get; } = new EndpointOptions(false); async Task> IFuturesTickerRestClient.GetFuturesTickerAsync(GetTickerRequest request, CancellationToken ct) { - var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickerOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -133,7 +133,7 @@ async Task> IFuturesTickerRestClient.GetF if (ticker == null || mark == null) return resultTicker.Result.AsExchangeError(Exchange, new ServerError("Not found")); - return resultTicker.Result.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedFuturesTicker(ticker.Symbol, ticker.LastPrice, ticker.HighPrice, ticker.LowPrice, ticker.Volume, ticker.PriceChangePercent) + return resultTicker.Result.AsExchangeResult(Exchange, request.Symbol.TradingMode, new SharedFuturesTicker(ticker.Symbol, ticker.LastPrice, ticker.HighPrice, ticker.LowPrice, ticker.Volume, ticker.PriceChangePercent) { IndexPrice = mark.IndexPrice, MarkPrice = mark.MarkPrice, @@ -157,7 +157,11 @@ async Task>> IFuturesTickerRe if (!resultMarkPrices.Result) return resultMarkPrices.Result.AsExchangeResult>(Exchange, null, default); - return resultTickers.Result.AsExchangeResult>(Exchange, SupportedTradingModes, resultTickers.Result.Data.Select(x => + var data = resultTickers.Result.Data; + if (request.TradingMode != null) + data = data.Where(x => request.TradingMode == TradingMode.PerpetualInverse ? x.Symbol.Contains("_PERP") : !x.Symbol.Contains("_PERP")); + + return resultTickers.Result.AsExchangeResult>(Exchange, SupportedTradingModes, data.Select(x => { var markPrice = resultMarkPrices.Result.Data.Single(p => p.Symbol == x.Symbol); return new SharedFuturesTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume, x.PriceChangePercent) @@ -177,7 +181,7 @@ async Task>> IFuturesTickerRe GetRecentTradesOptions IRecentTradeRestClient.GetRecentTradesOptions { get; } = new GetRecentTradesOptions(1000, false); async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, CancellationToken ct) { - var validationError = ((IRecentTradeRestClient)this).GetRecentTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IRecentTradeRestClient)this).GetRecentTradesOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -188,7 +192,7 @@ async Task>> IRecentTradeRestClient.G if (!result) return result.AsExchangeResult>(Exchange, null, default); - return result.AsExchangeResult>(Exchange, request.Symbol.ApiType, 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)).ToArray()); } #endregion @@ -212,7 +216,7 @@ async Task> IFuturesOrderRestClient.PlaceFuturesOrde var validationError = ((IFuturesOrderRestClient)this).PlaceFuturesOrderOptions.ValidateRequest( Exchange, request, - request.Symbol.ApiType, + request.Symbol.TradingMode, SupportedTradingModes, ((ISpotOrderRestClient)this).SpotSupportedOrderTypes, ((ISpotOrderRestClient)this).SpotSupportedTimeInForce, @@ -235,13 +239,13 @@ async Task> IFuturesOrderRestClient.PlaceFuturesOrde if (!result) return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedId(result.Data.Id.ToString())); + return result.AsExchangeResult(Exchange, request.Symbol.TradingMode, new SharedId(result.Data.Id.ToString())); } EndpointOptions IFuturesOrderRestClient.GetFuturesOrderOptions { get; } = new EndpointOptions(true); async Task> IFuturesOrderRestClient.GetFuturesOrderAsync(GetOrderRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -252,7 +256,7 @@ async Task> IFuturesOrderRestClient.GetFut if (!order) return order.AsExchangeResult(Exchange, null, default); - return order.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedFuturesOrder( + return order.AsExchangeResult(Exchange, request.Symbol.TradingMode, new SharedFuturesOrder( order.Data.Symbol, order.Data.Id.ToString(), ParseOrderType(order.Data.Type), @@ -276,7 +280,7 @@ async Task> IFuturesOrderRestClient.GetFut EndpointOptions IFuturesOrderRestClient.GetOpenFuturesOrdersOptions { get; } = new EndpointOptions(true); async Task>> IFuturesOrderRestClient.GetOpenFuturesOrdersAsync(GetOpenOrdersRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetOpenFuturesOrdersOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.TradingMode!.Value, SupportedTradingModes); + var validationError = ((IFuturesOrderRestClient)this).GetOpenFuturesOrdersOptions.ValidateRequest(Exchange, request, request.Symbol?.TradingMode ?? request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -285,7 +289,7 @@ async Task>> IFuturesOrderRest if (!orders) return orders.AsExchangeResult>(Exchange, null, default); - return orders.AsExchangeResult>(Exchange, SupportedTradingModes, orders.Data.Select(x => new SharedFuturesOrder( + return orders.AsExchangeResult>(Exchange, request.Symbol == null ? SupportedTradingModes : new[] { request.Symbol.TradingMode }, orders.Data.Select(x => new SharedFuturesOrder( x.Symbol, x.Id.ToString(), ParseOrderType(x.Type), @@ -309,7 +313,7 @@ async Task>> IFuturesOrderRest PaginatedEndpointOptions IFuturesOrderRestClient.GetClosedFuturesOrdersOptions { get; } = new PaginatedEndpointOptions(SharedPaginationSupport.Descending, true); async Task>> IFuturesOrderRestClient.GetClosedFuturesOrdersAsync(GetClosedOrdersRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetClosedFuturesOrdersOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IFuturesOrderRestClient)this).GetClosedFuturesOrdersOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -356,7 +360,7 @@ async Task>> IFuturesOrderRest EndpointOptions IFuturesOrderRestClient.GetFuturesOrderTradesOptions { get; } = new EndpointOptions(true); async Task>> IFuturesOrderRestClient.GetFuturesOrderTradesAsync(GetOrderTradesRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderTradesOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -367,7 +371,7 @@ async Task>> IFuturesOrderRestCli if (!orders) return orders.AsExchangeResult>(Exchange, null, default); - return orders.AsExchangeResult>(Exchange, request.Symbol.ApiType, orders.Data.Select(x => new SharedUserTrade( + return orders.AsExchangeResult>(Exchange, request.Symbol.TradingMode, orders.Data.Select(x => new SharedUserTrade( x.Symbol, x.OrderId.ToString(), x.Id.ToString(), @@ -386,7 +390,7 @@ async Task>> IFuturesOrderRestCli PaginatedEndpointOptions IFuturesOrderRestClient.GetFuturesUserTradesOptions { get; } = new PaginatedEndpointOptions(SharedPaginationSupport.Descending, true); async Task>> IFuturesOrderRestClient.GetFuturesUserTradesAsync(GetUserTradesRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetFuturesUserTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IFuturesOrderRestClient)this).GetFuturesUserTradesOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -411,7 +415,7 @@ async Task>> IFuturesOrderRestCli if (orders.Data.Count() == (request.Limit ?? 500)) nextToken = new FromIdToken(orders.Data.Max(o => o.Id).ToString()); - return orders.AsExchangeResult>(Exchange, request.Symbol.ApiType, orders.Data.Select(x => new SharedUserTrade( + return orders.AsExchangeResult>(Exchange, request.Symbol.TradingMode, orders.Data.Select(x => new SharedUserTrade( x.Symbol, x.OrderId.ToString(), x.Id.ToString(), @@ -430,7 +434,7 @@ async Task>> IFuturesOrderRestCli EndpointOptions IFuturesOrderRestClient.CancelFuturesOrderOptions { get; } = new EndpointOptions(true); async Task> IFuturesOrderRestClient.CancelFuturesOrderAsync(CancelOrderRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).CancelFuturesOrderOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IFuturesOrderRestClient)this).CancelFuturesOrderOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -441,13 +445,13 @@ async Task> IFuturesOrderRestClient.CancelFuturesOrd if (!order) return order.AsExchangeResult(Exchange, null, default); - return order.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedId(order.Data.Id.ToString())); + return order.AsExchangeResult(Exchange, request.Symbol.TradingMode, new SharedId(order.Data.Id.ToString())); } EndpointOptions IFuturesOrderRestClient.GetPositionsOptions { get; } = new EndpointOptions(true); async Task>> IFuturesOrderRestClient.GetPositionsAsync(GetPositionsRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetPositionsOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.TradingMode, SupportedTradingModes); + var validationError = ((IFuturesOrderRestClient)this).GetPositionsOptions.ValidateRequest(Exchange, request, request.Symbol?.TradingMode ?? request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -456,7 +460,7 @@ async Task>> IFuturesOrderRestClie if (!result) return result.AsExchangeResult>(Exchange, null, default); - return result.AsExchangeResult>(Exchange, request.Symbol == null ? SupportedTradingModes : new[] { request.Symbol.ApiType }, result.Data.Select(x => new SharedPosition(x.Symbol, Math.Abs(x.Quantity), x.UpdateTime) + return result.AsExchangeResult>(Exchange, request.Symbol == null ? SupportedTradingModes : new[] { request.Symbol.TradingMode }, result.Data.Select(x => new SharedPosition(x.Symbol, Math.Abs(x.Quantity), x.UpdateTime) { UnrealizedPnl = x.UnrealizedPnl, LiquidationPrice = x.LiquidationPrice == 0 ? null : x.LiquidationPrice, @@ -476,7 +480,7 @@ async Task>> IFuturesOrderRestClie }; async Task> IFuturesOrderRestClient.ClosePositionAsync(ClosePositionRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).ClosePositionOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IFuturesOrderRestClient)this).ClosePositionOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -496,7 +500,7 @@ async Task> IFuturesOrderRestClient.ClosePositionAsy if (!result) return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedId(result.Data.Id.ToString())); + return result.AsExchangeResult(Exchange, request.Symbol.TradingMode, new SharedId(result.Data.Id.ToString())); } private TimeInForce? GetTimeInForce(SharedOrderType type, SharedTimeInForce? tif) @@ -541,7 +545,7 @@ private SharedOrderType ParseOrderType(FuturesOrderType type) EndpointOptions ILeverageRestClient.GetLeverageOptions { get; } = new EndpointOptions(true); async Task> ILeverageRestClient.GetLeverageAsync(GetLeverageRequest request, CancellationToken ct) { - var validationError = ((ILeverageRestClient)this).GetLeverageOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((ILeverageRestClient)this).GetLeverageOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -554,7 +558,7 @@ async Task> ILeverageRestClient.GetLeverageAsy return result.AsExchangeError(Exchange, new ServerError("Not found")); var data = result.Data.Where(x => x.Symbol == symbol).ToList(); - return result.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedLeverage(data.First().Leverage) + return result.AsExchangeResult(Exchange, request.Symbol.TradingMode, new SharedLeverage(data.First().Leverage) { Side = request.PositionSide }); @@ -563,7 +567,7 @@ async Task> ILeverageRestClient.GetLeverageAsy SetLeverageOptions ILeverageRestClient.SetLeverageOptions { get; } = new SetLeverageOptions(); async Task> ILeverageRestClient.SetLeverageAsync(SetLeverageRequest request, CancellationToken ct) { - var validationError = ((ILeverageRestClient)this).SetLeverageOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((ILeverageRestClient)this).SetLeverageOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -571,7 +575,7 @@ async Task> ILeverageRestClient.SetLeverageAsy if (!result) return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedLeverage(result.Data.Leverage)); + return result.AsExchangeResult(Exchange, request.Symbol.TradingMode, new SharedLeverage(result.Data.Leverage)); } #endregion @@ -588,7 +592,7 @@ async Task>> IMarkPriceKlineRe if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IMarkPriceKlineRestClient)this).GetMarkPriceKlinesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IMarkPriceKlineRestClient)this).GetMarkPriceKlinesOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -629,7 +633,7 @@ async Task>> IMarkPriceKlineRe nextToken = new DateTimeToken(minOpenTime.AddSeconds(-(int)(interval - 1))); } - return result.AsExchangeResult>(Exchange, request.Symbol.ApiType, result.Data.Reverse().Select(x => new SharedFuturesKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)).ToArray(), nextToken); + return result.AsExchangeResult>(Exchange, request.Symbol.TradingMode, result.Data.Reverse().Select(x => new SharedFuturesKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)).ToArray(), nextToken); } #endregion @@ -638,7 +642,7 @@ async Task>> IMarkPriceKlineRe GetOrderBookOptions IOrderBookRestClient.GetOrderBookOptions { get; } = new GetOrderBookOptions(new[] { 5, 10, 20, 50, 100, 500, 1000 }, false); async Task> IOrderBookRestClient.GetOrderBookAsync(GetOrderBookRequest request, CancellationToken ct) { - var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -649,7 +653,7 @@ async Task> IOrderBookRestClient.GetOrderBook if (!result) return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedOrderBook(result.Data.Asks, result.Data.Bids)); + return result.AsExchangeResult(Exchange, request.Symbol.TradingMode, new SharedOrderBook(result.Data.Asks, result.Data.Bids)); } #endregion @@ -659,7 +663,7 @@ async Task> IOrderBookRestClient.GetOrderBook async Task>> ITradeHistoryRestClient.GetTradeHistoryAsync(GetTradeHistoryRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((ITradeHistoryRestClient)this).GetTradeHistoryOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((ITradeHistoryRestClient)this).GetTradeHistoryOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -683,7 +687,7 @@ async Task>> ITradeHistoryRestClient. nextToken = new FromIdToken(result.Data.Max(x => x.Id).ToString()); // Return - return result.AsExchangeResult>(Exchange, request.Symbol.ApiType, 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)).ToArray(), nextToken); } #endregion @@ -700,7 +704,7 @@ async Task>> IIndexPriceKlineR if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IIndexPriceKlineRestClient)this).GetIndexPriceKlinesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IIndexPriceKlineRestClient)this).GetIndexPriceKlinesOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -741,7 +745,7 @@ async Task>> IIndexPriceKlineR nextToken = new DateTimeToken(minOpenTime.AddSeconds(-(int)(interval - 1))); } - return result.AsExchangeResult>(Exchange, request.Symbol.ApiType, result.Data.Reverse().Select(x => new SharedFuturesKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)).ToArray(), nextToken); + return result.AsExchangeResult>(Exchange, request.Symbol.TradingMode, result.Data.Reverse().Select(x => new SharedFuturesKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)).ToArray(), nextToken); } #endregion @@ -751,7 +755,7 @@ async Task>> IIndexPriceKlineR EndpointOptions IOpenInterestRestClient.GetOpenInterestOptions { get; } = new EndpointOptions(false); async Task> IOpenInterestRestClient.GetOpenInterestAsync(GetOpenInterestRequest request, CancellationToken ct) { - var validationError = ((IOpenInterestRestClient)this).GetOpenInterestOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IOpenInterestRestClient)this).GetOpenInterestOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -759,7 +763,7 @@ async Task> IOpenInterestRestClient.GetOpe if (!result) return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedOpenInterest(result.Data.OpenInterest)); + return result.AsExchangeResult(Exchange, request.Symbol.TradingMode, new SharedOpenInterest(result.Data.OpenInterest)); } #endregion @@ -769,7 +773,7 @@ async Task> IOpenInterestRestClient.GetOpe async Task>> IFundingRateRestClient.GetFundingRateHistoryAsync(GetFundingRateHistoryRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((IFundingRateRestClient)this).GetFundingRateHistoryOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IFundingRateRestClient)this).GetFundingRateHistoryOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -789,10 +793,10 @@ async Task>> IFundingRateRestCl DateTimeToken? nextToken = null; if (result.Data.Count() == (request.Limit ?? 1000)) - nextToken = new DateTimeToken(result.Data.Max(x => x.FundingTime)); + nextToken = new DateTimeToken(result.Data.Max(x => x.FundingTime).AddSeconds(1)); // Return - return result.AsExchangeResult>(Exchange, request.Symbol.ApiType, result.Data.Select(x => new SharedFundingRate(x.FundingRate, x.FundingTime)).ToArray(), nextToken); + return result.AsExchangeResult>(Exchange, request.Symbol.TradingMode, result.Data.Select(x => new SharedFundingRate(x.FundingRate, x.FundingTime)).ToArray(), nextToken); } #endregion @@ -821,7 +825,7 @@ async Task>> IBalanceRestClient.Get GetPositionModeOptions IPositionModeRestClient.GetPositionModeOptions { get; } = new GetPositionModeOptions(); async Task> IPositionModeRestClient.GetPositionModeAsync(GetPositionModeRequest request, CancellationToken ct) { - var validationError = ((IPositionModeRestClient)this).GetPositionModeOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.TradingMode, SupportedTradingModes); + var validationError = ((IPositionModeRestClient)this).GetPositionModeOptions.ValidateRequest(Exchange, request, request.Symbol?.TradingMode ?? request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -835,7 +839,7 @@ async Task> IPositionModeRestClient. SetPositionModeOptions IPositionModeRestClient.SetPositionModeOptions { get; } = new SetPositionModeOptions(); async Task> IPositionModeRestClient.SetPositionModeAsync(SetPositionModeRequest request, CancellationToken ct) { - var validationError = ((IPositionModeRestClient)this).SetPositionModeOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.TradingMode, SupportedTradingModes); + var validationError = ((IPositionModeRestClient)this).SetPositionModeOptions.ValidateRequest(Exchange, request, request.Symbol?.TradingMode ?? request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs index aa7a8a607..dd0e34e7d 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs @@ -29,7 +29,7 @@ internal partial class BinanceSocketClientCoinFuturesApi : IBinanceSocketClientC EndpointOptions ITickerSocketClient.SubscribeTickerOptions { get; } = new EndpointOptions(false); async Task> ITickerSocketClient.SubscribeToTickerUpdatesAsync(SubscribeTickerRequest request, Action> handler, CancellationToken ct) { - var validationError = ((ITickerSocketClient)this).SubscribeTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((ITickerSocketClient)this).SubscribeTickerOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -72,12 +72,12 @@ async Task> ITickersSocketClient.SubscribeToA EndpointOptions ITradeSocketClient.SubscribeTradeOptions { get; } = new EndpointOptions(false); async Task> ITradeSocketClient.SubscribeToTradeUpdatesAsync(SubscribeTradeRequest request, Action>> handler, CancellationToken ct) { - var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) 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.Price, update.Data.Quantity, 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) })), ct:ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); } @@ -89,7 +89,7 @@ async Task> ITradeSocketClient.SubscribeToTra EndpointOptions IBookTickerSocketClient.SubscribeBookTickerOptions { get; } = new EndpointOptions(false); async Task> IBookTickerSocketClient.SubscribeToBookTickerUpdatesAsync(SubscribeBookTickerRequest request, Action> handler, CancellationToken ct) { - var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -109,7 +109,7 @@ async Task> IKlineSocketClient.SubscribeToKli if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeResult(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -124,7 +124,7 @@ async Task> IKlineSocketClient.SubscribeToKli SubscribeOrderBookOptions IOrderBookSocketClient.SubscribeOrderBookOptions { get; } = new SubscribeOrderBookOptions(false, new[] { 5, 10, 20 }); async Task> IOrderBookSocketClient.SubscribeToOrderBookUpdatesAsync(SubscribeOrderBookRequest request, Action> handler, CancellationToken ct) { - var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index 7ca8d0f87..47330df5b 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -33,7 +33,7 @@ async Task>> IKlineRestClient.GetKlin if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -75,7 +75,7 @@ async Task>> IKlineRestClient.GetKlin nextToken = new DateTimeToken(minOpenTime.AddSeconds(-(int)(interval - 1))); } - return result.AsExchangeResult>(Exchange, request.Symbol.ApiType, result.Data.Reverse().Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)).ToArray(), nextToken); + return result.AsExchangeResult>(Exchange, request.Symbol.TradingMode, result.Data.Reverse().Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)).ToArray(), nextToken); } #endregion @@ -110,7 +110,7 @@ async Task>> ISpotSymbolRestClie EndpointOptions ISpotTickerRestClient.GetSpotTickerOptions { get; } = new EndpointOptions(false); async Task> ISpotTickerRestClient.GetSpotTickerAsync(GetTickerRequest request, CancellationToken ct) { - var validationError = ((ISpotTickerRestClient)this).GetSpotTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((ISpotTickerRestClient)this).GetSpotTickerOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -142,7 +142,7 @@ async Task>> ISpotTickerRestClie async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, CancellationToken ct) { - var validationError = ((IRecentTradeRestClient)this).GetRecentTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IRecentTradeRestClient)this).GetRecentTradesOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -164,7 +164,7 @@ async Task>> IRecentTradeRestClient.G async Task>> ITradeHistoryRestClient.GetTradeHistoryAsync(GetTradeHistoryRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((ITradeHistoryRestClient)this).GetTradeHistoryOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((ITradeHistoryRestClient)this).GetTradeHistoryOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -196,7 +196,7 @@ async Task>> ITradeHistoryRestClient. GetOrderBookOptions IOrderBookRestClient.GetOrderBookOptions { get; } = new GetOrderBookOptions(1, 5000, false); async Task> IOrderBookRestClient.GetOrderBookAsync(GetOrderBookRequest request, CancellationToken ct) { - var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -249,7 +249,7 @@ async Task> ISpotOrderRestClient.PlaceSpotOrderAsync var validationError = ((ISpotOrderRestClient)this).PlaceSpotOrderOptions.ValidateRequest( Exchange, request, - request.Symbol.ApiType, + request.Symbol.TradingMode, SupportedTradingModes, ((ISpotOrderRestClient)this).SpotSupportedOrderTypes, ((ISpotOrderRestClient)this).SpotSupportedTimeInForce, @@ -277,7 +277,7 @@ async Task> ISpotOrderRestClient.PlaceSpotOrderAsync EndpointOptions ISpotOrderRestClient.GetSpotOrderOptions { get; } = new EndpointOptions(true); async Task> ISpotOrderRestClient.GetSpotOrderAsync(GetOrderRequest request, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetSpotOrderOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((ISpotOrderRestClient)this).GetSpotOrderOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -311,7 +311,7 @@ async Task> ISpotOrderRestClient.GetSpotOrder EndpointOptions ISpotOrderRestClient.GetOpenSpotOrdersOptions { get; } = new EndpointOptions(true); async Task>> ISpotOrderRestClient.GetOpenSpotOrdersAsync(GetOpenOrdersRequest request, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetOpenSpotOrdersOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.TradingMode!.Value, SupportedTradingModes); + var validationError = ((ISpotOrderRestClient)this).GetOpenSpotOrdersOptions.ValidateRequest(Exchange, request, request.Symbol?.TradingMode ?? request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -343,7 +343,7 @@ async Task>> ISpotOrderRestClient PaginatedEndpointOptions ISpotOrderRestClient.GetClosedSpotOrdersOptions { get; } = new PaginatedEndpointOptions(SharedPaginationSupport.Ascending, true); async Task>> ISpotOrderRestClient.GetClosedSpotOrdersAsync(GetClosedOrdersRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetClosedSpotOrdersOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((ISpotOrderRestClient)this).GetClosedSpotOrdersOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -389,7 +389,7 @@ async Task>> ISpotOrderRestClient EndpointOptions ISpotOrderRestClient.GetSpotOrderTradesOptions { get; } = new EndpointOptions(true); async Task>> ISpotOrderRestClient.GetSpotOrderTradesAsync(GetOrderTradesRequest request, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetSpotOrderTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((ISpotOrderRestClient)this).GetSpotOrderTradesOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -417,7 +417,7 @@ async Task>> ISpotOrderRestClient PaginatedEndpointOptions ISpotOrderRestClient.GetSpotUserTradesOptions { get; } = new PaginatedEndpointOptions(SharedPaginationSupport.Descending, true); async Task>> ISpotOrderRestClient.GetSpotUserTradesAsync(GetUserTradesRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetSpotUserTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((ISpotOrderRestClient)this).GetSpotUserTradesOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -458,7 +458,7 @@ async Task>> ISpotOrderRestClient EndpointOptions ISpotOrderRestClient.CancelSpotOrderOptions { get; } = new EndpointOptions(true); async Task> ISpotOrderRestClient.CancelSpotOrderAsync(CancelOrderRequest request, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).CancelSpotOrderOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((ISpotOrderRestClient)this).CancelSpotOrderOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs index 0f1d313a4..be6e43392 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs @@ -42,7 +42,7 @@ async Task> ITickersSocketClient.SubscribeToA EndpointOptions ITickerSocketClient.SubscribeTickerOptions { get; } = new EndpointOptions(false); async Task> ITickerSocketClient.SubscribeToTickerUpdatesAsync(SubscribeTickerRequest request, Action> handler, CancellationToken ct) { - var validationError = ((ITickerSocketClient)this).SubscribeTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((ITickerSocketClient)this).SubscribeTickerOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -58,12 +58,12 @@ async Task> ITickerSocketClient.SubscribeToTi EndpointOptions ITradeSocketClient.SubscribeTradeOptions { get; } = new EndpointOptions(false); async Task> ITradeSocketClient.SubscribeToTradeUpdatesAsync(SubscribeTradeRequest request, Action>> handler, CancellationToken ct) { - var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) 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.Price, update.Data.Quantity, 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) })), ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); } @@ -75,7 +75,7 @@ async Task> ITradeSocketClient.SubscribeToTra EndpointOptions IBookTickerSocketClient.SubscribeBookTickerOptions { get; } = new EndpointOptions(false); async Task> IBookTickerSocketClient.SubscribeToBookTickerUpdatesAsync(SubscribeBookTickerRequest request, Action> handler, CancellationToken ct) { - var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -165,7 +165,7 @@ async Task> IKlineSocketClient.SubscribeToKli if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeResult(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -180,7 +180,7 @@ async Task> IKlineSocketClient.SubscribeToKli SubscribeOrderBookOptions IOrderBookSocketClient.SubscribeOrderBookOptions { get; } = new SubscribeOrderBookOptions(false, new[] { 5, 10, 20 }); async Task> IOrderBookSocketClient.SubscribeToOrderBookUpdatesAsync(SubscribeOrderBookRequest request, Action> handler, CancellationToken ct) { - var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs index ca7a1d618..60cea1fd6 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -37,7 +37,7 @@ async Task>> IKlineRestClient.GetKlin if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -78,7 +78,7 @@ async Task>> IKlineRestClient.GetKlin nextToken = new DateTimeToken(minOpenTime.AddSeconds(-(int)(interval - 1))); } - return result.AsExchangeResult>(Exchange, request.Symbol.ApiType, result.Data.Reverse().Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)).ToArray(), nextToken); + return result.AsExchangeResult>(Exchange, request.Symbol.TradingMode, result.Data.Reverse().Select(x => new SharedKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)).ToArray(), nextToken); } #endregion @@ -96,7 +96,7 @@ async Task>> IMarkPriceKlineRe if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IMarkPriceKlineRestClient)this).GetMarkPriceKlinesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IMarkPriceKlineRestClient)this).GetMarkPriceKlinesOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -137,7 +137,7 @@ async Task>> IMarkPriceKlineRe nextToken = new DateTimeToken(minOpenTime.AddSeconds(-(int)(interval - 1))); } - return result.AsExchangeResult>(Exchange, request.Symbol.ApiType, result.Data.Reverse().Select(x => new SharedFuturesKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)).ToArray(), nextToken); + return result.AsExchangeResult>(Exchange, request.Symbol.TradingMode, result.Data.Reverse().Select(x => new SharedFuturesKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)).ToArray(), nextToken); } #endregion @@ -165,7 +165,7 @@ async Task>> IFuturesSymbolRe QuantityStep = s.LotSizeFilter?.StepSize, PriceStep = s.PriceFilter?.TickSize, ContractSize = 1, - DeliveryTime = s.DeliveryDate + DeliveryTime = s.DeliveryDate.Year == 2100 ? null : s.DeliveryDate }).ToArray()); } @@ -176,7 +176,7 @@ async Task>> IFuturesSymbolRe EndpointOptions IFuturesTickerRestClient.GetFuturesTickerOptions { get; } = new EndpointOptions(false); async Task> IFuturesTickerRestClient.GetFuturesTickerAsync(GetTickerRequest request, CancellationToken ct) { - var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickerOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -189,7 +189,7 @@ async Task> IFuturesTickerRestClient.GetF if (!resultMarkPrice.Result) return resultMarkPrice.Result.AsExchangeResult(Exchange, null, default); - return resultTicker.Result.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedFuturesTicker(resultTicker.Result.Data.Symbol, resultTicker.Result.Data.LastPrice, resultTicker.Result.Data.HighPrice, resultTicker.Result.Data.LowPrice, resultTicker.Result.Data.Volume, resultTicker.Result.Data.PriceChangePercent) + return resultTicker.Result.AsExchangeResult(Exchange, request.Symbol.TradingMode, new SharedFuturesTicker(resultTicker.Result.Data.Symbol, resultTicker.Result.Data.LastPrice, resultTicker.Result.Data.HighPrice, resultTicker.Result.Data.LowPrice, resultTicker.Result.Data.Volume, resultTicker.Result.Data.PriceChangePercent) { MarkPrice = resultMarkPrice.Result.Data.MarkPrice, IndexPrice = resultMarkPrice.Result.Data.IndexPrice, @@ -237,7 +237,7 @@ async Task>> IFuturesTickerRe GetRecentTradesOptions IRecentTradeRestClient.GetRecentTradesOptions { get; } = new GetRecentTradesOptions(1000, false); async Task>> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, CancellationToken ct) { - var validationError = ((IRecentTradeRestClient)this).GetRecentTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IRecentTradeRestClient)this).GetRecentTradesOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -248,7 +248,7 @@ async Task>> IRecentTradeRestClient.G if (!result) return result.AsExchangeResult>(Exchange, null, default); - return result.AsExchangeResult>(Exchange, request.Symbol.ApiType, 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)).ToArray()); } #endregion @@ -272,7 +272,7 @@ async Task> IFuturesOrderRestClient.PlaceFuturesOrde var validationError = ((IFuturesOrderRestClient)this).PlaceFuturesOrderOptions.ValidateRequest( Exchange, request, - request.Symbol.ApiType, + request.Symbol.TradingMode, SupportedTradingModes, ((ISpotOrderRestClient)this).SpotSupportedOrderTypes, ((ISpotOrderRestClient)this).SpotSupportedTimeInForce, @@ -295,13 +295,13 @@ async Task> IFuturesOrderRestClient.PlaceFuturesOrde if (!result) return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedId(result.Data.Id.ToString())); + return result.AsExchangeResult(Exchange, request.Symbol.TradingMode, new SharedId(result.Data.Id.ToString())); } EndpointOptions IFuturesOrderRestClient.GetFuturesOrderOptions { get; } = new EndpointOptions(true); async Task> IFuturesOrderRestClient.GetFuturesOrderAsync(GetOrderRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -312,7 +312,7 @@ async Task> IFuturesOrderRestClient.GetFut if (!order) return order.AsExchangeResult(Exchange, null, default); - return order.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedFuturesOrder( + return order.AsExchangeResult(Exchange, request.Symbol.TradingMode, new SharedFuturesOrder( order.Data.Symbol, order.Data.Id.ToString(), ParseOrderType(order.Data.Type), @@ -336,7 +336,7 @@ async Task> IFuturesOrderRestClient.GetFut EndpointOptions IFuturesOrderRestClient.GetOpenFuturesOrdersOptions { get; } = new EndpointOptions(true); async Task>> IFuturesOrderRestClient.GetOpenFuturesOrdersAsync(GetOpenOrdersRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetOpenFuturesOrdersOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.TradingMode!.Value, SupportedTradingModes); + var validationError = ((IFuturesOrderRestClient)this).GetOpenFuturesOrdersOptions.ValidateRequest(Exchange, request, request.Symbol?.TradingMode ?? request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -345,7 +345,7 @@ async Task>> IFuturesOrderRest if (!orders) return orders.AsExchangeResult>(Exchange, null, default); - return orders.AsExchangeResult>(Exchange, SupportedTradingModes, orders.Data.Select(x => new SharedFuturesOrder( + return orders.AsExchangeResult>(Exchange, request.Symbol == null ? SupportedTradingModes : new[] { request.Symbol.TradingMode }, orders.Data.Select(x => new SharedFuturesOrder( x.Symbol, x.Id.ToString(), ParseOrderType(x.Type), @@ -369,7 +369,7 @@ async Task>> IFuturesOrderRest PaginatedEndpointOptions IFuturesOrderRestClient.GetClosedFuturesOrdersOptions { get; } = new PaginatedEndpointOptions(SharedPaginationSupport.Descending, true); async Task>> IFuturesOrderRestClient.GetClosedFuturesOrdersAsync(GetClosedOrdersRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetClosedFuturesOrdersOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IFuturesOrderRestClient)this).GetClosedFuturesOrdersOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -392,7 +392,7 @@ async Task>> IFuturesOrderRest if (orders.Data.Count() == (request.Limit ?? 1000)) nextToken = new DateTimeToken(orders.Data.Max(o => o.CreateTime)); - return orders.AsExchangeResult>(Exchange, request.Symbol.ApiType, orders.Data.Where(x => x.Status == OrderStatus.Filled || x.Status == OrderStatus.Canceled || x.Status == OrderStatus.Expired).Select(x => new SharedFuturesOrder( + return orders.AsExchangeResult>(Exchange, request.Symbol.TradingMode, orders.Data.Where(x => x.Status == OrderStatus.Filled || x.Status == OrderStatus.Canceled || x.Status == OrderStatus.Expired).Select(x => new SharedFuturesOrder( x.Symbol, x.Id.ToString(), ParseOrderType(x.Type), @@ -416,7 +416,7 @@ async Task>> IFuturesOrderRest EndpointOptions IFuturesOrderRestClient.GetFuturesOrderTradesOptions { get; } = new EndpointOptions(true); async Task>> IFuturesOrderRestClient.GetFuturesOrderTradesAsync(GetOrderTradesRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderTradesOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -427,7 +427,7 @@ async Task>> IFuturesOrderRestCli if (!orders) return orders.AsExchangeResult>(Exchange, null, default); - return orders.AsExchangeResult>(Exchange, request.Symbol.ApiType, orders.Data.Select(x => new SharedUserTrade( + return orders.AsExchangeResult>(Exchange, request.Symbol.TradingMode, orders.Data.Select(x => new SharedUserTrade( x.Symbol, x.OrderId.ToString(), x.Id.ToString(), @@ -446,7 +446,7 @@ async Task>> IFuturesOrderRestCli PaginatedEndpointOptions IFuturesOrderRestClient.GetFuturesUserTradesOptions { get; } = new PaginatedEndpointOptions(SharedPaginationSupport.Descending, true); async Task>> IFuturesOrderRestClient.GetFuturesUserTradesAsync(GetUserTradesRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetFuturesUserTradesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IFuturesOrderRestClient)this).GetFuturesUserTradesOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -471,7 +471,7 @@ async Task>> IFuturesOrderRestCli if (orders.Data.Count() == (request.Limit ?? 500)) nextToken = new FromIdToken(orders.Data.Max(o => o.Id).ToString()); - return orders.AsExchangeResult>(Exchange, request.Symbol.ApiType, orders.Data.Select(x => new SharedUserTrade( + return orders.AsExchangeResult>(Exchange, request.Symbol.TradingMode, orders.Data.Select(x => new SharedUserTrade( x.Symbol, x.OrderId.ToString(), x.Id.ToString(), @@ -490,7 +490,7 @@ async Task>> IFuturesOrderRestCli EndpointOptions IFuturesOrderRestClient.CancelFuturesOrderOptions { get; } = new EndpointOptions(true); async Task> IFuturesOrderRestClient.CancelFuturesOrderAsync(CancelOrderRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).CancelFuturesOrderOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IFuturesOrderRestClient)this).CancelFuturesOrderOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -501,13 +501,13 @@ async Task> IFuturesOrderRestClient.CancelFuturesOrd if (!order) return order.AsExchangeResult(Exchange, null, default); - return order.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedId(order.Data.Id.ToString())); + return order.AsExchangeResult(Exchange, request.Symbol.TradingMode, new SharedId(order.Data.Id.ToString())); } EndpointOptions IFuturesOrderRestClient.GetPositionsOptions { get; } = new EndpointOptions(true); async Task>> IFuturesOrderRestClient.GetPositionsAsync(GetPositionsRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetPositionsOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.TradingMode, SupportedTradingModes); + var validationError = ((IFuturesOrderRestClient)this).GetPositionsOptions.ValidateRequest(Exchange, request, request.Symbol?.TradingMode ?? request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -519,7 +519,8 @@ async Task>> IFuturesOrderRestClie if (request.TradingMode.HasValue) data = data.Where(x => request.TradingMode == TradingMode.DeliveryLinear ? x.Symbol.Contains("_") : !x.Symbol.Contains("_")); - return result.AsExchangeResult>(Exchange, request.Symbol == null ? SupportedTradingModes : new[] { request.Symbol.ApiType }, data.Select(x => new SharedPosition(x.Symbol, Math.Abs(x.Quantity), x.UpdateTime) + var resultTypes = request.Symbol == null && request.TradingMode == null ? SupportedTradingModes : request.Symbol != null ? new[] { request.Symbol.TradingMode } : new[] { request.TradingMode!.Value }; + return result.AsExchangeResult>(Exchange, resultTypes, data.Select(x => new SharedPosition(x.Symbol, Math.Abs(x.Quantity), x.UpdateTime) { UnrealizedPnl = x.UnrealizedPnl, LiquidationPrice = x.LiquidationPrice == 0 ? null: x.LiquidationPrice, @@ -539,7 +540,7 @@ async Task>> IFuturesOrderRestClie }; async Task> IFuturesOrderRestClient.ClosePositionAsync(ClosePositionRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).ClosePositionOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IFuturesOrderRestClient)this).ClosePositionOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -559,7 +560,7 @@ async Task> IFuturesOrderRestClient.ClosePositionAsy if (!result) return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedId(result.Data.Id.ToString())); + return result.AsExchangeResult(Exchange, request.Symbol.TradingMode, new SharedId(result.Data.Id.ToString())); } private TimeInForce? GetTimeInForce(SharedOrderType type, SharedTimeInForce? tif) @@ -604,7 +605,7 @@ private SharedOrderType ParseOrderType(FuturesOrderType type) EndpointOptions ILeverageRestClient.GetLeverageOptions { get; } = new EndpointOptions(true); async Task> ILeverageRestClient.GetLeverageAsync(GetLeverageRequest request, CancellationToken ct) { - var validationError = ((ILeverageRestClient)this).GetLeverageOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((ILeverageRestClient)this).GetLeverageOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -615,7 +616,7 @@ async Task> ILeverageRestClient.GetLeverageAsy if (!result.Data.Any()) return result.AsExchangeError(Exchange, new ServerError("Not found")); - return result.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedLeverage(result.Data.First().Leverage) + return result.AsExchangeResult(Exchange, request.Symbol.TradingMode, new SharedLeverage(result.Data.First().Leverage) { Side = request.PositionSide }); @@ -624,7 +625,7 @@ async Task> ILeverageRestClient.GetLeverageAsy SetLeverageOptions ILeverageRestClient.SetLeverageOptions { get; } = new SetLeverageOptions(); async Task> ILeverageRestClient.SetLeverageAsync(SetLeverageRequest request, CancellationToken ct) { - var validationError = ((ILeverageRestClient)this).SetLeverageOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((ILeverageRestClient)this).SetLeverageOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -632,7 +633,7 @@ async Task> ILeverageRestClient.SetLeverageAsy if (!result) return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedLeverage(result.Data.Leverage)); + return result.AsExchangeResult(Exchange, request.Symbol.TradingMode, new SharedLeverage(result.Data.Leverage)); } #endregion @@ -640,7 +641,7 @@ async Task> ILeverageRestClient.SetLeverageAsy GetOrderBookOptions IOrderBookRestClient.GetOrderBookOptions { get; } = new GetOrderBookOptions(new[] { 5, 10, 20, 50, 100, 500, 1000 }, false); async Task> IOrderBookRestClient.GetOrderBookAsync(GetOrderBookRequest request, CancellationToken ct) { - var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -651,7 +652,7 @@ async Task> IOrderBookRestClient.GetOrderBook if (!result) return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedOrderBook(result.Data.Asks, result.Data.Bids)); + return result.AsExchangeResult(Exchange, request.Symbol.TradingMode, new SharedOrderBook(result.Data.Asks, result.Data.Bids)); } #endregion @@ -661,7 +662,7 @@ async Task> IOrderBookRestClient.GetOrderBook async Task>> ITradeHistoryRestClient.GetTradeHistoryAsync(GetTradeHistoryRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((ITradeHistoryRestClient)this).GetTradeHistoryOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((ITradeHistoryRestClient)this).GetTradeHistoryOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -685,7 +686,7 @@ async Task>> ITradeHistoryRestClient. nextToken = new FromIdToken(result.Data.Max(x => x.Id).ToString()); // Return - return result.AsExchangeResult>(Exchange, request.Symbol.ApiType, 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)).ToArray(), nextToken); } #endregion @@ -702,7 +703,7 @@ async Task>> IIndexPriceKlineR if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeWebResult>(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IIndexPriceKlineRestClient)this).GetIndexPriceKlinesOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IIndexPriceKlineRestClient)this).GetIndexPriceKlinesOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -743,7 +744,7 @@ async Task>> IIndexPriceKlineR nextToken = new DateTimeToken(minOpenTime.AddSeconds(-(int)(interval - 1))); } - return result.AsExchangeResult>(Exchange, request.Symbol.ApiType, result.Data.Reverse().Select(x => new SharedFuturesKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)).ToArray(), nextToken); + return result.AsExchangeResult>(Exchange, request.Symbol.TradingMode, result.Data.Reverse().Select(x => new SharedFuturesKline(x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice)).ToArray(), nextToken); } #endregion @@ -753,7 +754,7 @@ async Task>> IIndexPriceKlineR EndpointOptions IOpenInterestRestClient.GetOpenInterestOptions { get; } = new EndpointOptions(true); async Task> IOpenInterestRestClient.GetOpenInterestAsync(GetOpenInterestRequest request, CancellationToken ct) { - var validationError = ((IOpenInterestRestClient)this).GetOpenInterestOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IOpenInterestRestClient)this).GetOpenInterestOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -761,7 +762,7 @@ async Task> IOpenInterestRestClient.GetOpe if (!result) return result.AsExchangeResult(Exchange, null, default); - return result.AsExchangeResult(Exchange, request.Symbol.ApiType, new SharedOpenInterest(result.Data.OpenInterest)); + return result.AsExchangeResult(Exchange, request.Symbol.TradingMode, new SharedOpenInterest(result.Data.OpenInterest)); } #endregion @@ -771,7 +772,7 @@ async Task> IOpenInterestRestClient.GetOpe async Task>> IFundingRateRestClient.GetFundingRateHistoryAsync(GetFundingRateHistoryRequest request, INextPageToken? pageToken, CancellationToken ct) { - var validationError = ((IFundingRateRestClient)this).GetFundingRateHistoryOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IFundingRateRestClient)this).GetFundingRateHistoryOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult>(Exchange, validationError); @@ -791,10 +792,10 @@ async Task>> IFundingRateRestCl DateTimeToken? nextToken = null; if (result.Data.Count() == (request.Limit ?? 1000)) - nextToken = new DateTimeToken(result.Data.Max(x => x.FundingTime)); + nextToken = new DateTimeToken(result.Data.Max(x => x.FundingTime).AddSeconds(1)); // Return - return result.AsExchangeResult>(Exchange, request.Symbol.ApiType, result.Data.Select(x => new SharedFundingRate(x.FundingRate, x.FundingTime)).ToArray(), nextToken); + return result.AsExchangeResult>(Exchange, request.Symbol.TradingMode, result.Data.Select(x => new SharedFundingRate(x.FundingRate, x.FundingTime)).ToArray(), nextToken); } #endregion @@ -822,7 +823,7 @@ async Task>> IBalanceRestClient.Get GetPositionModeOptions IPositionModeRestClient.GetPositionModeOptions { get; } = new GetPositionModeOptions(); async Task> IPositionModeRestClient.GetPositionModeAsync(GetPositionModeRequest request, CancellationToken ct) { - var validationError = ((IPositionModeRestClient)this).GetPositionModeOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.TradingMode, SupportedTradingModes); + var validationError = ((IPositionModeRestClient)this).GetPositionModeOptions.ValidateRequest(Exchange, request, request.Symbol?.TradingMode ?? request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); @@ -836,7 +837,7 @@ async Task> IPositionModeRestClient. SetPositionModeOptions IPositionModeRestClient.SetPositionModeOptions { get; } = new SetPositionModeOptions(); async Task> IPositionModeRestClient.SetPositionModeAsync(SetPositionModeRequest request, CancellationToken ct) { - var validationError = ((IPositionModeRestClient)this).SetPositionModeOptions.ValidateRequest(Exchange, request, request.Symbol?.ApiType ?? request.TradingMode, SupportedTradingModes); + var validationError = ((IPositionModeRestClient)this).SetPositionModeOptions.ValidateRequest(Exchange, request, request.Symbol?.TradingMode ?? request.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs index 6d71df401..8887590ec 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs @@ -29,12 +29,12 @@ internal partial class BinanceSocketClientUsdFuturesApi : IBinanceSocketClientUs EndpointOptions ITickerSocketClient.SubscribeTickerOptions { get; } = new EndpointOptions(false); async Task> ITickerSocketClient.SubscribeToTickerUpdatesAsync(SubscribeTickerRequest request, Action> handler, CancellationToken ct) { - var validationError = ((ITickerSocketClient)this).SubscribeTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((ITickerSocketClient)this).SubscribeTickerOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); var symbol = request.Symbol.GetSymbol(FormatSymbol); - var result = await SubscribeToTickerUpdatesAsync(symbol, update => handler(update.AsExchangeEvent(Exchange, new SharedSpotTicker(symbol, update.Data.LastPrice, update.Data.LowPrice, update.Data.HighPrice, update.Data.Volume, update.Data.PriceChangePercent))), ct: ct).ConfigureAwait(false); + var result = await SubscribeToTickerUpdatesAsync(symbol, update => handler(update.AsExchangeEvent(Exchange, new SharedSpotTicker(symbol, update.Data.LastPrice, update.Data.HighPrice, update.Data.LowPrice, update.Data.Volume, update.Data.PriceChangePercent))), ct: ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); } @@ -59,7 +59,7 @@ async Task> ITickersSocketClient.SubscribeToA if (!data.Any()) return; - handler(update.AsExchangeEvent>(Exchange, data.Select(x => new SharedSpotTicker(x.Symbol, x.LastPrice, x.LowPrice, x.HighPrice, x.Volume, x.PriceChangePercent)).ToArray())); + handler(update.AsExchangeEvent>(Exchange, data.Select(x => new SharedSpotTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume, x.PriceChangePercent)).ToArray())); }, ct: ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); @@ -72,12 +72,12 @@ async Task> ITickersSocketClient.SubscribeToA EndpointOptions ITradeSocketClient.SubscribeTradeOptions { get; } = new EndpointOptions(false); async Task> ITradeSocketClient.SubscribeToTradeUpdatesAsync(SubscribeTradeRequest request, Action>> handler, CancellationToken ct) { - var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) 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.Price, update.Data.Quantity, 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) })), ct:ct).ConfigureAwait(false); return new ExchangeResult(Exchange, result); } @@ -89,7 +89,7 @@ async Task> ITradeSocketClient.SubscribeToTra EndpointOptions IBookTickerSocketClient.SubscribeBookTickerOptions { get; } = new EndpointOptions(false); async Task> IBookTickerSocketClient.SubscribeToBookTickerUpdatesAsync(SubscribeBookTickerRequest request, Action> handler, CancellationToken ct) { - var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -180,7 +180,7 @@ async Task> IKlineSocketClient.SubscribeToKli if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) return new ExchangeResult(Exchange, new ArgumentError("Interval not supported")); - var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); @@ -195,7 +195,7 @@ async Task> IKlineSocketClient.SubscribeToKli SubscribeOrderBookOptions IOrderBookSocketClient.SubscribeOrderBookOptions { get; } = new SubscribeOrderBookOptions(false, new[] { 5, 10, 20 }); async Task> IOrderBookSocketClient.SubscribeToOrderBookUpdatesAsync(SubscribeOrderBookRequest request, Action> handler, CancellationToken ct) { - var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, request.Symbol.ApiType, SupportedTradingModes); + var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes); if (validationError != null) return new ExchangeResult(Exchange, validationError); From da9fd496af8636c8c447a8878f7838b3d7253d61 Mon Sep 17 00:00:00 2001 From: JKorf Date: Mon, 23 Sep 2024 21:31:58 +0200 Subject: [PATCH 45/54] wip --- .../BinanceRestClientCoinFuturesApiShared.cs | 8 ++++---- .../UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs index f2bf15929..ef01408e6 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -202,7 +202,7 @@ async Task>> IRecentTradeRestClient.G SharedFeeDeductionType IFuturesOrderRestClient.FuturesFeeDeductionType => SharedFeeDeductionType.AddToCost; SharedFeeAssetType IFuturesOrderRestClient.FuturesFeeAssetType => SharedFeeAssetType.BaseAsset; - IEnumerable IFuturesOrderRestClient.FuturesSupportedOrderType { get; } = new[] { SharedOrderType.Limit, SharedOrderType.Market }; + IEnumerable IFuturesOrderRestClient.FuturesSupportedOrderTypes { get; } = new[] { SharedOrderType.Limit, SharedOrderType.Market }; IEnumerable IFuturesOrderRestClient.FuturesSupportedTimeInForce { get; } = new[] { SharedTimeInForce.GoodTillCanceled, SharedTimeInForce.ImmediateOrCancel, SharedTimeInForce.FillOrKill }; SharedQuantitySupport IFuturesOrderRestClient.FuturesSupportedOrderQuantity { get; } = new SharedQuantitySupport( SharedQuantityType.Contracts, @@ -218,9 +218,9 @@ async Task> IFuturesOrderRestClient.PlaceFuturesOrde request, request.Symbol.TradingMode, SupportedTradingModes, - ((ISpotOrderRestClient)this).SpotSupportedOrderTypes, - ((ISpotOrderRestClient)this).SpotSupportedTimeInForce, - ((ISpotOrderRestClient)this).SpotSupportedOrderQuantity); + ((IFuturesOrderRestClient)this).FuturesSupportedOrderTypes, + ((IFuturesOrderRestClient)this).FuturesSupportedTimeInForce, + ((IFuturesOrderRestClient)this).FuturesSupportedOrderQuantity); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs index 60cea1fd6..db4484f99 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -258,7 +258,7 @@ async Task>> IRecentTradeRestClient.G SharedFeeDeductionType IFuturesOrderRestClient.FuturesFeeDeductionType => SharedFeeDeductionType.AddToCost; SharedFeeAssetType IFuturesOrderRestClient.FuturesFeeAssetType => SharedFeeAssetType.QuoteAsset; - IEnumerable IFuturesOrderRestClient.FuturesSupportedOrderType { get; } = new[] { SharedOrderType.Limit, SharedOrderType.Market }; + IEnumerable IFuturesOrderRestClient.FuturesSupportedOrderTypes { get; } = new[] { SharedOrderType.Limit, SharedOrderType.Market }; IEnumerable IFuturesOrderRestClient.FuturesSupportedTimeInForce { get; } = new[] { SharedTimeInForce.GoodTillCanceled, SharedTimeInForce.ImmediateOrCancel, SharedTimeInForce.FillOrKill }; SharedQuantitySupport IFuturesOrderRestClient.FuturesSupportedOrderQuantity { get; } = new SharedQuantitySupport( SharedQuantityType.Contracts, @@ -274,9 +274,9 @@ async Task> IFuturesOrderRestClient.PlaceFuturesOrde request, request.Symbol.TradingMode, SupportedTradingModes, - ((ISpotOrderRestClient)this).SpotSupportedOrderTypes, - ((ISpotOrderRestClient)this).SpotSupportedTimeInForce, - ((ISpotOrderRestClient)this).SpotSupportedOrderQuantity); + ((IFuturesOrderRestClient)this).FuturesSupportedOrderTypes, + ((IFuturesOrderRestClient)this).FuturesSupportedTimeInForce, + ((IFuturesOrderRestClient)this).FuturesSupportedOrderQuantity); if (validationError != null) return new ExchangeWebResult(Exchange, validationError); From 777fcf7f9d3cf1284499d162d72eb53e715c768e Mon Sep 17 00:00:00 2001 From: Jkorf Date: Tue, 24 Sep 2024 16:50:25 +0200 Subject: [PATCH 46/54] wip --- .../TestImplementations/BinanceRestApiClient.cs | 2 +- Binance.Net/Binance.Net.csproj | 2 +- .../BinanceRestClientCoinFuturesApiShared.cs | 14 ++++---------- .../BinanceSocketClientCoinFuturesApiShared.cs | 16 ++-------------- .../SpotApi/BinanceRestClientSpotApiShared.cs | 10 ++-------- .../SpotApi/BinanceSocketClientSpotApi.cs | 1 - .../SpotApi/BinanceSocketClientSpotApiShared.cs | 15 ++------------- .../BinanceRestClientUsdFuturesApiShared.cs | 16 +++------------- .../BinanceSocketClientUsdFuturesApiShared.cs | 15 ++------------- .../ServiceCollectionExtensions.cs | 2 -- .../IBinanceRestClientCoinFuturesApiShared.cs | 7 +------ .../IBinanceSocketClientCoinFuturesApiShared.cs | 6 +----- .../SpotApi/IBinanceRestClientSpotApiShared.cs | 6 +----- .../SpotApi/IBinanceSocketClientSpotApi.cs | 4 +--- .../SpotApi/IBinanceSocketClientSpotApiShared.cs | 6 +----- .../IBinanceRestClientUsdFuturesApiShared.cs | 7 +------ .../IBinanceSocketClientUsdFuturesApiShared.cs | 6 +----- 17 files changed, 24 insertions(+), 111 deletions(-) diff --git a/Binance.Net.UnitTests/TestImplementations/BinanceRestApiClient.cs b/Binance.Net.UnitTests/TestImplementations/BinanceRestApiClient.cs index 74859e5c5..74e23d9b5 100644 --- a/Binance.Net.UnitTests/TestImplementations/BinanceRestApiClient.cs +++ b/Binance.Net.UnitTests/TestImplementations/BinanceRestApiClient.cs @@ -14,7 +14,7 @@ public BinanceRestApiClient(ILogger logger, BinanceRestOptions options, BinanceR } /// - public override string FormatSymbol(string baseAsset, string quoteAsset) => $"{baseAsset.ToUpperInvariant()}{quoteAsset.ToUpperInvariant()}"; + public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode futuresType, DateTime? deliverDate = null) => $"{baseAsset.ToUpperInvariant()}{quoteAsset.ToUpperInvariant()}"; public override TimeSpan? GetTimeOffset() => null; public override TimeSyncInfo GetTimeSyncInfo() => null; protected override AuthenticationProvider CreateAuthenticationProvider(ApiCredentials credentials) => throw new NotImplementedException(); diff --git a/Binance.Net/Binance.Net.csproj b/Binance.Net/Binance.Net.csproj index cf42ff825..f18b09d5d 100644 --- a/Binance.Net/Binance.Net.csproj +++ b/Binance.Net/Binance.Net.csproj @@ -31,7 +31,7 @@ true - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs index ef01408e6..d8da08dec 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -1,15 +1,7 @@ using Binance.Net.Interfaces.Clients.CoinFuturesApi; using Binance.Net.Enums; -using CryptoExchange.Net.SharedApis.Enums; -using CryptoExchange.Net.SharedApis.Interfaces; -using CryptoExchange.Net.SharedApis.Models; -using CryptoExchange.Net.SharedApis.Models.Rest; -using CryptoExchange.Net.SharedApis.ResponseModels; -using CryptoExchange.Net.SharedApis.Interfaces.Rest.Futures; -using CryptoExchange.Net.SharedApis.Interfaces.Rest.Spot; -using CryptoExchange.Net.SharedApis.Models.Options.Endpoints; -using CryptoExchange.Net.SharedApis.Interfaces.Rest; -using CryptoExchange.Net.SharedApis.Models.Options; +using CryptoExchange.Net.SharedApis; +using System.Linq.Expressions; namespace Binance.Net.Clients.CoinFuturesApi { @@ -375,6 +367,7 @@ async Task>> IFuturesOrderRestCli x.Symbol, x.OrderId.ToString(), x.Id.ToString(), + x.Buyer ? SharedOrderSide.Buy : SharedOrderSide.Sell, x.Quantity, x.Price, x.Timestamp) @@ -419,6 +412,7 @@ async Task>> IFuturesOrderRestCli x.Symbol, x.OrderId.ToString(), x.Id.ToString(), + x.Buyer ? SharedOrderSide.Buy : SharedOrderSide.Sell, x.Quantity, x.Price, x.Timestamp) diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs index dd0e34e7d..d7754da10 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApiShared.cs @@ -1,18 +1,6 @@ using Binance.Net.Interfaces.Clients.CoinFuturesApi; -using Binance.Net.Interfaces.Clients.SpotApi; using CryptoExchange.Net.Objects.Sockets; -using CryptoExchange.Net.SharedApis.Enums; -using CryptoExchange.Net.SharedApis.Interfaces.Socket; -using CryptoExchange.Net.SharedApis.Interfaces.Socket.Futures; -using CryptoExchange.Net.SharedApis.Models; -using CryptoExchange.Net.SharedApis.Models.Options; -using CryptoExchange.Net.SharedApis.Models.Options.Endpoints; -using CryptoExchange.Net.SharedApis.Models.Options.Subscriptions; -using CryptoExchange.Net.SharedApis.Models.Socket; -using CryptoExchange.Net.SharedApis.ResponseModels; -using System; -using System.Collections.Generic; -using System.Text; +using CryptoExchange.Net.SharedApis; namespace Binance.Net.Clients.CoinFuturesApi { @@ -223,7 +211,7 @@ async Task> IFuturesOrderSocketClient.Subscri PositionSide = update.Data.UpdateData.PositionSide == Enums.PositionSide.Long ? SharedPositionSide.Long : update.Data.UpdateData.PositionSide == Enums.PositionSide.Short ? SharedPositionSide.Short : null, ReduceOnly = update.Data.UpdateData.IsReduce, TimeInForce = update.Data.UpdateData.TimeInForce == Enums.TimeInForce.ImmediateOrCancel ? SharedTimeInForce.ImmediateOrCancel : update.Data.UpdateData.TimeInForce == Enums.TimeInForce.FillOrKill ? SharedTimeInForce.FillOrKill : SharedTimeInForce.GoodTillCanceled, - LastTrade = update.Data.UpdateData.QuantityOfLastFilledTrade == 0 ? null : new SharedUserTrade(update.Data.UpdateData.Symbol, update.Data.UpdateData.OrderId.ToString(), update.Data.UpdateData.TradeId.ToString(), update.Data.UpdateData.QuantityOfLastFilledTrade, update.Data.UpdateData.PriceLastFilledTrade, update.Data.UpdateData.UpdateTime) + LastTrade = update.Data.UpdateData.QuantityOfLastFilledTrade == 0 ? null : new SharedUserTrade(update.Data.UpdateData.Symbol, update.Data.UpdateData.OrderId.ToString(), update.Data.UpdateData.TradeId.ToString(), update.Data.UpdateData.Side == Enums.OrderSide.Buy ? SharedOrderSide.Buy : SharedOrderSide.Sell, update.Data.UpdateData.QuantityOfLastFilledTrade, update.Data.UpdateData.PriceLastFilledTrade, update.Data.UpdateData.UpdateTime) { Role = update.Data.UpdateData.BuyerIsMaker ? SharedRole.Maker : SharedRole.Taker } diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs index 47330df5b..109a58bdf 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApiShared.cs @@ -1,14 +1,6 @@ using Binance.Net.Interfaces.Clients.SpotApi; -using CryptoExchange.Net.SharedApis.Enums; -using CryptoExchange.Net.SharedApis.Interfaces; -using CryptoExchange.Net.SharedApis.Models.Rest; -using CryptoExchange.Net.SharedApis.ResponseModels; using Binance.Net.Enums; -using CryptoExchange.Net.SharedApis.Models; -using CryptoExchange.Net.SharedApis.Interfaces.Rest.Spot; using CryptoExchange.Net.SharedApis; -using CryptoExchange.Net.SharedApis.Models.Options.Endpoints; -using CryptoExchange.Net.SharedApis.Interfaces.Rest; namespace Binance.Net.Clients.SpotApi { @@ -404,6 +396,7 @@ async Task>> ISpotOrderRestClient x.Symbol, x.OrderId.ToString(), x.Id.ToString(), + x.IsBuyer ? SharedOrderSide.Buy : SharedOrderSide.Sell, x.Quantity, x.Price, x.Timestamp) @@ -445,6 +438,7 @@ async Task>> ISpotOrderRestClient x.Symbol, x.OrderId.ToString(), x.Id.ToString(), + x.IsBuyer ? SharedOrderSide.Buy : SharedOrderSide.Sell, x.Quantity, x.Price, x.Timestamp) diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs index 521c613dd..af0518cc7 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs @@ -9,7 +9,6 @@ using CryptoExchange.Net.Clients; using CryptoExchange.Net.Converters.MessageParsing; using CryptoExchange.Net.Objects.Sockets; -using CryptoExchange.Net.SharedApis.Interfaces; using CryptoExchange.Net.Sockets; namespace Binance.Net.Clients.SpotApi diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs index be6e43392..4ff04b215 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApiShared.cs @@ -1,17 +1,6 @@ using Binance.Net.Interfaces.Clients.SpotApi; using CryptoExchange.Net.Objects.Sockets; -using CryptoExchange.Net.SharedApis.Enums; -using CryptoExchange.Net.SharedApis.Interfaces.Socket; -using CryptoExchange.Net.SharedApis.Interfaces.Socket.Spot; -using CryptoExchange.Net.SharedApis.Models; -using CryptoExchange.Net.SharedApis.Models.Options; -using CryptoExchange.Net.SharedApis.Models.Options.Endpoints; -using CryptoExchange.Net.SharedApis.Models.Options.Subscriptions; -using CryptoExchange.Net.SharedApis.Models.Socket; -using CryptoExchange.Net.SharedApis.ResponseModels; -using System; -using System.Collections.Generic; -using System.Text; +using CryptoExchange.Net.SharedApis; namespace Binance.Net.Clients.SpotApi { @@ -145,7 +134,7 @@ async Task> ISpotOrderSocketClient.SubscribeT Fee = update.Data.Fee, FeeAsset = update.Data.FeeAsset, TimeInForce = update.Data.TimeInForce == Enums.TimeInForce.ImmediateOrCancel ? SharedTimeInForce.ImmediateOrCancel : update.Data.TimeInForce == Enums.TimeInForce.FillOrKill ? SharedTimeInForce.FillOrKill : SharedTimeInForce.GoodTillCanceled, - LastTrade = update.Data.LastQuantityFilled == 0 ? null : new SharedUserTrade(update.Data.Symbol, update.Data.Id.ToString(), update.Data.TradeId.ToString(), update.Data.LastQuantityFilled, update.Data.LastPriceFilled, update.Data.UpdateTime) + LastTrade = update.Data.LastQuantityFilled == 0 ? null : new SharedUserTrade(update.Data.Symbol, update.Data.Id.ToString(), update.Data.TradeId.ToString(), update.Data.Side == Enums.OrderSide.Buy ? SharedOrderSide.Buy : SharedOrderSide.Sell, update.Data.LastQuantityFilled, update.Data.LastPriceFilled, update.Data.UpdateTime) { Role = update.Data.BuyerIsMaker ? SharedRole.Maker : SharedRole.Taker } diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs index db4484f99..6abfd831c 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -1,18 +1,6 @@ using Binance.Net.Enums; using Binance.Net.Interfaces.Clients.UsdFuturesApi; -using CryptoExchange.Net.SharedApis.Enums; -using CryptoExchange.Net.SharedApis.Interfaces; -using CryptoExchange.Net.SharedApis.Interfaces.Rest; -using CryptoExchange.Net.SharedApis.Interfaces.Rest.Futures; -using CryptoExchange.Net.SharedApis.Interfaces.Rest.Spot; -using CryptoExchange.Net.SharedApis.Models; -using CryptoExchange.Net.SharedApis.Models.Options; -using CryptoExchange.Net.SharedApis.Models.Options.Endpoints; -using CryptoExchange.Net.SharedApis.Models.Rest; -using CryptoExchange.Net.SharedApis.ResponseModels; -using System; -using System.Collections.Generic; -using System.Text; +using CryptoExchange.Net.SharedApis; namespace Binance.Net.Clients.UsdFuturesApi { @@ -431,6 +419,7 @@ async Task>> IFuturesOrderRestCli x.Symbol, x.OrderId.ToString(), x.Id.ToString(), + x.Buyer ? SharedOrderSide.Buy : SharedOrderSide.Sell, x.Quantity, x.Price, x.Timestamp) @@ -475,6 +464,7 @@ async Task>> IFuturesOrderRestCli x.Symbol, x.OrderId.ToString(), x.Id.ToString(), + x.Buyer ? SharedOrderSide.Buy : SharedOrderSide.Sell, x.Quantity, x.Price, x.Timestamp) diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs index 8887590ec..87f9f3177 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApiShared.cs @@ -1,18 +1,7 @@ using Binance.Net.Interfaces.Clients.SpotApi; using Binance.Net.Interfaces.Clients.UsdFuturesApi; using CryptoExchange.Net.Objects.Sockets; -using CryptoExchange.Net.SharedApis.Enums; -using CryptoExchange.Net.SharedApis.Interfaces.Socket; -using CryptoExchange.Net.SharedApis.Interfaces.Socket.Futures; -using CryptoExchange.Net.SharedApis.Models; -using CryptoExchange.Net.SharedApis.Models.Options; -using CryptoExchange.Net.SharedApis.Models.Options.Endpoints; -using CryptoExchange.Net.SharedApis.Models.Options.Subscriptions; -using CryptoExchange.Net.SharedApis.Models.Socket; -using CryptoExchange.Net.SharedApis.ResponseModels; -using System; -using System.Collections.Generic; -using System.Text; +using CryptoExchange.Net.SharedApis; namespace Binance.Net.Clients.UsdFuturesApi { @@ -160,7 +149,7 @@ async Task> IFuturesOrderSocketClient.Subscri PositionSide = update.Data.UpdateData.PositionSide == Enums.PositionSide.Long ? SharedPositionSide.Long : update.Data.UpdateData.PositionSide == Enums.PositionSide.Short ? SharedPositionSide.Short : null, ReduceOnly = update.Data.UpdateData.IsReduce, TimeInForce = update.Data.UpdateData.TimeInForce == Enums.TimeInForce.ImmediateOrCancel ? SharedTimeInForce.ImmediateOrCancel : update.Data.UpdateData.TimeInForce == Enums.TimeInForce.FillOrKill ? SharedTimeInForce.FillOrKill : SharedTimeInForce.GoodTillCanceled, - LastTrade = update.Data.UpdateData.QuantityOfLastFilledTrade == 0 ? null : new SharedUserTrade(update.Data.UpdateData.Symbol, update.Data.UpdateData.OrderId.ToString(), update.Data.UpdateData.TradeId.ToString(), update.Data.UpdateData.QuantityOfLastFilledTrade, update.Data.UpdateData.PriceLastFilledTrade, update.Data.UpdateData.UpdateTime) + LastTrade = update.Data.UpdateData.QuantityOfLastFilledTrade == 0 ? null : new SharedUserTrade(update.Data.UpdateData.Symbol, update.Data.UpdateData.OrderId.ToString(), update.Data.UpdateData.TradeId.ToString(), update.Data.UpdateData.Side == Enums.OrderSide.Buy ? SharedOrderSide.Buy : SharedOrderSide.Sell, update.Data.UpdateData.QuantityOfLastFilledTrade, update.Data.UpdateData.PriceLastFilledTrade, update.Data.UpdateData.UpdateTime) { Role = update.Data.UpdateData.BuyerIsMaker ? SharedRole.Maker : SharedRole.Taker } diff --git a/Binance.Net/ExtensionMethods/ServiceCollectionExtensions.cs b/Binance.Net/ExtensionMethods/ServiceCollectionExtensions.cs index 6dc845388..4bc412525 100644 --- a/Binance.Net/ExtensionMethods/ServiceCollectionExtensions.cs +++ b/Binance.Net/ExtensionMethods/ServiceCollectionExtensions.cs @@ -1,11 +1,9 @@ using Binance.Net.Clients; using Binance.Net.Interfaces; using Binance.Net.Interfaces.Clients; -using Binance.Net.Interfaces.Clients.SpotApi; using Binance.Net.Objects.Options; using Binance.Net.SymbolOrderBooks; using CryptoExchange.Net.Clients; -using CryptoExchange.Net.SharedApis.Interfaces; using System.Net; namespace Microsoft.Extensions.DependencyInjection diff --git a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs index 9f25ff325..e0816db13 100644 --- a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApiShared.cs @@ -1,9 +1,4 @@ -using CryptoExchange.Net.SharedApis.Interfaces.Rest; -using CryptoExchange.Net.SharedApis.Interfaces.Rest.Futures; -using CryptoExchange.Net.SharedApis.Interfaces.Rest.Spot; -using System; -using System.Collections.Generic; -using System.Text; +using CryptoExchange.Net.SharedApis; namespace Binance.Net.Interfaces.Clients.CoinFuturesApi { diff --git a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceSocketClientCoinFuturesApiShared.cs b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceSocketClientCoinFuturesApiShared.cs index b4145505e..19fcbc3de 100644 --- a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceSocketClientCoinFuturesApiShared.cs +++ b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceSocketClientCoinFuturesApiShared.cs @@ -1,8 +1,4 @@ -using CryptoExchange.Net.SharedApis.Interfaces.Socket; -using CryptoExchange.Net.SharedApis.Interfaces.Socket.Futures; -using System; -using System.Collections.Generic; -using System.Text; +using CryptoExchange.Net.SharedApis; namespace Binance.Net.Interfaces.Clients.CoinFuturesApi { diff --git a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs index 5d0907ce1..941b9d5f8 100644 --- a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs +++ b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApiShared.cs @@ -1,8 +1,4 @@ -using CryptoExchange.Net.SharedApis.Interfaces.Rest; -using CryptoExchange.Net.SharedApis.Interfaces.Rest.Spot; -using System; -using System.Collections.Generic; -using System.Text; +using CryptoExchange.Net.SharedApis; namespace Binance.Net.Interfaces.Clients.SpotApi { diff --git a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApi.cs b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApi.cs index 52217187d..ac5380774 100644 --- a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApi.cs +++ b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApi.cs @@ -1,6 +1,4 @@ -using CryptoExchange.Net.SharedApis.Interfaces; - -namespace Binance.Net.Interfaces.Clients.SpotApi +namespace Binance.Net.Interfaces.Clients.SpotApi { /// /// Spot API socket subscriptions and requests diff --git a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApiShared.cs b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApiShared.cs index 84182ab78..54bc39410 100644 --- a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApiShared.cs +++ b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApiShared.cs @@ -1,8 +1,4 @@ -using CryptoExchange.Net.SharedApis.Interfaces.Socket; -using CryptoExchange.Net.SharedApis.Interfaces.Socket.Spot; -using System; -using System.Collections.Generic; -using System.Text; +using CryptoExchange.Net.SharedApis; namespace Binance.Net.Interfaces.Clients.SpotApi { diff --git a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs index fc2a53fd9..00f53974f 100644 --- a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApiShared.cs @@ -1,9 +1,4 @@ -using CryptoExchange.Net.SharedApis.Interfaces.Rest; -using CryptoExchange.Net.SharedApis.Interfaces.Rest.Futures; -using CryptoExchange.Net.SharedApis.Interfaces.Rest.Spot; -using System; -using System.Collections.Generic; -using System.Text; +using CryptoExchange.Net.SharedApis; namespace Binance.Net.Interfaces.Clients.UsdFuturesApi { diff --git a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceSocketClientUsdFuturesApiShared.cs b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceSocketClientUsdFuturesApiShared.cs index bed9efcf0..a5e364d0a 100644 --- a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceSocketClientUsdFuturesApiShared.cs +++ b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceSocketClientUsdFuturesApiShared.cs @@ -1,8 +1,4 @@ -using CryptoExchange.Net.SharedApis.Interfaces.Socket; -using CryptoExchange.Net.SharedApis.Interfaces.Socket.Futures; -using System; -using System.Collections.Generic; -using System.Text; +using CryptoExchange.Net.SharedApis; namespace Binance.Net.Interfaces.Clients.UsdFuturesApi { From 161c2236f863b26f0b46a39e0caf33b77f87e998 Mon Sep 17 00:00:00 2001 From: Jkorf Date: Wed, 25 Sep 2024 16:29:01 +0200 Subject: [PATCH 47/54] wip --- Binance.Net/Binance.Net.xml | 6 +++--- .../BinanceRestClientCoinFuturesApiShared.cs | 8 ++++---- .../BinanceRestClientUsdFuturesApiShared.cs | 9 +++++---- .../CoinFuturesApi/IBinanceRestClientCoinFuturesApi.cs | 2 +- .../Clients/SpotApi/IBinanceRestClientSpotApi.cs | 2 +- .../UsdFuturesApi/IBinanceRestClientUsdFuturesApi.cs | 2 +- 6 files changed, 15 insertions(+), 14 deletions(-) diff --git a/Binance.Net/Binance.Net.xml b/Binance.Net/Binance.Net.xml index bc0da712e..a501b10a2 100644 --- a/Binance.Net/Binance.Net.xml +++ b/Binance.Net/Binance.Net.xml @@ -5488,7 +5488,7 @@ - DEPRECATED, use SharedClient instead + DEPRECATED; use instead for common/shared functionality. See for more info. @@ -8479,7 +8479,7 @@ - DEPRECATED, use SharedClient instead + DEPRECATED; use instead for common/shared functionality. See for more info. @@ -11246,7 +11246,7 @@ - DEPRECATED, use SharedClient instead + DEPRECATED; use instead for common/shared functionality. See for more info. diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs index d8da08dec..8a562cc61 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApiShared.cs @@ -197,10 +197,10 @@ async Task>> IRecentTradeRestClient.G IEnumerable IFuturesOrderRestClient.FuturesSupportedOrderTypes { get; } = new[] { SharedOrderType.Limit, SharedOrderType.Market }; IEnumerable IFuturesOrderRestClient.FuturesSupportedTimeInForce { get; } = new[] { SharedTimeInForce.GoodTillCanceled, SharedTimeInForce.ImmediateOrCancel, SharedTimeInForce.FillOrKill }; SharedQuantitySupport IFuturesOrderRestClient.FuturesSupportedOrderQuantity { get; } = new SharedQuantitySupport( - SharedQuantityType.Contracts, - SharedQuantityType.Contracts, - SharedQuantityType.Contracts, - SharedQuantityType.Contracts); + SharedQuantityType.BaseAsset, + SharedQuantityType.BaseAsset, + SharedQuantityType.BaseAsset, + SharedQuantityType.BaseAsset); PlaceFuturesOrderOptions IFuturesOrderRestClient.PlaceFuturesOrderOptions { get; } = new PlaceFuturesOrderOptions(); async Task> IFuturesOrderRestClient.PlaceFuturesOrderAsync(PlaceFuturesOrderRequest request, CancellationToken ct) diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs index 6abfd831c..f241094f3 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApiShared.cs @@ -152,6 +152,7 @@ async Task>> IFuturesSymbolRe MaxTradeQuantity = s.LotSizeFilter?.MaxQuantity, QuantityStep = s.LotSizeFilter?.StepSize, PriceStep = s.PriceFilter?.TickSize, + MinNotionalValue = s.MinNotionalFilter?.MinNotional, ContractSize = 1, DeliveryTime = s.DeliveryDate.Year == 2100 ? null : s.DeliveryDate }).ToArray()); @@ -249,10 +250,10 @@ async Task>> IRecentTradeRestClient.G IEnumerable IFuturesOrderRestClient.FuturesSupportedOrderTypes { get; } = new[] { SharedOrderType.Limit, SharedOrderType.Market }; IEnumerable IFuturesOrderRestClient.FuturesSupportedTimeInForce { get; } = new[] { SharedTimeInForce.GoodTillCanceled, SharedTimeInForce.ImmediateOrCancel, SharedTimeInForce.FillOrKill }; SharedQuantitySupport IFuturesOrderRestClient.FuturesSupportedOrderQuantity { get; } = new SharedQuantitySupport( - SharedQuantityType.Contracts, - SharedQuantityType.Contracts, - SharedQuantityType.Contracts, - SharedQuantityType.Contracts); + SharedQuantityType.BaseAsset, + SharedQuantityType.BaseAsset, + SharedQuantityType.BaseAsset, + SharedQuantityType.BaseAsset); PlaceFuturesOrderOptions IFuturesOrderRestClient.PlaceFuturesOrderOptions { get; } = new PlaceFuturesOrderOptions(); async Task> IFuturesOrderRestClient.PlaceFuturesOrderAsync(PlaceFuturesOrderRequest request, CancellationToken ct) diff --git a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApi.cs b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApi.cs index 4661e5c38..6d917bf52 100644 --- a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApi.cs +++ b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApi.cs @@ -24,7 +24,7 @@ public interface IBinanceRestClientCoinFuturesApi : IRestApiClient, IDisposable public IBinanceRestClientCoinFuturesApiTrading Trading { get; } /// - /// DEPRECATED, use SharedClient instead + /// DEPRECATED; use instead for common/shared functionality. See for more info. /// public IFuturesClient CommonFuturesClient { get; } diff --git a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApi.cs b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApi.cs index bf6b1594c..eecb2e105 100644 --- a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApi.cs +++ b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApi.cs @@ -23,7 +23,7 @@ public interface IBinanceRestClientSpotApi : IRestApiClient, IDisposable public IBinanceRestClientSpotApiTrading Trading { get; } /// - /// DEPRECATED, use SharedClient instead + /// DEPRECATED; use instead for common/shared functionality. See for more info. /// public ISpotClient CommonSpotClient { get; } diff --git a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApi.cs b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApi.cs index 6380fd16f..45aca6b4e 100644 --- a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApi.cs +++ b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApi.cs @@ -23,7 +23,7 @@ public interface IBinanceRestClientUsdFuturesApi : IRestApiClient, IDisposable public IBinanceRestClientUsdFuturesApiTrading Trading { get; } /// - /// DEPRECATED, use SharedClient instead + /// DEPRECATED; use instead for common/shared functionality. See for more info. /// public IFuturesClient CommonFuturesClient { get; } From a7c6f087fa7b34b5b5b0bb96a60530d9cce88078 Mon Sep 17 00:00:00 2001 From: JKorf Date: Wed, 25 Sep 2024 19:56:03 +0200 Subject: [PATCH 48/54] wip --- Binance.Net/Binance.Net.xml | 18 +++++++++--------- .../IBinanceRestClientCoinFuturesApi.cs | 4 ++-- .../IBinanceSocketClientCoinFuturesApi.cs | 2 +- .../SpotApi/IBinanceRestClientSpotApi.cs | 4 ++-- .../SpotApi/IBinanceSocketClientSpotApi.cs | 2 +- .../IBinanceRestClientUsdFuturesApi.cs | 4 ++-- .../IBinanceSocketClientUsdFuturesApi.cs | 2 +- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Binance.Net/Binance.Net.xml b/Binance.Net/Binance.Net.xml index a501b10a2..2395f3f66 100644 --- a/Binance.Net/Binance.Net.xml +++ b/Binance.Net/Binance.Net.xml @@ -5488,12 +5488,12 @@ - DEPRECATED; use instead for common/shared functionality. See for more info. + DEPRECATED; use instead for common/shared functionality. See for more info. - Get the shared rest requests client + Get the shared rest requests client. This interface is shared with other exhanges to allow for a common implementation for different exchanges. @@ -6141,7 +6141,7 @@ - Get the shared socket subscription client + Get the shared socket subscription client. This interface is shared with other exhanges to allow for a common implementation for different exchanges. @@ -8479,12 +8479,12 @@ - DEPRECATED; use instead for common/shared functionality. See for more info. + DEPRECATED; use instead for common/shared functionality. See for more info. - Get the shared rest requests client + Get the shared rest requests client. This interface is shared with other exhanges to allow for a common implementation for different exchanges. @@ -10490,7 +10490,7 @@ - Get the shared socket subscription client + Get the shared socket subscription client. This interface is shared with other exhanges to allow for a common implementation for different exchanges. @@ -11246,12 +11246,12 @@ - DEPRECATED; use instead for common/shared functionality. See for more info. + DEPRECATED; use instead for common/shared functionality. See for more info. - Get the shared rest requests client + Get the shared rest requests client. This interface is shared with other exhanges to allow for a common implementation for different exchanges. @@ -12242,7 +12242,7 @@ - Get the shared socket subscription client + Get the shared socket subscription client. This interface is shared with other exhanges to allow for a common implementation for different exchanges. diff --git a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApi.cs b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApi.cs index 6d917bf52..3f9336248 100644 --- a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApi.cs +++ b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceRestClientCoinFuturesApi.cs @@ -24,12 +24,12 @@ public interface IBinanceRestClientCoinFuturesApi : IRestApiClient, IDisposable public IBinanceRestClientCoinFuturesApiTrading Trading { get; } /// - /// DEPRECATED; use instead for common/shared functionality. See for more info. + /// DEPRECATED; use instead for common/shared functionality. See for more info. /// public IFuturesClient CommonFuturesClient { get; } /// - /// Get the shared rest requests client + /// Get the shared rest requests client. This interface is shared with other exhanges to allow for a common implementation for different exchanges. /// public IBinanceRestClientCoinFuturesApiShared SharedClient { get; } diff --git a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceSocketClientCoinFuturesApi.cs b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceSocketClientCoinFuturesApi.cs index 3ffccebc0..5874fb35d 100644 --- a/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceSocketClientCoinFuturesApi.cs +++ b/Binance.Net/Interfaces/Clients/CoinFuturesApi/IBinanceSocketClientCoinFuturesApi.cs @@ -12,7 +12,7 @@ namespace Binance.Net.Interfaces.Clients.CoinFuturesApi public interface IBinanceSocketClientCoinFuturesApi : ISocketApiClient, IDisposable { /// - /// Get the shared socket subscription client + /// Get the shared socket subscription client. This interface is shared with other exhanges to allow for a common implementation for different exchanges. /// IBinanceSocketClientCoinFuturesApiShared SharedClient { get; } diff --git a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApi.cs b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApi.cs index eecb2e105..87e8f180a 100644 --- a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApi.cs +++ b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceRestClientSpotApi.cs @@ -23,12 +23,12 @@ public interface IBinanceRestClientSpotApi : IRestApiClient, IDisposable public IBinanceRestClientSpotApiTrading Trading { get; } /// - /// DEPRECATED; use instead for common/shared functionality. See for more info. + /// DEPRECATED; use instead for common/shared functionality. See for more info. /// public ISpotClient CommonSpotClient { get; } /// - /// Get the shared rest requests client + /// Get the shared rest requests client. This interface is shared with other exhanges to allow for a common implementation for different exchanges. /// public IBinanceRestClientSpotApiShared SharedClient { get; } } diff --git a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApi.cs b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApi.cs index ac5380774..c90ac9f69 100644 --- a/Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApi.cs +++ b/Binance.Net/Interfaces/Clients/SpotApi/IBinanceSocketClientSpotApi.cs @@ -19,7 +19,7 @@ public interface IBinanceSocketClientSpotApi : ISocketApiClient IBinanceSocketClientSpotApiTrading Trading { get; } /// - /// Get the shared socket subscription client + /// Get the shared socket subscription client. This interface is shared with other exhanges to allow for a common implementation for different exchanges. /// IBinanceSocketClientSpotApiShared SharedClient { get; } } diff --git a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApi.cs b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApi.cs index 45aca6b4e..7f01588a7 100644 --- a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApi.cs +++ b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceRestClientUsdFuturesApi.cs @@ -23,12 +23,12 @@ public interface IBinanceRestClientUsdFuturesApi : IRestApiClient, IDisposable public IBinanceRestClientUsdFuturesApiTrading Trading { get; } /// - /// DEPRECATED; use instead for common/shared functionality. See for more info. + /// DEPRECATED; use instead for common/shared functionality. See for more info. /// public IFuturesClient CommonFuturesClient { get; } /// - /// Get the shared rest requests client + /// Get the shared rest requests client. This interface is shared with other exhanges to allow for a common implementation for different exchanges. /// public IBinanceRestClientUsdFuturesApiShared SharedClient { get; } } diff --git a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceSocketClientUsdFuturesApi.cs b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceSocketClientUsdFuturesApi.cs index 3084a797f..deb74659d 100644 --- a/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceSocketClientUsdFuturesApi.cs +++ b/Binance.Net/Interfaces/Clients/UsdFuturesApi/IBinanceSocketClientUsdFuturesApi.cs @@ -12,7 +12,7 @@ namespace Binance.Net.Interfaces.Clients.UsdFuturesApi public interface IBinanceSocketClientUsdFuturesApi : ISocketApiClient, IDisposable { /// - /// Get the shared socket subscription client + /// Get the shared socket subscription client. This interface is shared with other exhanges to allow for a common implementation for different exchanges. /// IBinanceSocketClientUsdFuturesApiShared SharedClient { get; } From f224519179eddcadc5887f816f2f06fc724f6353 Mon Sep 17 00:00:00 2001 From: JKorf Date: Wed, 25 Sep 2024 21:50:18 +0200 Subject: [PATCH 49/54] wip --- .../Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs | 2 +- .../Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs | 2 +- Binance.Net/Clients/GeneralApi/BinanceRestClientGeneralApi.cs | 2 +- Binance.Net/Clients/SpotApi/BinanceRestClientSpotApi.cs | 2 +- Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs | 2 +- .../Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs | 2 +- .../Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs index 3119f3f32..e1646d356 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs @@ -75,7 +75,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(); /// - public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode apiType, DateTime? deliverTime = null) + 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")); } diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs index 9c7916eab..7729f53a1 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs @@ -69,7 +69,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden public IBinanceSocketClientCoinFuturesApiShared SharedClient => this; /// - public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode apiType, DateTime? deliverTime = null) + 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")); } diff --git a/Binance.Net/Clients/GeneralApi/BinanceRestClientGeneralApi.cs b/Binance.Net/Clients/GeneralApi/BinanceRestClientGeneralApi.cs index 4055323c8..9adf8e417 100644 --- a/Binance.Net/Clients/GeneralApi/BinanceRestClientGeneralApi.cs +++ b/Binance.Net/Clients/GeneralApi/BinanceRestClientGeneralApi.cs @@ -74,7 +74,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(); /// - public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode apiType, DateTime? deliverTime = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); + public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode tradingMode, DateTime? deliverTime = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); 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 968fc6713..0c08da7a5 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApi.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApi.cs @@ -76,7 +76,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(); /// - public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode apiType, DateTime? deliverTime) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); + public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode tradingMode, DateTime? deliverTime) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); #region helpers diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs index af0518cc7..30fa1ba77 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs @@ -62,7 +62,7 @@ internal BinanceSocketClientSpotApi(ILogger logger, BinanceSocketOptions options public IBinanceSocketClientSpotApiShared SharedClient => this; /// - public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode apiType, DateTime? deliverTime = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); + public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode tradingMode, DateTime? deliverTime = null) => baseAsset.ToUpperInvariant() + quoteAsset.ToUpperInvariant(); /// protected override AuthenticationProvider CreateAuthenticationProvider(ApiCredentials credentials) diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs index 0c235b1b1..8dbaa635e 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs @@ -49,7 +49,7 @@ internal partial class BinanceRestClientUsdFuturesApi : RestApiClient, IBinanceR public event Action? OnOrderCanceled; /// - public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode apiType, DateTime? deliverTime = null) + 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")); } diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs index a8fd94b4e..6ff8c4246 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs @@ -66,7 +66,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden => new BinanceAuthenticationProvider(credentials); /// - public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode apiType, DateTime? deliverTime = null) + 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")); } From a5c7d59d1b1130a9487e01e6370ec69786d78a27 Mon Sep 17 00:00:00 2001 From: Jkorf Date: Thu, 26 Sep 2024 13:38:30 +0200 Subject: [PATCH 50/54] wip --- Binance.Net.UnitTests/TestImplementations/TestSocket.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Binance.Net.UnitTests/TestImplementations/TestSocket.cs b/Binance.Net.UnitTests/TestImplementations/TestSocket.cs index b803555ac..60e2f82c0 100644 --- a/Binance.Net.UnitTests/TestImplementations/TestSocket.cs +++ b/Binance.Net.UnitTests/TestImplementations/TestSocket.cs @@ -20,6 +20,7 @@ public class TestSocket: IWebsocket public event Func OnReconnected; public event Func OnReconnecting; public event Func OnRequestRateLimited; + public event Func OnConnectRateLimited; public event Func OnError; #pragma warning restore 0067 public event Func OnRequestSent; From deff832b4e5a96c7b09186f1a401fafa4f715c54 Mon Sep 17 00:00:00 2001 From: Jkorf Date: Thu, 26 Sep 2024 17:00:28 +0200 Subject: [PATCH 51/54] wip --- .../TestImplementations/BinanceRestApiClient.cs | 1 + Binance.Net/Binance.Net.xml | 14 +++++++------- .../BinanceRestClientCoinFuturesApi.cs | 1 + .../BinanceSocketClientCoinFuturesApi.cs | 1 + .../GeneralApi/BinanceRestClientGeneralApi.cs | 1 + .../Clients/SpotApi/BinanceRestClientSpotApi.cs | 1 + .../Clients/SpotApi/BinanceSocketClientSpotApi.cs | 1 + .../BinanceRestClientUsdFuturesApi.cs | 1 + .../BinanceSocketClientUsdFuturesApi.cs | 1 + 9 files changed, 15 insertions(+), 7 deletions(-) diff --git a/Binance.Net.UnitTests/TestImplementations/BinanceRestApiClient.cs b/Binance.Net.UnitTests/TestImplementations/BinanceRestApiClient.cs index 74e23d9b5..258566df2 100644 --- a/Binance.Net.UnitTests/TestImplementations/BinanceRestApiClient.cs +++ b/Binance.Net.UnitTests/TestImplementations/BinanceRestApiClient.cs @@ -2,6 +2,7 @@ using CryptoExchange.Net.Authentication; using CryptoExchange.Net.Clients; using CryptoExchange.Net.Objects; +using CryptoExchange.Net.SharedApis; using Microsoft.Extensions.Logging; using System; diff --git a/Binance.Net/Binance.Net.xml b/Binance.Net/Binance.Net.xml index 89c702c60..9ca9d8b05 100644 --- a/Binance.Net/Binance.Net.xml +++ b/Binance.Net/Binance.Net.xml @@ -265,7 +265,7 @@ - + @@ -469,7 +469,7 @@ - + @@ -628,7 +628,7 @@ - + @@ -1133,7 +1133,7 @@ - + @@ -1673,7 +1673,7 @@ - + @@ -1908,7 +1908,7 @@ Event triggered when an order is canceled via this client. Note that this does not trigger when using CancelAllOrdersAsync. Only available for Spot orders - + @@ -2224,7 +2224,7 @@ - + diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs index e1646d356..36b164cc7 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceRestClientCoinFuturesApi.cs @@ -9,6 +9,7 @@ using CryptoExchange.Net.Converters.MessageParsing; using CryptoExchange.Net.Clients; using CryptoExchange.Net.RateLimiting.Interfaces; +using CryptoExchange.Net.SharedApis; namespace Binance.Net.Clients.CoinFuturesApi { diff --git a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs index 7729f53a1..525391fef 100644 --- a/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs +++ b/Binance.Net/Clients/CoinFuturesApi/BinanceSocketClientCoinFuturesApi.cs @@ -12,6 +12,7 @@ using CryptoExchange.Net.Clients; using CryptoExchange.Net.Converters.MessageParsing; using CryptoExchange.Net.Objects.Sockets; +using CryptoExchange.Net.SharedApis; using CryptoExchange.Net.Sockets; namespace Binance.Net.Clients.CoinFuturesApi diff --git a/Binance.Net/Clients/GeneralApi/BinanceRestClientGeneralApi.cs b/Binance.Net/Clients/GeneralApi/BinanceRestClientGeneralApi.cs index 9adf8e417..ac5c00bd9 100644 --- a/Binance.Net/Clients/GeneralApi/BinanceRestClientGeneralApi.cs +++ b/Binance.Net/Clients/GeneralApi/BinanceRestClientGeneralApi.cs @@ -5,6 +5,7 @@ using CryptoExchange.Net.Converters.MessageParsing; using CryptoExchange.Net.Clients; using CryptoExchange.Net.RateLimiting.Interfaces; +using CryptoExchange.Net.SharedApis; namespace Binance.Net.Clients.GeneralApi { diff --git a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApi.cs b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApi.cs index 0c08da7a5..07dd2c24e 100644 --- a/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApi.cs +++ b/Binance.Net/Clients/SpotApi/BinanceRestClientSpotApi.cs @@ -10,6 +10,7 @@ using CryptoExchange.Net.Converters.MessageParsing; using CryptoExchange.Net.Clients; using CryptoExchange.Net.RateLimiting.Interfaces; +using CryptoExchange.Net.SharedApis; namespace Binance.Net.Clients.SpotApi { diff --git a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs index 30fa1ba77..77d7e18ff 100644 --- a/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs +++ b/Binance.Net/Clients/SpotApi/BinanceSocketClientSpotApi.cs @@ -9,6 +9,7 @@ using CryptoExchange.Net.Clients; using CryptoExchange.Net.Converters.MessageParsing; using CryptoExchange.Net.Objects.Sockets; +using CryptoExchange.Net.SharedApis; using CryptoExchange.Net.Sockets; namespace Binance.Net.Clients.SpotApi diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs index 8dbaa635e..d7749bb67 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceRestClientUsdFuturesApi.cs @@ -9,6 +9,7 @@ using CryptoExchange.Net.Converters.MessageParsing; using CryptoExchange.Net.Clients; using CryptoExchange.Net.RateLimiting.Interfaces; +using CryptoExchange.Net.SharedApis; namespace Binance.Net.Clients.UsdFuturesApi { diff --git a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs index 6ff8c4246..58134f350 100644 --- a/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs +++ b/Binance.Net/Clients/UsdFuturesApi/BinanceSocketClientUsdFuturesApi.cs @@ -11,6 +11,7 @@ using CryptoExchange.Net.Clients; using CryptoExchange.Net.Converters.MessageParsing; using CryptoExchange.Net.Objects.Sockets; +using CryptoExchange.Net.SharedApis; using CryptoExchange.Net.Sockets; namespace Binance.Net.Clients.UsdFuturesApi From 1bf691014fd3a7911f1acee1d0ebc1f9518cb689 Mon Sep 17 00:00:00 2001 From: Jkorf Date: Fri, 27 Sep 2024 08:21:19 +0200 Subject: [PATCH 52/54] wip --- Binance.Net/ExtensionMethods/ServiceCollectionExtensions.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Binance.Net/ExtensionMethods/ServiceCollectionExtensions.cs b/Binance.Net/ExtensionMethods/ServiceCollectionExtensions.cs index 4bc412525..1bca891a7 100644 --- a/Binance.Net/ExtensionMethods/ServiceCollectionExtensions.cs +++ b/Binance.Net/ExtensionMethods/ServiceCollectionExtensions.cs @@ -64,6 +64,10 @@ public static IServiceCollection AddBinance( services.RegisterSharedRestInterfaces(x => x.GetRequiredService().SpotApi.SharedClient); services.RegisterSharedSocketInterfaces(x => x.GetRequiredService().SpotApi.SharedClient); + services.RegisterSharedRestInterfaces(x => x.GetRequiredService().UsdFuturesApi.SharedClient); + services.RegisterSharedSocketInterfaces(x => x.GetRequiredService().UsdFuturesApi.SharedClient); + services.RegisterSharedRestInterfaces(x => x.GetRequiredService().CoinFuturesApi.SharedClient); + services.RegisterSharedSocketInterfaces(x => x.GetRequiredService().CoinFuturesApi.SharedClient); if (socketClientLifeTime == null) services.AddSingleton(); From e7d086c0005a403d4465fc0f66f5596a7cb48d60 Mon Sep 17 00:00:00 2001 From: Jkorf Date: Fri, 27 Sep 2024 09:27:17 +0200 Subject: [PATCH 53/54] Update Binance.Net.csproj --- Binance.Net/Binance.Net.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Binance.Net/Binance.Net.csproj b/Binance.Net/Binance.Net.csproj index f18b09d5d..f96341689 100644 --- a/Binance.Net/Binance.Net.csproj +++ b/Binance.Net/Binance.Net.csproj @@ -7,9 +7,9 @@ Binance.Net JKorf - 10.2.1 - 10.2.1 - 10.2.1 + 10.4.0 + 10.4.0 + 10.4.0 Binance.Net is a client library for accessing the Binance REST and Websocket API. All data is mapped to readable models and enum values. Additional features include automatic websocket (re)connection management, client side rate limiting, an implementation for maintaining a client side order book, easy integration with other exchange client libraries and more. false Binance;Binance.Net;Binance Client;Binance API;CryptoCurrency;CryptoCurrency Exchange From f97b7509d45db67f7cb193c4d69b093b3d73f728 Mon Sep 17 00:00:00 2001 From: Jkorf Date: Fri, 27 Sep 2024 11:11:06 +0200 Subject: [PATCH 54/54] Update Binance.Net.csproj --- Binance.Net/Binance.Net.csproj | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Binance.Net/Binance.Net.csproj b/Binance.Net/Binance.Net.csproj index f96341689..97a1a3e8b 100644 --- a/Binance.Net/Binance.Net.csproj +++ b/Binance.Net/Binance.Net.csproj @@ -52,8 +52,6 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - - - + \ No newline at end of file