diff --git a/AGENTS.md b/AGENTS.md index fd0a0d0..b02ff94 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -7,7 +7,7 @@ description: Use BitMart.Net when generating C#/.NET code that interacts with Bi ## Quick decision -If the user asks for BitMart API access in C#/.NET, use **BitMart.Net**. Do not write raw `HttpClient` calls to BitMart endpoints. For multi-exchange code, use `CryptoExchange.Net.SharedApis`. +If the user asks for BitMart API access in C#/.NET, use **BitMart.Net**. Do not write raw `HttpClient` calls to BitMart endpoints. For multi-exchange code, use `CryptoExchange.Net.SharedApis` through the `.SharedClient` properties. Use `.SharedClient.Discover()` to inspect supported shared features at runtime. ## Installation @@ -40,7 +40,7 @@ var publicClient = new BitMartRestClient(); ## Core Pattern: Result Handling -Every REST method returns `WebCallResult` or `WebCallResult`. WebSocket subscriptions return `CallResult`. Always check `.Success` before accessing `.Data`. +Every REST method returns `HttpResult` or `HttpResult`. WebSocket subscriptions return `WebSocketResult`. Shared non-I/O symbol/cache helpers return `ExchangeCallResult`. Always check `.Success` before accessing `.Data`. ```csharp var ticker = await restClient.SpotApi.ExchangeData.GetTickerAsync("BTC_USDT"); @@ -345,6 +345,9 @@ using BitMart.Net.Clients; using CryptoExchange.Net.SharedApis; var shared = new BitMartRestClient().SpotApi.SharedClient; +var info = shared.Discover(); +Console.WriteLine($"{info.Exchange} supports {info.Features.Count(x => x.Supported)} shared features"); + var symbol = new SharedSymbol(TradingMode.Spot, "BTC", "USDT"); var ticker = await shared.GetSpotTickerAsync(new GetTickerRequest(symbol)); ``` diff --git a/BitMart.Net.UnitTests/BitMartRestClientTests.cs b/BitMart.Net.UnitTests/BitMartRestClientTests.cs index 52dfe28..9250a50 100644 --- a/BitMart.Net.UnitTests/BitMartRestClientTests.cs +++ b/BitMart.Net.UnitTests/BitMartRestClientTests.cs @@ -32,12 +32,11 @@ public void CheckSignatureExample1() return headers["X-BM-SIGN"].ToString(); }, "1d022acf035f8d7f899dcaad0621fe39d351f7809e30ac8c96939a36548a6502", - new Dictionary + new Parameters(BitMartExchange._parameterSerializationSettings) { { "symbol", "LTCBTC" }, }, DateTimeConverter.ParseFromDouble(1499827320559), - true, false); } diff --git a/BitMart.Net.UnitTests/RestRequestTests.cs b/BitMart.Net.UnitTests/RestRequestTests.cs index 2b0071a..c608908 100644 --- a/BitMart.Net.UnitTests/RestRequestTests.cs +++ b/BitMart.Net.UnitTests/RestRequestTests.cs @@ -86,7 +86,7 @@ public async Task ValidateSpotSubAccountCalls() await tester.ValidateAsync(client => client.SpotApi.SubAccount.TransferSubAccountToSubAccountAsync("123", 0.1m, "123", "123", "123"), "TransferSubAccountToSubAccount"); await tester.ValidateAsync(client => client.SpotApi.SubAccount.GetSubAccountTransferHistoryForMainAsync(123), "GetSubAccountTransferHistoryForMain", nestedJsonProperty: "data"); await tester.ValidateAsync(client => client.SpotApi.SubAccount.GetSubAccountTransferHistoryAsync(123), "GetSubAccountTransferHistory", nestedJsonProperty: "data"); - await tester.ValidateAsync(client => client.SpotApi.SubAccount.GetSubAcccountBalanceAsync("123"), "GetSubAcccountBalance", nestedJsonProperty: "data.wallet"); + await tester.ValidateAsync(client => client.SpotApi.SubAccount.GetSubAccountBalanceAsync("123"), "GetSubAcccountBalance", nestedJsonProperty: "data.wallet"); await tester.ValidateAsync(client => client.SpotApi.SubAccount.GetSubAccountListAsync(), "GetSubAccountList", nestedJsonProperty: "data.subAccountList"); } @@ -158,7 +158,7 @@ public async Task ValidateUsdFuturesSubAccountCalls() await tester.ValidateAsync(client => client.UsdFuturesApi.SubAccount.TransferSubToMainForMainAsync("123", 0.1m, "123", "123"), "TransferSubToMainForMain"); await tester.ValidateAsync(client => client.UsdFuturesApi.SubAccount.TransferMainToSubForMainAsync("123", 0.1m, "123", "123"), "TransferMainToSubForMain"); await tester.ValidateAsync(client => client.UsdFuturesApi.SubAccount.TransferSubToMainForSubAsync("123", 0.1m, "123"), "TransferSubToMainForSub"); - await tester.ValidateAsync(client => client.UsdFuturesApi.SubAccount.GetSubAcccountBalanceAsync("123"), "GetSubAcccountBalance", nestedJsonProperty: "data.wallet"); + await tester.ValidateAsync(client => client.UsdFuturesApi.SubAccount.GetSubAccountBalanceAsync("123"), "GetSubAcccountBalance", nestedJsonProperty: "data.wallet"); await tester.ValidateAsync(client => client.UsdFuturesApi.SubAccount.GetSubAccountTransferHistoryForMainAsync("123", 123), "GetSubAccountTransferHistoryForMain", nestedJsonProperty: "data"); await tester.ValidateAsync(client => client.UsdFuturesApi.SubAccount.GetSubAccountTransferHistoryAsync(123), "GetSubAccountTransferHistory", nestedJsonProperty: "data"); } @@ -192,7 +192,7 @@ public async Task ValidateUsdFuturesTradingCalls() await tester.ValidateAsync(client => client.UsdFuturesApi.Trading.CancelAllAfterAsync("ETHUSDT", TimeSpan.Zero), "CancelAllAfter", nestedJsonProperty: "data"); } - private bool IsAuthenticated(WebCallResult result) + private bool IsAuthenticated(IHttpResult result) { return result.RequestHeaders.Any(x => x.Key == "X-BM-SIGN"); } diff --git a/BitMart.Net.UnitTests/SocketSubscriptionTests.cs b/BitMart.Net.UnitTests/SocketSubscriptionTests.cs index bc38502..718892c 100644 --- a/BitMart.Net.UnitTests/SocketSubscriptionTests.cs +++ b/BitMart.Net.UnitTests/SocketSubscriptionTests.cs @@ -28,7 +28,7 @@ public async Task ValidateConcurrentSpotSubscriptions() OutputOriginalData = true, }), logger); - var tester = new SocketSubscriptionValidator(client, "Subscriptions/Spot", "wss://ws-manager-compress.bitmart.com", "data"); + var tester = new SocketSubscriptionValidator(client, "Subscriptions/Spot", "wss://ws-manager-compress.bitmart.com/api?protocol=1.1", "data"); await tester.ValidateConcurrentAsync( (client, handler) => client.SpotApi.SubscribeToKlineUpdatesAsync("ETH_USDT", KlineStreamInterval.OneDay, handler), (client, handler) => client.SpotApi.SubscribeToKlineUpdatesAsync("ETH_USDT", KlineStreamInterval.OneHour, handler), @@ -67,7 +67,7 @@ public async Task ValidateConcurrentFuturesSubscriptions() OutputOriginalData = true }), logger); - var tester = new SocketSubscriptionValidator(client, "Subscriptions/Futures", "wss://openapi-ws.bitmart.com", "data"); + var tester = new SocketSubscriptionValidator(client, "Subscriptions/Futures", "wss://openapi-ws-v2.bitmart.com/api?protocol=1.1", "data"); await tester.ValidateConcurrentAsync( (client, handler) => client.UsdFuturesApi.SubscribeToKlineUpdatesAsync("ETHUSDT", FuturesStreamKlineInterval.OneDay, handler), (client, handler) => client.UsdFuturesApi.SubscribeToKlineUpdatesAsync("ETHUSDT", FuturesStreamKlineInterval.OneHour, handler), diff --git a/BitMart.Net.UnitTests/Subscriptions/Spot/Order.txt b/BitMart.Net.UnitTests/Subscriptions/Spot/Order.txt index 079b1a4..f827931 100644 --- a/BitMart.Net.UnitTests/Subscriptions/Spot/Order.txt +++ b/BitMart.Net.UnitTests/Subscriptions/Spot/Order.txt @@ -27,7 +27,7 @@ "client_order_id":"order4872191", "create_time":"1609926028000", "update_time":"1609926044000", - "order_mode":"0", + "order_mode":"spot", "entrust_type":"normal", "order_state":"partially_filled" } diff --git a/BitMart.Net/BitMart.Net.csproj b/BitMart.Net/BitMart.Net.csproj index 4c9b8d7..995243a 100644 --- a/BitMart.Net/BitMart.Net.csproj +++ b/BitMart.Net/BitMart.Net.csproj @@ -49,11 +49,11 @@ - all runtime; build; native; contentfiles; analyzers; buildtransitive + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/BitMart.Net/BitMartAuthenticationProvider.cs b/BitMart.Net/BitMartAuthenticationProvider.cs index 1f31bef..2fabb00 100644 --- a/BitMart.Net/BitMartAuthenticationProvider.cs +++ b/BitMart.Net/BitMartAuthenticationProvider.cs @@ -23,12 +23,12 @@ public BitMartAuthenticationProvider(BitMartCredentials credentials) : base(cred public override void ProcessRequest(RestApiClient apiClient, RestRequestConfiguration request) { - if (!request.Authenticated) + if (!request.RequestDefinition.Authenticated) return; var timestamp = GetMillisecondTimestamp(apiClient); var queryParams = request.GetQueryString(false); - var bodyParams = GetSerializedBody(_serializer, request.BodyParameters ?? new Dictionary()); + var bodyParams = GetSerializedBody(_serializer, request.BodyParameters ?? new Parameters(BitMartExchange._parameterSerializationSettings)); var signStr = $"{timestamp}#{Credential.Pass}#{queryParams}{bodyParams}"; request.Headers ??= new Dictionary(); diff --git a/BitMart.Net/BitMartExchange.cs b/BitMart.Net/BitMartExchange.cs index 5d6b744..5a179c3 100644 --- a/BitMart.Net/BitMartExchange.cs +++ b/BitMart.Net/BitMartExchange.cs @@ -26,7 +26,8 @@ public static class BitMartExchange "https://www.bitmart.com", ["https://developer-pro.bitmart.com/#introduction"], PlatformType.CryptoCurrencyExchange, - CentralizationType.Centralized + CentralizationType.Centralized, + BitMartEnvironment.All ); /// @@ -62,6 +63,11 @@ public static class BitMartExchange public static ExchangeType Type { get; } = ExchangeType.CEX; internal static JsonSerializerContext _serializerContext = JsonSerializerContextCache.GetOrCreate(); + internal static ParameterSerializationSettings _parameterSerializationSettings = new ParameterSerializationSettings + { + Decimal = DecimalSerialization.String, + DateTimes = DateTimeSerialization.MillisecondsNumber + }; /// /// Aliases for BitMart assets @@ -95,7 +101,7 @@ public static string FormatSymbol(string baseAsset, string quoteAsset, TradingMo /// /// Rate limiter configuration for the BitMart API /// - public static BitMartRateLimiters RateLimiter { get; } = new BitMartRateLimiters(); + public static BitMartRateLimiters RateLimiter { get; set; } = new BitMartRateLimiters(); } /// @@ -114,13 +120,19 @@ public class BitMartRateLimiters public event Action RateLimitUpdated; #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. - internal BitMartRateLimiters() + /// + /// ctor + /// + public BitMartRateLimiters() #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. { Initialize(); } - private void Initialize() + /// + /// Initialize the rate limits + /// + protected virtual void Initialize() { BitMart = new RateLimitGate("BitMart IP"); SocketLimits = new RateLimitGate("Socket limits") diff --git a/BitMart.Net/BitMartUserDataTracker.cs b/BitMart.Net/BitMartUserDataTracker.cs index 56553e1..596f145 100644 --- a/BitMart.Net/BitMartUserDataTracker.cs +++ b/BitMart.Net/BitMartUserDataTracker.cs @@ -20,7 +20,6 @@ public BitMartUserSpotDataTracker( SpotUserDataTrackerConfig? config) : base( logger, restClient.SpotApi.SharedClient, - null, restClient.SpotApi.SharedClient, socketClient.SpotApi.SharedClient, restClient.SpotApi.SharedClient, @@ -48,7 +47,6 @@ public BitMartUserUsdFuturesDataTracker( string? userIdentifier, FuturesUserDataTrackerConfig? config) : base(logger, restClient.UsdFuturesApi.SharedClient, - null, restClient.UsdFuturesApi.SharedClient, socketClient.UsdFuturesApi.SharedClient, restClient.UsdFuturesApi.SharedClient, diff --git a/BitMart.Net/Clients/BitMartRestClient.cs b/BitMart.Net/Clients/BitMartRestClient.cs index 03fd6ad..0681b81 100644 --- a/BitMart.Net/Clients/BitMartRestClient.cs +++ b/BitMart.Net/Clients/BitMartRestClient.cs @@ -48,8 +48,8 @@ public BitMartRestClient(HttpClient? httpClient, ILoggerFactory? loggerFactory, { Initialize(options.Value); - UsdFuturesApi = AddApiClient(new BitMartRestClientUsdFuturesApi(_logger, this, httpClient, options.Value)); - SpotApi = AddApiClient(new BitMartRestClientSpotApi(_logger, httpClient, options.Value)); + UsdFuturesApi = AddApiClient(new BitMartRestClientUsdFuturesApi(loggerFactory, this, httpClient, options.Value)); + SpotApi = AddApiClient(new BitMartRestClientSpotApi(loggerFactory, httpClient, options.Value)); } #endregion diff --git a/BitMart.Net/Clients/BitMartSocketClient.cs b/BitMart.Net/Clients/BitMartSocketClient.cs index f24157a..0b740f8 100644 --- a/BitMart.Net/Clients/BitMartSocketClient.cs +++ b/BitMart.Net/Clients/BitMartSocketClient.cs @@ -49,8 +49,8 @@ public BitMartSocketClient(IOptions options, ILoggerFactor { Initialize(options.Value); - UsdFuturesApi = AddApiClient(new BitMartSocketClientUsdFuturesApi(_logger, options.Value)); - SpotApi = AddApiClient(new BitMartSocketClientSpotApi(_logger, options.Value)); + UsdFuturesApi = AddApiClient(new BitMartSocketClientUsdFuturesApi(loggerFactory, options.Value)); + SpotApi = AddApiClient(new BitMartSocketClientSpotApi(loggerFactory, options.Value)); } #endregion diff --git a/BitMart.Net/Clients/BitMartUserClientProvider.cs b/BitMart.Net/Clients/BitMartUserClientProvider.cs index 12c6198..1a6cf14 100644 --- a/BitMart.Net/Clients/BitMartUserClientProvider.cs +++ b/BitMart.Net/Clients/BitMartUserClientProvider.cs @@ -1,6 +1,7 @@ using BitMart.Net.Interfaces.Clients; using BitMart.Net.Objects.Options; using CryptoExchange.Net.Authentication; +using CryptoExchange.Net.Clients; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using System; @@ -10,18 +11,17 @@ namespace BitMart.Net.Clients { /// - public class BitMartUserClientProvider : IBitMartUserClientProvider + public class BitMartUserClientProvider : UserClientProvider< + IBitMartRestClient, + IBitMartSocketClient, + BitMartRestOptions, + BitMartSocketOptions, + BitMartCredentials, + BitMartEnvironment + >, IBitMartUserClientProvider { - private ConcurrentDictionary _restClients = new ConcurrentDictionary(); - private ConcurrentDictionary _socketClients = new ConcurrentDictionary(); - - private readonly IOptions _restOptions; - private readonly IOptions _socketOptions; - private readonly HttpClient _httpClient; - private readonly ILoggerFactory? _loggerFactory; - /// - public string ExchangeName => BitMartExchange.ExchangeName; + public override string ExchangeName => BitMartExchange.ExchangeName; /// /// ctor @@ -40,97 +40,15 @@ public BitMartUserClientProvider( ILoggerFactory? loggerFactory, IOptions restOptions, IOptions socketOptions) + : base(httpClient, loggerFactory, restOptions, socketOptions) { - _httpClient = httpClient ?? new HttpClient(); - _httpClient.Timeout = restOptions.Value.RequestTimeout; - _loggerFactory = loggerFactory; - _restOptions = restOptions; - _socketOptions = socketOptions; } /// - public void InitializeUserClient(string userIdentifier, BitMartCredentials credentials, BitMartEnvironment? environment = null) - { - CreateRestClient(userIdentifier, credentials, environment); - CreateSocketClient(userIdentifier, credentials, environment); - } - - /// - public void ClearUserClients(string userIdentifier) - { - _restClients.TryRemove(userIdentifier, out _); - _socketClients.TryRemove(userIdentifier, out _); - } - + protected override IBitMartRestClient ConstructRestClient(HttpClient client, ILoggerFactory? loggerFactory, IOptions options) + => new BitMartRestClient(client, loggerFactory, options); /// - public IBitMartRestClient GetRestClient(string userIdentifier, BitMartCredentials? credentials = null, BitMartEnvironment? environment = null) - { - if (!_restClients.TryGetValue(userIdentifier, out var client) || client.Disposed) - client = CreateRestClient(userIdentifier, credentials, environment); - - return client; - } - - /// - public IBitMartSocketClient GetSocketClient(string userIdentifier, BitMartCredentials? credentials = null, BitMartEnvironment? environment = null) - { - if (!_socketClients.TryGetValue(userIdentifier, out var client) || client.Disposed) - client = CreateSocketClient(userIdentifier, credentials, environment); - - return client; - } - - private IBitMartRestClient CreateRestClient(string userIdentifier, BitMartCredentials? credentials, BitMartEnvironment? environment) - { - var clientRestOptions = SetRestEnvironment(environment); - var client = new BitMartRestClient(_httpClient, _loggerFactory, clientRestOptions); - if (credentials != null) - { - client.SetApiCredentials(credentials); - _restClients[userIdentifier] = client; - } - return client; - } - - private IBitMartSocketClient CreateSocketClient(string userIdentifier, BitMartCredentials? credentials, BitMartEnvironment? environment) - { - var clientSocketOptions = SetSocketEnvironment(environment); - var client = new BitMartSocketClient(clientSocketOptions!, _loggerFactory); - if (credentials != null) - { - client.SetApiCredentials(credentials); - _socketClients[userIdentifier] = client; - } - return client; - } - - private IOptions SetRestEnvironment(BitMartEnvironment? environment) - { - if (environment == null) - return _restOptions; - - var newRestClientOptions = new BitMartRestOptions(); - var restOptions = _restOptions.Value.Set(newRestClientOptions); - newRestClientOptions.Environment = environment; - return Options.Create(newRestClientOptions); - } - - private IOptions SetSocketEnvironment(BitMartEnvironment? environment) - { - if (environment == null) - return _socketOptions; - - var newSocketClientOptions = new BitMartSocketOptions(); - var restOptions = _socketOptions.Value.Set(newSocketClientOptions); - newSocketClientOptions.Environment = environment; - return Options.Create(newSocketClientOptions); - } - - private static T ApplyOptionsDelegate(Action? del) where T : new() - { - var opts = new T(); - del?.Invoke(opts); - return opts; - } + protected override IBitMartSocketClient ConstructSocketClient(ILoggerFactory? loggerFactory, IOptions options) + => new BitMartSocketClient(options, loggerFactory); } } diff --git a/BitMart.Net/Clients/SpotApi/BitMartRestClientSpotApi.cs b/BitMart.Net/Clients/SpotApi/BitMartRestClientSpotApi.cs index 894f013..5197c64 100644 --- a/BitMart.Net/Clients/SpotApi/BitMartRestClientSpotApi.cs +++ b/BitMart.Net/Clients/SpotApi/BitMartRestClientSpotApi.cs @@ -50,14 +50,14 @@ internal partial class BitMartRestClientSpotApi : RestApiClient new BitMartAuthenticationProvider(credentials); - internal Task SendAsync(RequestDefinition definition, ParameterCollection? parameters, CancellationToken cancellationToken, int? weight = null, Dictionary? additionalHeaders = null) - => SendToAddressAsync(BaseAddress, definition, parameters, cancellationToken, weight, additionalHeaders); - - internal async Task SendToAddressAsync(string baseAddress, RequestDefinition definition, ParameterCollection? parameters, CancellationToken cancellationToken, int? weight = null, Dictionary? additionalHeaders = null) + internal async Task SendAsync(RequestDefinition definition, Parameters? parameters, CancellationToken cancellationToken, int? weight = null, Dictionary? additionalHeaders = null) { if (Authenticated) { - var window = (int?)((BitMartRestOptions)ClientOptions).ReceiveWindow?.TotalMilliseconds; - parameters ??= new ParameterCollection(); - parameters.AddOptional("recvWindow", window); + var window = (int?)ClientOptions.ReceiveWindow?.TotalMilliseconds; + parameters ??= new Parameters(BitMartExchange._parameterSerializationSettings); + parameters.Add("recvWindow", window); } - var result = await base.SendAsync(baseAddress, definition, parameters, cancellationToken, additionalHeaders, weight).ConfigureAwait(false); - if (!result) - return result.AsDataless(); + var result = await base.SendAsync(definition, parameters, cancellationToken, additionalHeaders, weight).ConfigureAwait(false); + if (!result.Success) + return result; if (result.Data.Code != 1000) - return result.AsDatalessError(new ServerError(result.Data.Code, GetErrorInfo(result.Data.Code, result.Data.Message))); + return HttpResult.Fail(result, new ServerError(result.Data.Code, GetErrorInfo(result.Data.Code, result.Data.Message))); - return result.AsDataless(); + return result; } - internal Task> SendAsync(RequestDefinition definition, ParameterCollection? parameters, CancellationToken cancellationToken, int? weight = null, Dictionary? additionalHeaders = null) where T : class - => SendToAddressAsync(BaseAddress, definition, parameters, cancellationToken, weight, additionalHeaders); - - internal async Task> SendToAddressAsync(string baseAddress, RequestDefinition definition, ParameterCollection? parameters, CancellationToken cancellationToken, int? weight = null, Dictionary? additionalHeaders = null) where T : class + internal async Task> SendAsync(RequestDefinition definition, Parameters? parameters, CancellationToken cancellationToken, int? weight = null, Dictionary? additionalHeaders = null) where T : class { if (Authenticated) { - var window = (int?)((BitMartRestOptions)ClientOptions).ReceiveWindow?.TotalMilliseconds; - parameters ??= new ParameterCollection(); - parameters.AddOptional("recvWindow", window); + var window = (int?)ClientOptions.ReceiveWindow?.TotalMilliseconds; + parameters ??= new Parameters(BitMartExchange._parameterSerializationSettings); + parameters.Add("recvWindow", window); } - var result = await base.SendAsync>(baseAddress, definition, parameters, cancellationToken, additionalHeaders, weight).ConfigureAwait(false); - if (!result) - return result.As(default); + var result = await base.SendAsync>(definition, parameters, cancellationToken, additionalHeaders, weight).ConfigureAwait(false); + if (!result.Success) + return HttpResult.Fail(result); if (result.Data.Code != 1000) - return result.AsError(new ServerError(result.Data.Code, GetErrorInfo(result.Data.Code, result.Data.Message))); + return HttpResult.Fail(result, new ServerError(result.Data.Code, GetErrorInfo(result.Data.Code, result.Data.Message))); - return result.As(result.Data.Data); + return HttpResult.Ok(result, result.Data.Data); } /// - protected override Task> GetServerTimestampAsync() + protected override Task> GetServerTimestampAsync() => ExchangeData.GetServerTimeAsync(); /// diff --git a/BitMart.Net/Clients/SpotApi/BitMartRestClientSpotApiAccount.cs b/BitMart.Net/Clients/SpotApi/BitMartRestClientSpotApiAccount.cs index 16278ae..68b92f1 100644 --- a/BitMart.Net/Clients/SpotApi/BitMartRestClientSpotApiAccount.cs +++ b/BitMart.Net/Clients/SpotApi/BitMartRestClientSpotApiAccount.cs @@ -22,162 +22,183 @@ internal BitMartRestClientSpotApiAccount(BitMartRestClientSpotApi baseClient) } /// - public async Task> GetFundingBalancesAsync(string? asset = null, bool? needUsdValuation = null, CancellationToken ct = default) + public async Task> GetFundingBalancesAsync(string? asset = null, bool? needUsdValuation = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); - parameters.AddOptional("currency", asset); - parameters.AddOptional("needUsdValuation", needUsdValuation); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/account/v1/wallet", BitMartExchange.RateLimiter.BitMart, 1, true, + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); + parameters.Add("currency", asset); + parameters.Add("needUsdValuation", needUsdValuation); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/account/v1/wallet", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(12, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); - return result.As(result.Data?.Wallet); + if (!result.Success) + return HttpResult.Fail(result); + + return HttpResult.Ok(result, result.Data.Wallet); } /// - public async Task> GetSpotBalancesAsync(CancellationToken ct = default) + public async Task> GetSpotBalancesAsync(CancellationToken ct = default) { - var parameters = new ParameterCollection(); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/spot/v1/wallet", BitMartExchange.RateLimiter.BitMart, 1, true, + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/spot/v1/wallet", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(12, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); - return result.As(result.Data?.Wallet); + if (!result.Success) + return HttpResult.Fail(result); + + return HttpResult.Ok(result, result.Data.Wallet); } /// - public async Task> GetDepositAddressAsync(string asset, CancellationToken ct = default) + public async Task> GetDepositAddressAsync(string asset, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("currency", asset); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/account/v1/deposit/address", BitMartExchange.RateLimiter.BitMart, 1, true, + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/account/v1/deposit/address", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(2, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; } /// - public async Task> GetWithdrawalQuotaAsync(string asset, CancellationToken ct = default) + public async Task> GetWithdrawalQuotaAsync(string asset, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("currency", asset); - var request = _definitions.GetOrCreate(HttpMethod.Get, "account/v1/withdraw/charge", BitMartExchange.RateLimiter.BitMart, 1, true, + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "account/v1/withdraw/charge", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(2, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; } /// - public async Task> WithdrawAsync(string asset, decimal quantity, string? targetAddress = null, string? memo = null, string? remark = null, string? accountDestType = null, string? targetAccount = null, string? areaCode = null, CancellationToken ct = default) + public async Task> WithdrawAsync(string asset, decimal quantity, string? targetAddress = null, string? memo = null, string? remark = null, string? accountDestType = null, string? targetAccount = null, string? areaCode = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); - parameters.AddOptional("address", targetAddress); - parameters.AddOptional("address_memo", memo); - parameters.AddOptional("destination", remark); - parameters.AddOptional("type", accountDestType); - parameters.AddOptional("value", targetAccount); - parameters.AddOptional("areaCode", areaCode); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); + parameters.Add("address", targetAddress); + parameters.Add("address_memo", memo); + parameters.Add("destination", remark); + parameters.Add("type", accountDestType); + parameters.Add("value", targetAccount); + parameters.Add("areaCode", areaCode); parameters.Add("currency", asset); - parameters.AddString("amount", quantity); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/account/v1/withdraw/apply", BitMartExchange.RateLimiter.BitMart, 1, true, + parameters.Add("amount", quantity); + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/account/v1/withdraw/apply", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(8, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; } /// - public async Task> GetDepositHistoryAsync(string? asset = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default) + public async Task> GetDepositHistoryAsync(string? asset = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("operation_type", "deposit"); parameters.Add("N", limit ?? 100); - parameters.AddOptional("currency", asset); - parameters.AddOptionalMilliseconds("startTime", startTime); - parameters.AddOptionalMilliseconds("endTime", endTime); - var request = _definitions.GetOrCreate(HttpMethod.Get, "account/v2/deposit-withdraw/history", BitMartExchange.RateLimiter.BitMart, 1, true, + parameters.Add("currency", asset); + parameters.Add("startTime", startTime); + parameters.Add("endTime", endTime); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "account/v2/deposit-withdraw/history", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(8, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); - return result.As(result.Data?.Records); + if (!result.Success) + return HttpResult.Fail(result); + + return HttpResult.Ok(result, result.Data.Records); } /// - public async Task> GetWithdrawalHistoryAsync(string? asset = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default) + public async Task> GetWithdrawalHistoryAsync(string? asset = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("operation_type", "withdraw"); parameters.Add("N", limit ?? 100); - parameters.AddOptional("currency", asset); - parameters.AddOptionalMilliseconds("startTime", startTime); - parameters.AddOptionalMilliseconds("endTime", endTime); - var request = _definitions.GetOrCreate(HttpMethod.Get, "account/v2/deposit-withdraw/history", BitMartExchange.RateLimiter.BitMart, 1, true, + parameters.Add("currency", asset); + parameters.Add("startTime", startTime); + parameters.Add("endTime", endTime); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "account/v2/deposit-withdraw/history", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(8, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); - return result.As(result.Data?.Records); + if (!result.Success) + return HttpResult.Fail(result); + + return HttpResult.Ok(result, result.Data.Records); } /// - public async Task> GetDepositWithdrawalAsync(string id, CancellationToken ct = default) + public async Task> GetDepositWithdrawalAsync(string id, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("id", id); - var request = _definitions.GetOrCreate(HttpMethod.Get, "account/v1/deposit-withdraw/detail", BitMartExchange.RateLimiter.BitMart, 1, true, + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "account/v1/deposit-withdraw/detail", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(8, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); - return result.As(result.Data?.Record); + if (!result.Success) + return HttpResult.Fail(result); + + return HttpResult.Ok(result, result.Data.Record); } /// - public async Task> GetIsolatedMarginAccountsAsync(string? symbol = null, CancellationToken ct = default) + public async Task> GetIsolatedMarginAccountsAsync(string? symbol = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); - parameters.AddOptional("symbol", symbol); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/spot/v1/margin/isolated/account", BitMartExchange.RateLimiter.BitMart, 1, true, + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); + parameters.Add("symbol", symbol); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/spot/v1/margin/isolated/account", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(12, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); - return result.As(result.Data?.Symbols); + if (!result.Success) + return HttpResult.Fail(result); + + return HttpResult.Ok(result, result.Data.Symbols); } /// - public async Task> IsolatedMarginTransferAsync(string symbol, string asset, decimal quantity, TransferDirection direction, CancellationToken ct = default) + public async Task> IsolatedMarginTransferAsync(string symbol, string asset, decimal quantity, TransferDirection direction, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("symbol", symbol); parameters.Add("currency", asset); - parameters.AddString("amount", quantity); - parameters.AddEnum("side", direction); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/spot/v1/margin/isolated/transfer", BitMartExchange.RateLimiter.BitMart, 1, true, + parameters.Add("amount", quantity); + parameters.Add("side", direction); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/spot/v1/margin/isolated/transfer", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(2, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; } /// - public async Task> GetBaseTradeFeesAsync(CancellationToken ct = default) + public async Task> GetBaseTradeFeesAsync(CancellationToken ct = default) { - var parameters = new ParameterCollection(); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/spot/v1/user_fee", BitMartExchange.RateLimiter.BitMart, 1, true, + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/spot/v1/user_fee", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(2, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; } /// - public async Task> GetSymbolTradeFeeAsync(string symbol, CancellationToken ct = default) + public async Task> GetSymbolTradeFeeAsync(string symbol, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("symbol", symbol); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/spot/v1/trade_fee", BitMartExchange.RateLimiter.BitMart, 1, true, + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/spot/v1/trade_fee", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(2, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; } /// - public async Task> GetWithdrawalAddressesAsync(CancellationToken ct = default) + public async Task> GetWithdrawalAddressesAsync(CancellationToken ct = default) { - var parameters = new ParameterCollection(); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/account/v1/withdraw/address/list", BitMartExchange.RateLimiter.BitMart, 1, true, + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/account/v1/withdraw/address/list", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(2, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); - return result.As(result.Data?.List); + if (!result.Success) + return HttpResult.Fail(result); + + return HttpResult.Ok(result, result.Data.List); } } diff --git a/BitMart.Net/Clients/SpotApi/BitMartRestClientSpotApiExchangeData.cs b/BitMart.Net/Clients/SpotApi/BitMartRestClientSpotApiExchangeData.cs index 9736639..9bd8c5a 100644 --- a/BitMart.Net/Clients/SpotApi/BitMartRestClientSpotApiExchangeData.cs +++ b/BitMart.Net/Clients/SpotApi/BitMartRestClientSpotApiExchangeData.cs @@ -25,138 +25,156 @@ internal BitMartRestClientSpotApiExchangeData(ILogger logger, BitMartRestClientS #region Get Server Time /// - public async Task> GetServerTimeAsync(CancellationToken ct = default) + public async Task> GetServerTimeAsync(CancellationToken ct = default) { - var request = _definitions.GetOrCreate(HttpMethod.Get, "system/time", BitMartExchange.RateLimiter.BitMart, 1, false, new SingleLimitGuard(10, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding), preventCaching: true); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "system/time", BitMartExchange.RateLimiter.BitMart, 1, false, new SingleLimitGuard(10, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding), preventCaching: true); var result = await _baseClient.SendAsync(request, null, ct).ConfigureAwait(false); - return result.As(result.Data?.Timestamp ?? default); + if (!result.Success) + return HttpResult.Fail(result); + + return HttpResult.Ok(result, result.Data.Timestamp); } #endregion /// - public async Task> GetAssetsAsync(CancellationToken ct = default) + public async Task> GetAssetsAsync(CancellationToken ct = default) { - var parameters = new ParameterCollection(); - var request = _definitions.GetOrCreate(HttpMethod.Get, "spot/v1/currencies", BitMartExchange.RateLimiter.BitMart, 1, false, + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "spot/v1/currencies", BitMartExchange.RateLimiter.BitMart, 1, false, new SingleLimitGuard(8, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); - return result.As(result.Data?.Currencies); + if (!result.Success) + return HttpResult.Fail(result); + + return HttpResult.Ok(result, result.Data.Currencies); } /// - public async Task> GetSymbolsAsync(CancellationToken ct = default) + public async Task> GetSymbolsAsync(CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/spot/v1/symbols/details", BitMartExchange.RateLimiter.BitMart, 1, false, + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/spot/v1/symbols/details", BitMartExchange.RateLimiter.BitMart, 1, false, new SingleLimitGuard(12, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); - return result.As(result.Data?.Symbols); + if (!result.Success) + return HttpResult.Fail(result); + + return HttpResult.Ok(result, result.Data.Symbols); } /// - public async Task> GetSymbolNamesAsync(CancellationToken ct = default) + public async Task> GetSymbolNamesAsync(CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/spot/v1/symbols", BitMartExchange.RateLimiter.BitMart, 1, false, + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/spot/v1/symbols", BitMartExchange.RateLimiter.BitMart, 1, false, new SingleLimitGuard(8, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); - return result.As(result.Data?.Symbols); + if (!result.Success) + return HttpResult.Fail(result); + + return HttpResult.Ok(result, result.Data.Symbols); } /// - public async Task> GetTickerAsync(string symbol, CancellationToken ct = default) + public async Task> GetTickerAsync(string symbol, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("symbol", symbol); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/spot/quotation/v3/ticker", BitMartExchange.RateLimiter.BitMart, 1, false, + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/spot/quotation/v3/ticker", BitMartExchange.RateLimiter.BitMart, 1, false, new SingleLimitGuard(15, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; } /// - public async Task> GetTickersAsync(CancellationToken ct = default) + public async Task> GetTickersAsync(CancellationToken ct = default) { - var parameters = new ParameterCollection(); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/spot/quotation/v3/tickers", BitMartExchange.RateLimiter.BitMart, 1, false, + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/spot/quotation/v3/tickers", BitMartExchange.RateLimiter.BitMart, 1, false, new SingleLimitGuard(10, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; } /// - public async Task> GetAssetDepositWithdrawInfoAsync(string? asset = null, CancellationToken ct = default) + public async Task> GetAssetDepositWithdrawInfoAsync(string? asset = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); - parameters.AddOptional("currencies", asset); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/account/v1/currencies", BitMartExchange.RateLimiter.BitMart, 1, false, + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); + parameters.Add("currencies", asset); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/account/v1/currencies", BitMartExchange.RateLimiter.BitMart, 1, false, new SingleLimitGuard(2, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); - return result.As(result.Data?.Currencies); + if (!result.Success) + return HttpResult.Fail(result); + + return HttpResult.Ok(result, result.Data.Currencies); } /// - public async Task> GetServerStatusAsync(CancellationToken ct = default) + public async Task> GetServerStatusAsync(CancellationToken ct = default) { - var parameters = new ParameterCollection(); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/system/service", BitMartExchange.RateLimiter.BitMart, 1, false, + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/system/service", BitMartExchange.RateLimiter.BitMart, 1, false, new SingleLimitGuard(10, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); - return result.As(result.Data?.Service); + if (!result.Success) + return HttpResult.Fail(result); + + return HttpResult.Ok(result, result.Data.Service); } /// - public async Task> GetKlinesAsync(string symbol, KlineInterval klineInterval, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default) + public async Task> GetKlinesAsync(string symbol, KlineInterval klineInterval, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); - parameters.AddOptionalSecondsString("after", startTime); - parameters.AddOptionalSecondsString("before", endTime); - parameters.AddOptional("limit", limit); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); + parameters.Add("after", startTime, DateTimeSerialization.SecondsString); + parameters.Add("before", endTime, DateTimeSerialization.SecondsString); + parameters.Add("limit", limit); parameters.Add("symbol", symbol); - parameters.AddEnum("step", klineInterval); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/spot/quotation/v3/lite-klines", BitMartExchange.RateLimiter.BitMart, 1, false, + parameters.Add("step", klineInterval); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/spot/quotation/v3/lite-klines", BitMartExchange.RateLimiter.BitMart, 1, false, new SingleLimitGuard(15, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; } /// - public async Task> GetKlineHistoryAsync(string symbol, KlineInterval klineInterval, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default) + public async Task> GetKlineHistoryAsync(string symbol, KlineInterval klineInterval, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); - parameters.AddOptionalSecondsString("after", startTime); - parameters.AddOptionalSecondsString("before", endTime); - parameters.AddOptional("limit", limit); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); + parameters.Add("after", startTime, DateTimeSerialization.SecondsString); + parameters.Add("before", endTime, DateTimeSerialization.SecondsString); + parameters.Add("limit", limit); parameters.Add("symbol", symbol); - parameters.AddEnum("step", klineInterval); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/spot/quotation/v3/klines", BitMartExchange.RateLimiter.BitMart, 1, false, + parameters.Add("step", klineInterval); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/spot/quotation/v3/klines", BitMartExchange.RateLimiter.BitMart, 1, false, new SingleLimitGuard(10, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; } /// - public async Task> GetTradesAsync(string symbol, int? limit = null, CancellationToken ct = default) + public async Task> GetTradesAsync(string symbol, int? limit = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); - parameters.AddOptional("limit", limit); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); + parameters.Add("limit", limit); parameters.Add("symbol", symbol); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/spot/quotation/v3/trades", BitMartExchange.RateLimiter.BitMart, 1, false, + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/spot/quotation/v3/trades", BitMartExchange.RateLimiter.BitMart, 1, false, new SingleLimitGuard(15, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; } /// - public async Task> GetOrderBookAsync(string symbol, int? limit = null, CancellationToken ct = default) + public async Task> GetOrderBookAsync(string symbol, int? limit = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); - parameters.AddOptional("limit", limit); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); + parameters.Add("limit", limit); parameters.Add("symbol", symbol); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/spot/quotation/v3/books", BitMartExchange.RateLimiter.BitMart, 1, false, + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/spot/quotation/v3/books", BitMartExchange.RateLimiter.BitMart, 1, false, new SingleLimitGuard(15, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; diff --git a/BitMart.Net/Clients/SpotApi/BitMartRestClientSpotApiMargin.cs b/BitMart.Net/Clients/SpotApi/BitMartRestClientSpotApiMargin.cs index 737e0af..470c39a 100644 --- a/BitMart.Net/Clients/SpotApi/BitMartRestClientSpotApiMargin.cs +++ b/BitMart.Net/Clients/SpotApi/BitMartRestClientSpotApiMargin.cs @@ -23,13 +23,13 @@ internal BitMartRestClientSpotApiMargin(BitMartRestClientSpotApi baseClient) #region Borrow /// - public async Task> BorrowAsync(string symbol, string asset, decimal quantity, CancellationToken ct = default) + public async Task> BorrowAsync(string symbol, string asset, decimal quantity, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("symbol", symbol); parameters.Add("currency", asset); - parameters.AddString("amount", quantity); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/spot/v1/margin/isolated/borrow", BitMartExchange.RateLimiter.BitMart, 1, true, + parameters.Add("amount", quantity); + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/spot/v1/margin/isolated/borrow", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(2, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; @@ -40,13 +40,13 @@ public async Task> BorrowAsync(string symbol, str #region Repay /// - public async Task> RepayAsync(string symbol, string asset, decimal quantity, CancellationToken ct = default) + public async Task> RepayAsync(string symbol, string asset, decimal quantity, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("symbol", symbol); parameters.Add("currency", asset); - parameters.AddString("amount", quantity); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/spot/v1/margin/isolated/repay", BitMartExchange.RateLimiter.BitMart, 1, true, + parameters.Add("amount", quantity); + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/spot/v1/margin/isolated/repay", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(2, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; @@ -57,18 +57,21 @@ public async Task> RepayAsync(string symbol, strin #region Get Borrow History /// - public async Task> GetBorrowHistoryAsync(string symbol, string? borrowId = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default) + public async Task> GetBorrowHistoryAsync(string symbol, string? borrowId = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("symbol", symbol); - parameters.AddOptional("borrow_id", borrowId); - parameters.AddOptionalMilliseconds("start_time", startTime); - parameters.AddOptionalMilliseconds("end_time", endTime); - parameters.AddOptional("N", limit); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/spot/v1/margin/isolated/borrow_record", BitMartExchange.RateLimiter.BitMart, 1, true, + parameters.Add("borrow_id", borrowId); + parameters.Add("start_time", startTime); + parameters.Add("end_time", endTime); + parameters.Add("N", limit); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/spot/v1/margin/isolated/borrow_record", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(60, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); - return result.As(result.Data?.Records); + if (!result.Success) + return HttpResult.Fail(result); + + return HttpResult.Ok(result, result.Data.Records); } #endregion @@ -76,19 +79,22 @@ public async Task> GetBorrowHistoryAsync(string sy #region Get Repay History /// - public async Task> GetRepayHistoryAsync(string symbol, string? asset = null, string? repayId = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default) + public async Task> GetRepayHistoryAsync(string symbol, string? asset = null, string? repayId = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("symbol", symbol); - parameters.AddOptional("currency", asset); - parameters.AddOptional("repay_id", repayId); - parameters.AddOptionalMillisecondsString("start_time", startTime); - parameters.AddOptionalMillisecondsString("end_time", endTime); - parameters.AddOptional("N", limit); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/spot/v1/margin/isolated/repay_record", BitMartExchange.RateLimiter.BitMart, 1, true, + parameters.Add("currency", asset); + parameters.Add("repay_id", repayId); + parameters.Add("start_time", startTime); + parameters.Add("end_time", endTime); + parameters.Add("N", limit); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/spot/v1/margin/isolated/repay_record", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(60, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); - return result.As(result.Data?.Records); + if (!result.Success) + return HttpResult.Fail(result); + + return HttpResult.Ok(result, result.Data.Records); } #endregion @@ -96,14 +102,17 @@ public async Task> GetRepayHistoryAsync(string symb #region Get Borrow Info /// - public async Task> GetBorrowInfoAsync(string? symbol = null, CancellationToken ct = default) + public async Task> GetBorrowInfoAsync(string? symbol = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); - parameters.AddOptional("symbol", symbol); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/spot/v1/margin/isolated/pairs", BitMartExchange.RateLimiter.BitMart, 1, true, + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); + parameters.Add("symbol", symbol); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/spot/v1/margin/isolated/pairs", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(2, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); - return result.As(result.Data?.Symbols); + if (!result.Success) + return HttpResult.Fail(result); + + return HttpResult.Ok(result, result.Data.Symbols); } #endregion diff --git a/BitMart.Net/Clients/SpotApi/BitMartRestClientSpotApiShared.cs b/BitMart.Net/Clients/SpotApi/BitMartRestClientSpotApiShared.cs index 25cc83a..a170b97 100644 --- a/BitMart.Net/Clients/SpotApi/BitMartRestClientSpotApiShared.cs +++ b/BitMart.Net/Clients/SpotApi/BitMartRestClientSpotApiShared.cs @@ -15,15 +15,16 @@ namespace BitMart.Net.Clients.SpotApi internal partial class BitMartRestClientSpotApi : IBitMartRestClientSpotApiShared { private const string _topicId = "BitMartSpot"; - public string Exchange => BitMartExchange.ExchangeName; + private const string _exchangeName = "BitMart"; public TradingMode[] SupportedTradingModes { get; } = new[] { TradingMode.Spot }; public void SetDefaultExchangeParameter(string key, object value) => ExchangeParameters.SetStaticParameter(Exchange, key, value); public void ResetDefaultExchangeParameters() => ExchangeParameters.ResetStaticParameters(); + public SharedClientInfo Discover() => SharedUtils.GetClientInfo(BitMartExchange.Metadata, this); #region Kline client - GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(true, false, true, 200, false, + GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(_exchangeName, true, false, true, 200, false, SharedKlineInterval.OneMinute, SharedKlineInterval.FiveMinutes, SharedKlineInterval.FifteenMinutes, @@ -35,15 +36,12 @@ internal partial class BitMartRestClientSpotApi : IBitMartRestClientSpotApiShare SharedKlineInterval.OneWeek, SharedKlineInterval.OneMonth); - async Task> IKlineRestClient.GetKlinesAsync(GetKlinesRequest request, PageRequest? pageRequest, CancellationToken ct) + async Task> IKlineRestClient.GetKlinesAsync(GetKlinesRequest request, PageRequest? pageRequest, CancellationToken ct) { var interval = (Enums.KlineInterval)request.Interval; - if (!Enum.IsDefined(typeof(Enums.KlineInterval), interval)) - return new ExchangeWebResult(Exchange, ArgumentError.Invalid(nameof(GetKlinesRequest.Interval), "Interval not supported")); - - var validationError = ((IKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, request.Symbol!.TradingMode, SupportedTradingModes); + var validationError = SharedClient.GetKlinesOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var direction = DataDirection.Ascending; var symbol = request.Symbol!.GetSymbol(FormatSymbol); @@ -51,7 +49,7 @@ async Task> IKlineRestClient.GetKlinesAsync(Get var pageParams = Pagination.GetPaginationParameters(direction, limit, request.StartTime, request.EndTime ?? DateTime.UtcNow, pageRequest, true); // Get data - WebCallResult result; + HttpResult result; if ((DateTime.UtcNow - pageParams.EndTime)?.TotalSeconds < (int)interval) { result = await ExchangeData.GetKlinesAsync( @@ -73,8 +71,8 @@ async Task> IKlineRestClient.GetKlinesAsync(Get ct: ct ).ConfigureAwait(false); } - if (!result) - return result.AsExchangeResult(Exchange, null, default); + if (!result.Success) + return HttpResult.Fail(result); var nextPageRequest = Pagination.GetNextPageRequest( () => Pagination.NextPageFromTime(pageParams, result.Data.Max(x => x.OpenTime)), @@ -84,10 +82,7 @@ async Task> IKlineRestClient.GetKlinesAsync(Get request.EndTime ?? DateTime.UtcNow, pageParams); - return result.AsExchangeResult( - Exchange, - request.Symbol.TradingMode, - ExchangeHelpers.ApplyFilter(result.Data, x => x.OpenTime, request.StartTime, request.EndTime, direction) + return HttpResult.Ok(result, ExchangeHelpers.ApplyFilter(result.Data, x => x.OpenTime, request.StartTime, request.EndTime, direction) .Select(x => new SharedKline(request.Symbol, symbol, x.OpenTime, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)) .ToArray(), nextPageRequest); @@ -97,18 +92,18 @@ async Task> IKlineRestClient.GetKlinesAsync(Get #region Spot Symbol client - EndpointOptions ISpotSymbolRestClient.GetSpotSymbolsOptions { get; } = new EndpointOptions(false); - async Task> ISpotSymbolRestClient.GetSpotSymbolsAsync(GetSymbolsRequest request, CancellationToken ct) + GetSpotSymbolsOptions ISpotSymbolRestClient.GetSpotSymbolsOptions { get; } = new GetSpotSymbolsOptions(_exchangeName, false); + async Task> ISpotSymbolRestClient.GetSpotSymbolsAsync(GetSymbolsRequest request, CancellationToken ct) { - var validationError = ((ISpotSymbolRestClient)this).GetSpotSymbolsOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedTradingModes); + var validationError = SharedClient.GetSpotSymbolsOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var result = await ExchangeData.GetSymbolsAsync(ct: ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult(Exchange, null, default); + if (!result.Success) + return HttpResult.Fail(result); - var response = result.AsExchangeResult(Exchange, TradingMode.Spot, result.Data.Select(s => new SharedSpotSymbol(s.BaseAsset, s.QuoteAsset, s.Symbol, s.TradeStatus == SymbolStatus.Trading) + var response = HttpResult.Ok(result, result.Data.Select(s => new SharedSpotSymbol(s.BaseAsset, s.QuoteAsset, s.Symbol, s.TradeStatus == SymbolStatus.Trading) { MinTradeQuantity = s.BaseMinQuantity, QuantityStep = s.BaseMinQuantity, @@ -116,80 +111,80 @@ async Task> ISpotSymbolRestClient.GetSpotS MinNotionalValue = s.MinBuyQuantity == null && s.MinSellQuantity == null ? null : Math.Min(s.MinBuyQuantity ?? decimal.MaxValue, s.MinSellQuantity ?? decimal.MaxValue) }).ToArray()); - ExchangeSymbolCache.UpdateSymbolInfo(_topicId, response.Data); + ExchangeSymbolCache.UpdateSymbolInfo(_topicId, EnvironmentName, null, response.Data!); return response; } - async Task> ISpotSymbolRestClient.GetSpotSymbolsForBaseAssetAsync(string baseAsset) + async Task> ISpotSymbolRestClient.GetSpotSymbolsForBaseAssetAsync(string baseAsset) { - if (!ExchangeSymbolCache.HasCached(_topicId)) + if (!ExchangeSymbolCache.HasCached(_topicId, EnvironmentName, null)) { var symbols = await ((ISpotSymbolRestClient)this).GetSpotSymbolsAsync(new GetSymbolsRequest()).ConfigureAwait(false); - if (!symbols) - return new ExchangeResult(Exchange, symbols.Error!); + if (!symbols.Success) + return ExchangeCallResult.Fail(Exchange, symbols.Error!); } - return new ExchangeResult(Exchange, ExchangeSymbolCache.GetSymbolsForBaseAsset(_topicId, baseAsset)); + return ExchangeCallResult.Ok(Exchange, ExchangeSymbolCache.GetSymbolsForBaseAsset(_topicId, EnvironmentName, null, baseAsset)); } - async Task> ISpotSymbolRestClient.SupportsSpotSymbolAsync(SharedSymbol symbol) + async Task> ISpotSymbolRestClient.SupportsSpotSymbolAsync(SharedSymbol symbol) { if (symbol.TradingMode != TradingMode.Spot) throw new ArgumentException(nameof(symbol), "Only Spot symbols allowed"); - if (!ExchangeSymbolCache.HasCached(_topicId)) + if (!ExchangeSymbolCache.HasCached(_topicId, EnvironmentName, null)) { var symbols = await ((ISpotSymbolRestClient)this).GetSpotSymbolsAsync(new GetSymbolsRequest()).ConfigureAwait(false); - if (!symbols) - return new ExchangeResult(Exchange, symbols.Error!); + if (!symbols.Success) + return ExchangeCallResult.Fail(Exchange, symbols.Error!); } - return new ExchangeResult(Exchange, ExchangeSymbolCache.SupportsSymbol(_topicId, symbol)); + return ExchangeCallResult.Ok(Exchange, ExchangeSymbolCache.SupportsSymbol(_topicId, EnvironmentName, null, symbol)); } - async Task> ISpotSymbolRestClient.SupportsSpotSymbolAsync(string symbolName) + async Task> ISpotSymbolRestClient.SupportsSpotSymbolAsync(string symbolName) { - if (!ExchangeSymbolCache.HasCached(_topicId)) + if (!ExchangeSymbolCache.HasCached(_topicId, EnvironmentName, null)) { var symbols = await ((ISpotSymbolRestClient)this).GetSpotSymbolsAsync(new GetSymbolsRequest()).ConfigureAwait(false); - if (!symbols) - return new ExchangeResult(Exchange, symbols.Error!); + if (!symbols.Success) + return ExchangeCallResult.Fail(Exchange, symbols.Error!); } - return new ExchangeResult(Exchange, ExchangeSymbolCache.SupportsSymbol(_topicId, symbolName)); + return ExchangeCallResult.Ok(Exchange, ExchangeSymbolCache.SupportsSymbol(_topicId, EnvironmentName, null, symbolName)); } #endregion #region Ticker client - GetTickerOptions ISpotTickerRestClient.GetSpotTickerOptions { get; } = new GetTickerOptions(); - async Task> ISpotTickerRestClient.GetSpotTickerAsync(GetTickerRequest request, CancellationToken ct) + GetSpotTickerOptions ISpotTickerRestClient.GetSpotTickerOptions { get; } = new GetSpotTickerOptions(_exchangeName); + async Task> ISpotTickerRestClient.GetSpotTickerAsync(GetTickerRequest request, CancellationToken ct) { - var validationError = ((ISpotTickerRestClient)this).GetSpotTickerOptions.ValidateRequest(Exchange, request, request.Symbol!.TradingMode, SupportedTradingModes); + var validationError = SharedClient.GetSpotTickerOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var result = await ExchangeData.GetTickerAsync(request.Symbol!.GetSymbol(FormatSymbol), ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult(Exchange, null, default); + if (!result.Success) + return HttpResult.Fail(result); - return result.AsExchangeResult(Exchange, TradingMode.Spot, new SharedSpotTicker(ExchangeSymbolCache.ParseSymbol(_topicId, result.Data.Symbol), result.Data.Symbol, result.Data.LastPrice, result.Data.HighPrice, result.Data.LowPrice, result.Data.Volume24h, result.Data.Change * 100) + return HttpResult.Ok(result, new SharedSpotTicker(ExchangeSymbolCache.ParseSymbol(_topicId, EnvironmentName, null, result.Data.Symbol), result.Data.Symbol, result.Data.LastPrice, result.Data.HighPrice, result.Data.LowPrice, result.Data.Volume24h, result.Data.Change * 100) { QuoteVolume = result.Data.QuoteVolume24h }); } - GetTickersOptions ISpotTickerRestClient.GetSpotTickersOptions { get; } = new GetTickersOptions(); - async Task> ISpotTickerRestClient.GetSpotTickersAsync(GetTickersRequest request, CancellationToken ct) + GetSpotTickersOptions ISpotTickerRestClient.GetSpotTickersOptions { get; } = new GetSpotTickersOptions(_exchangeName); + async Task> ISpotTickerRestClient.GetSpotTickersAsync(GetTickersRequest request, CancellationToken ct) { - var validationError = ((ISpotTickerRestClient)this).GetSpotTickersOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedTradingModes); + var validationError = SharedClient.GetSpotTickersOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var result = await ExchangeData.GetTickersAsync(ct: ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult(Exchange, null, default); + if (!result.Success) + return HttpResult.Fail(result); - return result.AsExchangeResult(Exchange, TradingMode.Spot, result.Data.Select(x => new SharedSpotTicker(ExchangeSymbolCache.ParseSymbol(_topicId, x.Symbol), x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume24h, x.Change * 100) + return HttpResult.Ok(result, result.Data.Select(x => new SharedSpotTicker(ExchangeSymbolCache.ParseSymbol(_topicId, EnvironmentName, null, x.Symbol), x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume24h, x.Change * 100) { QuoteVolume = x.QuoteVolume24h }).ToArray()); @@ -199,19 +194,19 @@ async Task> ISpotTickerRestClient.GetSpotT #region Book Ticker client - EndpointOptions IBookTickerRestClient.GetBookTickerOptions { get; } = new EndpointOptions(false); - async Task> IBookTickerRestClient.GetBookTickerAsync(GetBookTickerRequest request, CancellationToken ct) + GetBookTickerOptions IBookTickerRestClient.GetBookTickerOptions { get; } = new GetBookTickerOptions(_exchangeName, false); + async Task> IBookTickerRestClient.GetBookTickerAsync(GetBookTickerRequest request, CancellationToken ct) { - var validationError = ((IBookTickerRestClient)this).GetBookTickerOptions.ValidateRequest(Exchange, request, request.Symbol!.TradingMode, SupportedTradingModes); + var validationError = SharedClient.GetBookTickerOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var resultTicker = await ExchangeData.GetOrderBookAsync(request.Symbol!.GetSymbol(FormatSymbol), 1, ct: ct).ConfigureAwait(false); - if (!resultTicker) - return resultTicker.AsExchangeResult(Exchange, null, default); + if (!resultTicker.Success) + return HttpResult.Fail(resultTicker); - return resultTicker.AsExchangeResult(Exchange, request.Symbol!.TradingMode, new SharedBookTicker( - ExchangeSymbolCache.ParseSymbol(_topicId, resultTicker.Data.Symbol), + return HttpResult.Ok(resultTicker, new SharedBookTicker( + ExchangeSymbolCache.ParseSymbol(_topicId, EnvironmentName, null, resultTicker.Data.Symbol), resultTicker.Data.Symbol, resultTicker.Data.Asks[0].Price, resultTicker.Data.Asks[0].Quantity, @@ -222,23 +217,23 @@ async Task> IBookTickerRestClient.GetBookTic #endregion #region Recent Trade client - GetRecentTradesOptions IRecentTradeRestClient.GetRecentTradesOptions { get; } = new GetRecentTradesOptions(50, false); + GetRecentTradesOptions IRecentTradeRestClient.GetRecentTradesOptions { get; } = new GetRecentTradesOptions(_exchangeName, 50, false); - async Task> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, CancellationToken ct) + async Task> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, CancellationToken ct) { - var validationError = ((IRecentTradeRestClient)this).GetRecentTradesOptions.ValidateRequest(Exchange, request, request.Symbol!.TradingMode, SupportedTradingModes); + var validationError = SharedClient.GetRecentTradesOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var symbol = request.Symbol!.GetSymbol(FormatSymbol); var result = await ExchangeData.GetTradesAsync( symbol, limit: request.Limit, ct: ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult(Exchange, null, default); + if (!result.Success) + return HttpResult.Fail(result); - return result.AsExchangeResult(Exchange, request.Symbol!.TradingMode, result.Data.Select(x => + return HttpResult.Ok(result, result.Data.Select(x => new SharedTrade(request.Symbol, symbol, x.Quantity, x.Price, x.Timestamp) { Side = x.Side == OrderSide.Buy ? SharedOrderSide.Buy : SharedOrderSide.Sell, @@ -248,29 +243,39 @@ async Task> IRecentTradeRestClient.GetRecentTra #endregion #region Balance client - GetBalancesOptions IBalanceRestClient.GetBalancesOptions { get; } = new GetBalancesOptions(AccountTypeFilter.Spot, AccountTypeFilter.Funding); + GetBalancesOptions IBalanceRestClient.GetBalancesOptions { get; } = new GetBalancesOptions(_exchangeName, AccountTypeFilter.Spot, AccountTypeFilter.Funding); - async Task> IBalanceRestClient.GetBalancesAsync(GetBalancesRequest request, CancellationToken ct) + async Task> IBalanceRestClient.GetBalancesAsync(GetBalancesRequest request, CancellationToken ct) { - var validationError = ((IBalanceRestClient)this).GetBalancesOptions.ValidateRequest(Exchange, request, SupportedTradingModes); + var validationError = SharedClient.GetBalancesOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); if (request.AccountType == SharedAccountType.Funding) { var result = await Account.GetFundingBalancesAsync(ct: ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult(Exchange, null, default); - - return result.AsExchangeResult(Exchange, TradingMode.Spot, result.Data.Select(x => new SharedBalance(x.Name, x.Available, x.Available + x.Frozen)).ToArray()); + if (!result.Success) + return HttpResult.Fail(result); + + return HttpResult.Ok(result, result.Data.Select(x => + new SharedBalance( + SupportedTradingModes, + x.Name, + x.Available, + x.Available + x.Frozen)).ToArray()); } else { var result = await Account.GetSpotBalancesAsync(ct: ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult(Exchange, null, default); - - return result.AsExchangeResult(Exchange, TradingMode.Spot, result.Data.Select(x => new SharedBalance(x.Id, x.Available, x.Available + x.Frozen)).ToArray()); + if (!result.Success) + return HttpResult.Fail(result); + + return HttpResult.Ok(result, result.Data.Select(x => + new SharedBalance( + SupportedTradingModes, + x.Id, + x.Available, + x.Available + x.Frozen)).ToArray()); } } @@ -290,19 +295,12 @@ async Task> IBalanceRestClient.GetBalancesAsy string ISpotOrderRestClient.GenerateClientOrderId() => ExchangeHelpers.RandomString(32); - PlaceSpotOrderOptions ISpotOrderRestClient.PlaceSpotOrderOptions { get; } = new PlaceSpotOrderOptions(); - async Task> ISpotOrderRestClient.PlaceSpotOrderAsync(PlaceSpotOrderRequest request, CancellationToken ct) - { - var validationError = ((ISpotOrderRestClient)this).PlaceSpotOrderOptions.ValidateRequest( - Exchange, - request, - request.Symbol!.TradingMode, - SupportedTradingModes, - ((ISpotOrderRestClient)this).SpotSupportedOrderTypes, - ((ISpotOrderRestClient)this).SpotSupportedTimeInForce, - ((ISpotOrderRestClient)this).SpotSupportedOrderQuantity); + PlaceSpotOrderOptions ISpotOrderRestClient.PlaceSpotOrderOptions { get; } = new PlaceSpotOrderOptions(_exchangeName); + async Task> ISpotOrderRestClient.PlaceSpotOrderAsync(PlaceSpotOrderRequest request, CancellationToken ct) + { + var validationError = SharedClient.PlaceSpotOrderOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var result = await Trading.PlaceOrderAsync( request.Symbol!.GetSymbol(FormatSymbol), @@ -314,25 +312,25 @@ async Task> ISpotOrderRestClient.PlaceSpotOrderAsync clientOrderId: request.ClientOrderId, ct: ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult(Exchange, null, default); + if (!result.Success) + return HttpResult.Fail(result); - return result.AsExchangeResult(Exchange, request.Symbol!.TradingMode, new SharedId(result.Data.OrderId)); + return HttpResult.Ok(result, new SharedId(result.Data.OrderId)); } - EndpointOptions ISpotOrderRestClient.GetSpotOrderOptions { get; } = new EndpointOptions(true); - async Task> ISpotOrderRestClient.GetSpotOrderAsync(GetOrderRequest request, CancellationToken ct) + GetSpotOrderOptions ISpotOrderRestClient.GetSpotOrderOptions { get; } = new GetSpotOrderOptions(_exchangeName, true); + async Task> ISpotOrderRestClient.GetSpotOrderAsync(GetOrderRequest request, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetSpotOrderOptions.ValidateRequest(Exchange, request, request.Symbol!.TradingMode, SupportedTradingModes); + var validationError = SharedClient.GetSpotOrderOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var order = await Trading.GetOrderAsync(request.OrderId, ct: ct).ConfigureAwait(false); - if (!order) - return order.AsExchangeResult(Exchange, null, default); + if (!order.Success) + return HttpResult.Fail(order); - return order.AsExchangeResult(Exchange, TradingMode.Spot, new SharedSpotOrder( - ExchangeSymbolCache.ParseSymbol(_topicId, order.Data.Symbol), + return HttpResult.Ok(order, new SharedSpotOrder( + ExchangeSymbolCache.ParseSymbol(_topicId, EnvironmentName, null, order.Data.Symbol), order.Data.Symbol, order.Data.OrderId.ToString(), ParseOrderType(order.Data.OrderType), @@ -350,20 +348,20 @@ async Task> ISpotOrderRestClient.GetSpotOrder }); } - EndpointOptions ISpotOrderRestClient.GetOpenSpotOrdersOptions { get; } = new EndpointOptions(true); - async Task> ISpotOrderRestClient.GetOpenSpotOrdersAsync(GetOpenOrdersRequest request, CancellationToken ct) + GetOpenSpotOrdersOptions ISpotOrderRestClient.GetOpenSpotOrdersOptions { get; } = new GetOpenSpotOrdersOptions(_exchangeName, true); + async Task> ISpotOrderRestClient.GetOpenSpotOrdersAsync(GetOpenOrdersRequest request, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetOpenSpotOrdersOptions.ValidateRequest(Exchange, request, request.Symbol?.TradingMode ?? request.TradingMode, SupportedTradingModes); + var validationError = SharedClient.GetOpenSpotOrdersOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var symbol = request.Symbol?.GetSymbol(FormatSymbol); var orders = await Trading.GetOpenOrdersAsync(symbol, ct: ct).ConfigureAwait(false); - if (!orders) - return orders.AsExchangeResult(Exchange, null, default); + if (!orders.Success) + return HttpResult.Fail(orders); - return orders.AsExchangeResult(Exchange, TradingMode.Spot, orders.Data.Select(x => new SharedSpotOrder( - ExchangeSymbolCache.ParseSymbol(_topicId, x.Symbol), + return HttpResult.Ok(orders, orders.Data.Select(x => new SharedSpotOrder( + ExchangeSymbolCache.ParseSymbol(_topicId, EnvironmentName, null, x.Symbol), x.Symbol, x.OrderId.ToString(), ParseOrderType(x.OrderType), @@ -381,12 +379,12 @@ async Task> ISpotOrderRestClient.GetOpenSpo }).ToArray()); } - GetClosedOrdersOptions ISpotOrderRestClient.GetClosedSpotOrdersOptions { get; } = new GetClosedOrdersOptions(false, true, true, 200); - async Task> ISpotOrderRestClient.GetClosedSpotOrdersAsync(GetClosedOrdersRequest request, PageRequest? pageRequest, CancellationToken ct) + GetSpotClosedOrdersOptions ISpotOrderRestClient.GetClosedSpotOrdersOptions { get; } = new GetSpotClosedOrdersOptions(_exchangeName, false, true, true, 200); + async Task> ISpotOrderRestClient.GetClosedSpotOrdersAsync(GetClosedOrdersRequest request, PageRequest? pageRequest, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetClosedSpotOrdersOptions.ValidateRequest(Exchange, request, request.Symbol!.TradingMode, SupportedTradingModes); + var validationError = SharedClient.GetClosedSpotOrdersOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var direction = DataDirection.Descending; var limit = 200; @@ -399,8 +397,8 @@ async Task> ISpotOrderRestClient.GetClosedS endTime: pageParams.EndTime, limit: limit, ct: ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult(Exchange, null, default); + if (!result.Success) + return HttpResult.Fail(result); var nextPageRequest = Pagination.GetNextPageRequest( () => Pagination.NextPageFromTime(pageParams, result.Data.Min(x => x.CreateTime)), @@ -410,13 +408,10 @@ async Task> ISpotOrderRestClient.GetClosedS request.EndTime ?? DateTime.UtcNow, pageParams); - return result.AsExchangeResult( - Exchange, - request.Symbol.TradingMode, - ExchangeHelpers.ApplyFilter(result.Data, x => x.CreateTime, request.StartTime, request.EndTime, direction) + return HttpResult.Ok(result, ExchangeHelpers.ApplyFilter(result.Data, x => x.CreateTime, request.StartTime, request.EndTime, direction) .Select(x => new SharedSpotOrder( - ExchangeSymbolCache.ParseSymbol(_topicId, x.Symbol), + ExchangeSymbolCache.ParseSymbol(_topicId, EnvironmentName, null, x.Symbol), x.Symbol, x.OrderId.ToString(), ParseOrderType(x.OrderType), @@ -435,19 +430,19 @@ async Task> ISpotOrderRestClient.GetClosedS .ToArray(), nextPageRequest); } - EndpointOptions ISpotOrderRestClient.GetSpotOrderTradesOptions { get; } = new EndpointOptions(true); - async Task> ISpotOrderRestClient.GetSpotOrderTradesAsync(GetOrderTradesRequest request, CancellationToken ct) + GetSpotOrderTradesOptions ISpotOrderRestClient.GetSpotOrderTradesOptions { get; } = new GetSpotOrderTradesOptions(_exchangeName, true); + async Task> ISpotOrderRestClient.GetSpotOrderTradesAsync(GetOrderTradesRequest request, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetSpotOrderTradesOptions.ValidateRequest(Exchange, request, request.Symbol!.TradingMode, SupportedTradingModes); + var validationError = SharedClient.GetSpotOrderTradesOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var trades = await Trading.GetOrderTradesAsync(request.OrderId, ct: ct).ConfigureAwait(false); - if (!trades) - return trades.AsExchangeResult(Exchange, null, default); + if (!trades.Success) + return HttpResult.Fail(trades); - return trades.AsExchangeResult(Exchange, TradingMode.Spot, trades.Data.Select(x => new SharedUserTrade( - ExchangeSymbolCache.ParseSymbol(_topicId, x.Symbol), + return HttpResult.Ok(trades, trades.Data.Select(x => new SharedUserTrade( + ExchangeSymbolCache.ParseSymbol(_topicId, EnvironmentName, null, x.Symbol), x.Symbol, x.OrderId, x.TradeId, @@ -463,12 +458,12 @@ async Task> ISpotOrderRestClient.GetSpotOrd }).ToArray()); } - GetUserTradesOptions ISpotOrderRestClient.GetSpotUserTradesOptions { get; } = new GetUserTradesOptions (false, true, true, 200); - async Task> ISpotOrderRestClient.GetSpotUserTradesAsync(GetUserTradesRequest request, PageRequest? pageRequest, CancellationToken ct) + GetSpotUserTradesOptions ISpotOrderRestClient.GetSpotUserTradesOptions { get; } = new GetSpotUserTradesOptions(_exchangeName, false, true, true, 200); + async Task> ISpotOrderRestClient.GetSpotUserTradesAsync(GetUserTradesRequest request, PageRequest? pageRequest, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetSpotUserTradesOptions.ValidateRequest(Exchange, request, request.Symbol!.TradingMode, SupportedTradingModes); + var validationError = SharedClient.GetSpotUserTradesOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var direction = DataDirection.Descending; var limit = request.Limit ?? 200; @@ -480,8 +475,8 @@ async Task> ISpotOrderRestClient.GetSpotUse endTime: pageParams.EndTime, limit: limit, ct: ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult(Exchange, null, default); + if (!result.Success) + return HttpResult.Fail(result); var nextPageRequest = Pagination.GetNextPageRequest( () => Pagination.NextPageFromTime(pageParams, result.Data.Min(x => x.CreateTime)), @@ -491,13 +486,10 @@ async Task> ISpotOrderRestClient.GetSpotUse request.EndTime ?? DateTime.UtcNow, pageParams); - return result.AsExchangeResult( - Exchange, - request.Symbol.TradingMode, - ExchangeHelpers.ApplyFilter(result.Data, x => x.CreateTime, request.StartTime, request.EndTime, direction) + return HttpResult.Ok(result, ExchangeHelpers.ApplyFilter(result.Data, x => x.CreateTime, request.StartTime, request.EndTime, direction) .Select(x => new SharedUserTrade( - ExchangeSymbolCache.ParseSymbol(_topicId, x.Symbol), + ExchangeSymbolCache.ParseSymbol(_topicId, EnvironmentName, null, x.Symbol), x.Symbol, x.OrderId, x.TradeId, @@ -514,18 +506,18 @@ async Task> ISpotOrderRestClient.GetSpotUse .ToArray(), nextPageRequest); } - EndpointOptions ISpotOrderRestClient.CancelSpotOrderOptions { get; } = new EndpointOptions(true); - async Task> ISpotOrderRestClient.CancelSpotOrderAsync(CancelOrderRequest request, CancellationToken ct) + CancelSpotOrderOptions ISpotOrderRestClient.CancelSpotOrderOptions { get; } = new CancelSpotOrderOptions(_exchangeName, true); + async Task> ISpotOrderRestClient.CancelSpotOrderAsync(CancelOrderRequest request, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).CancelSpotOrderOptions.ValidateRequest(Exchange, request, request.Symbol!.TradingMode, SupportedTradingModes); + var validationError = SharedClient.CancelSpotOrderOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var order = await Trading.CancelOrderAsync(request.Symbol!.GetSymbol(FormatSymbol), request.OrderId, ct: ct).ConfigureAwait(false); - if (!order) - return order.AsExchangeResult(Exchange, null, default); + if (!order.Success) + return HttpResult.Fail(order); - return order.AsExchangeResult(Exchange, request.Symbol!.TradingMode, new SharedId(request.OrderId)); + return HttpResult.Ok(order, new SharedId(request.OrderId)); } private SharedOrderStatus ParseOrderStatus(OrderStatus status) @@ -568,19 +560,19 @@ private OrderType GetOrderType(SharedOrderType type, SharedTimeInForce? tif) #region Spot Client Id Order Client - EndpointOptions ISpotOrderClientIdRestClient.GetSpotOrderByClientOrderIdOptions { get; } = new EndpointOptions(true); - async Task> ISpotOrderClientIdRestClient.GetSpotOrderByClientOrderIdAsync(GetOrderRequest request, CancellationToken ct) + GetSpotOrderByClientOrderIdOptions ISpotOrderClientIdRestClient.GetSpotOrderByClientOrderIdOptions { get; } = new GetSpotOrderByClientOrderIdOptions(_exchangeName, true); + async Task> ISpotOrderClientIdRestClient.GetSpotOrderByClientOrderIdAsync(GetOrderRequest request, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).GetSpotOrderOptions.ValidateRequest(Exchange, request, request.Symbol!.TradingMode, SupportedTradingModes); + var validationError = SharedClient.GetSpotOrderOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var order = await Trading.GetOrderByClientOrderIdAsync(request.OrderId, ct: ct).ConfigureAwait(false); - if (!order) - return order.AsExchangeResult(Exchange, null, default); + if (!order.Success) + return HttpResult.Fail(order); - return order.AsExchangeResult(Exchange, TradingMode.Spot, new SharedSpotOrder( - ExchangeSymbolCache.ParseSymbol(_topicId, order.Data.Symbol), + return HttpResult.Ok(order, new SharedSpotOrder( + ExchangeSymbolCache.ParseSymbol(_topicId, EnvironmentName, null, order.Data.Symbol), order.Data.Symbol, order.Data.OrderId.ToString(), ParseOrderType(order.Data.OrderType), @@ -598,38 +590,38 @@ async Task> ISpotOrderClientIdRestClient.GetS }); } - EndpointOptions ISpotOrderClientIdRestClient.CancelSpotOrderByClientOrderIdOptions { get; } = new EndpointOptions(true); - async Task> ISpotOrderClientIdRestClient.CancelSpotOrderByClientOrderIdAsync(CancelOrderRequest request, CancellationToken ct) + CancelSpotOrderByClientOrderIdOptions ISpotOrderClientIdRestClient.CancelSpotOrderByClientOrderIdOptions { get; } = new CancelSpotOrderByClientOrderIdOptions(_exchangeName, true); + async Task> ISpotOrderClientIdRestClient.CancelSpotOrderByClientOrderIdAsync(CancelOrderRequest request, CancellationToken ct) { - var validationError = ((ISpotOrderRestClient)this).CancelSpotOrderOptions.ValidateRequest(Exchange, request, request.Symbol!.TradingMode, SupportedTradingModes); + var validationError = SharedClient.CancelSpotOrderOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var order = await Trading.CancelOrderAsync(request.Symbol!.GetSymbol(FormatSymbol), clientOrderId: request.OrderId, ct: ct).ConfigureAwait(false); - if (!order) - return order.AsExchangeResult(Exchange, null, default); + if (!order.Success) + return HttpResult.Fail(order); - return order.AsExchangeResult(Exchange, TradingMode.Spot, new SharedId(request.OrderId)); + return HttpResult.Ok(order, new SharedId(request.OrderId)); } #endregion #region Asset client - EndpointOptions IAssetsRestClient.GetAssetOptions { get; } = new EndpointOptions(false); - async Task> IAssetsRestClient.GetAssetAsync(GetAssetRequest request, CancellationToken ct) + GetAssetOptions IAssetsRestClient.GetAssetOptions { get; } = new GetAssetOptions(_exchangeName, false); + async Task> IAssetsRestClient.GetAssetAsync(GetAssetRequest request, CancellationToken ct) { - var validationError = ((IAssetsRestClient)this).GetAssetOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedTradingModes); + var validationError = SharedClient.GetAssetOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var assets = await ExchangeData.GetAssetDepositWithdrawInfoAsync(ct: ct).ConfigureAwait(false); - if (!assets) - return assets.AsExchangeResult(Exchange, null, default); + if (!assets.Success) + return HttpResult.Fail(assets); var asset = assets.Data.Where(x => x.Asset.Split(new[] { "-" }, StringSplitOptions.RemoveEmptyEntries)[0].Equals(request.Asset, StringComparison.InvariantCultureIgnoreCase)).ToList(); if (asset == null) - return assets.AsExchangeError(Exchange, new ServerError(new ErrorInfo(ErrorType.UnknownAsset, "Asset not found"))); + return HttpResult.Fail(Exchange, new ServerError(new ErrorInfo(ErrorType.UnknownAsset, "Asset not found"))); - return assets.AsExchangeResult(Exchange, TradingMode.Spot, new SharedAsset(request.Asset) + return HttpResult.Ok(assets, new SharedAsset(request.Asset) { Networks = asset.Select(x => new SharedAssetNetwork(x.Network) { @@ -642,19 +634,19 @@ async Task> IAssetsRestClient.GetAssetAsync(GetAs }); } - EndpointOptions IAssetsRestClient.GetAssetsOptions { get; } = new EndpointOptions(false); + GetAssetsOptions IAssetsRestClient.GetAssetsOptions { get; } = new GetAssetsOptions(_exchangeName, false); - async Task> IAssetsRestClient.GetAssetsAsync(GetAssetsRequest request, CancellationToken ct) + async Task> IAssetsRestClient.GetAssetsAsync(GetAssetsRequest request, CancellationToken ct) { - var validationError = ((IAssetsRestClient)this).GetAssetsOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedTradingModes); + var validationError = SharedClient.GetAssetsOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var assets = await ExchangeData.GetAssetDepositWithdrawInfoAsync(ct: ct).ConfigureAwait(false); - if (!assets) - return assets.AsExchangeResult(Exchange, null, default); + if (!assets.Success) + return HttpResult.Fail(assets); - return assets.AsExchangeResult(Exchange, TradingMode.Spot, assets.Data.GroupBy(x => x.Asset.Split(new[] { "-" }, StringSplitOptions.RemoveEmptyEntries)[0]).Select(x => new SharedAsset(x.Key) + return HttpResult.Ok(assets, assets.Data.GroupBy(x => x.Asset.Split(new[] { "-" }, StringSplitOptions.RemoveEmptyEntries)[0]).Select(x => new SharedAsset(x.Key) { Networks = x.Select(x => new SharedAssetNetwork(x.Network) { @@ -671,22 +663,22 @@ async Task> IAssetsRestClient.GetAssetsAsync(Ge #region Deposit client - EndpointOptions IDepositRestClient.GetDepositAddressesOptions { get; } = new EndpointOptions(true); - async Task> IDepositRestClient.GetDepositAddressesAsync(GetDepositAddressesRequest request, CancellationToken ct) + GetDepositAddressesOptions IDepositRestClient.GetDepositAddressesOptions { get; } = new GetDepositAddressesOptions(_exchangeName, true); + async Task> IDepositRestClient.GetDepositAddressesAsync(GetDepositAddressesRequest request, CancellationToken ct) { - var validationError = ((IDepositRestClient)this).GetDepositAddressesOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedTradingModes); + var validationError = SharedClient.GetDepositAddressesOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var assetName = request.Asset; if (request.Network != null && request.Network != request.Asset) assetName += "-" + request.Network; var depositAddresses = await Account.GetDepositAddressAsync(assetName).ConfigureAwait(false); - if (!depositAddresses) - return depositAddresses.AsExchangeResult(Exchange, null, default); + if (!depositAddresses.Success) + return HttpResult.Fail(depositAddresses); - return depositAddresses.AsExchangeResult(Exchange, TradingMode.Spot, new[] { new SharedDepositAddress(depositAddresses.Data.Asset.Split(new[] { "-" }, StringSplitOptions.RemoveEmptyEntries)[0], depositAddresses.Data.Address) + return HttpResult.Ok(depositAddresses, new[] { new SharedDepositAddress(depositAddresses.Data.Asset.Split(new[] { "-" }, StringSplitOptions.RemoveEmptyEntries)[0], depositAddresses.Data.Address) { TagOrMemo = depositAddresses.Data.AddressMemo, Network = depositAddresses.Data.Network @@ -694,12 +686,12 @@ async Task> IDepositRestClient.GetDepo }); } - GetDepositsOptions IDepositRestClient.GetDepositsOptions { get; } = new GetDepositsOptions(false, true, true, 1000); - async Task> IDepositRestClient.GetDepositsAsync(GetDepositsRequest request, PageRequest? pageRequest, CancellationToken ct) + GetDepositsOptions IDepositRestClient.GetDepositsOptions { get; } = new GetDepositsOptions(_exchangeName, false, true, true, 1000); + async Task> IDepositRestClient.GetDepositsAsync(GetDepositsRequest request, PageRequest? pageRequest, CancellationToken ct) { - var validationError = ((IDepositRestClient)this).GetDepositsOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedTradingModes); + var validationError = SharedClient.GetDepositsOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var direction = DataDirection.Descending; var limit = request.Limit ?? 1000; @@ -713,8 +705,8 @@ async Task> IDepositRestClient.GetDepositsAsy endTime: pageParams.EndTime, limit: pageParams.Limit, ct: ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult(Exchange, null, default); + if (!result.Success) + return HttpResult.Fail(result); var nextPageRequest = Pagination.GetNextPageRequest( () => Pagination.NextPageFromTime(pageParams, result.Data.Min(x => x.ApplyTime)), @@ -725,10 +717,7 @@ async Task> IDepositRestClient.GetDepositsAsy pageParams, maxTimespan); - return result.AsExchangeResult( - Exchange, - TradingMode.Spot, - ExchangeHelpers.ApplyFilter(result.Data, x => x.ApplyTime, request.StartTime, request.EndTime, direction) + return HttpResult.Ok(result, ExchangeHelpers.ApplyFilter(result.Data, x => x.ApplyTime, request.StartTime, request.EndTime, direction) .Select(x => new SharedDeposit( x.Asset.Split(new[] { "-" }, StringSplitOptions.RemoveEmptyEntries)[0], @@ -760,33 +749,33 @@ private SharedTransferStatus ParseTransferStatus(DepositWithdrawalStatus status) #region Order Book client - GetOrderBookOptions IOrderBookRestClient.GetOrderBookOptions { get; } = new GetOrderBookOptions(1, 50, false); - async Task> IOrderBookRestClient.GetOrderBookAsync(GetOrderBookRequest request, CancellationToken ct) + GetOrderBookOptions IOrderBookRestClient.GetOrderBookOptions { get; } = new GetOrderBookOptions(_exchangeName, 1, 50, false); + async Task> IOrderBookRestClient.GetOrderBookAsync(GetOrderBookRequest request, CancellationToken ct) { - var validationError = ((IOrderBookRestClient)this).GetOrderBookOptions.ValidateRequest(Exchange, request, request.Symbol!.TradingMode, SupportedTradingModes); + var validationError = SharedClient.GetOrderBookOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var result = await ExchangeData.GetOrderBookAsync( request.Symbol!.GetSymbol(FormatSymbol), limit: request.Limit, ct: ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult(Exchange, null, default); + if (!result.Success) + return HttpResult.Fail(result); - return result.AsExchangeResult(Exchange, request.Symbol!.TradingMode, new SharedOrderBook(result.Data.Asks, result.Data.Bids)); + return HttpResult.Ok(result, new SharedOrderBook(result.Data.Asks, result.Data.Bids)); } #endregion #region Withdrawal client - GetWithdrawalsOptions IWithdrawalRestClient.GetWithdrawalsOptions { get; } = new GetWithdrawalsOptions(false, true, true, 1000); - async Task> IWithdrawalRestClient.GetWithdrawalsAsync(GetWithdrawalsRequest request, PageRequest? pageRequest, CancellationToken ct) + GetWithdrawalsOptions IWithdrawalRestClient.GetWithdrawalsOptions { get; } = new GetWithdrawalsOptions(_exchangeName, false, true, true, 1000); + async Task> IWithdrawalRestClient.GetWithdrawalsAsync(GetWithdrawalsRequest request, PageRequest? pageRequest, CancellationToken ct) { - var validationError = ((IWithdrawalRestClient)this).GetWithdrawalsOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedTradingModes); + var validationError = SharedClient.GetWithdrawalsOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var direction = DataDirection.Descending; var limit = request.Limit ?? 1000; @@ -800,8 +789,8 @@ async Task> IWithdrawalRestClient.GetWithd endTime: pageParams.EndTime, limit: pageParams.Limit, ct: ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult(Exchange, null, default); + if (!result.Success) + return HttpResult.Fail(result); var nextPageRequest = Pagination.GetNextPageRequest( () => Pagination.NextPageFromTime(pageParams, result.Data.Min(x => x.ApplyTime)), @@ -812,12 +801,15 @@ async Task> IWithdrawalRestClient.GetWithd pageParams, maxTimespan); - return result.AsExchangeResult( - Exchange, - TradingMode.Spot, - ExchangeHelpers.ApplyFilter(result.Data, x => x.ApplyTime, request.StartTime, request.EndTime, direction) + return HttpResult.Ok(result, ExchangeHelpers.ApplyFilter(result.Data, x => x.ApplyTime, request.StartTime, request.EndTime, direction) .Select(x => - new SharedWithdrawal(x.Asset.Split(new[] { "-" }, StringSplitOptions.RemoveEmptyEntries)[0], x.Address!, x.ArrivalQuantity, x.Status == DepositWithdrawalStatus.Completed, x.ApplyTime) + new SharedWithdrawal( + x.Asset.Split(new[] { "-" }, StringSplitOptions.RemoveEmptyEntries)[0], + x.Address!, + x.ArrivalQuantity, + x.Status == DepositWithdrawalStatus.Completed, + x.ApplyTime, + GetWithdrawalStatus(x)) { Network = x.Asset.Split('-')[1], Id = x.WithdrawId!, @@ -828,17 +820,31 @@ async Task> IWithdrawalRestClient.GetWithd .ToArray(), nextPageRequest); } + private SharedTransferStatus GetWithdrawalStatus(BitMartDepositWithdrawal x) + { + if (x.Status == DepositWithdrawalStatus.Canceled || x.Status == DepositWithdrawalStatus.Failed) + return SharedTransferStatus.Failed; + + if (x.Status == DepositWithdrawalStatus.Completed) + return SharedTransferStatus.Completed; + + if (x.Status == DepositWithdrawalStatus.Created || x.Status == DepositWithdrawalStatus.Processing || x.Status == DepositWithdrawalStatus.Submitted) + return SharedTransferStatus.InProgress; + + return SharedTransferStatus.Unknown; + } + #endregion #region Withdraw client - WithdrawOptions IWithdrawRestClient.WithdrawOptions { get; } = new WithdrawOptions(); + WithdrawOptions IWithdrawRestClient.WithdrawOptions { get; } = new WithdrawOptions(_exchangeName); - async Task> IWithdrawRestClient.WithdrawAsync(WithdrawRequest request, CancellationToken ct) + async Task> IWithdrawRestClient.WithdrawAsync(WithdrawRequest request, CancellationToken ct) { - var validationError = ((IWithdrawRestClient)this).WithdrawOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedTradingModes); + var validationError = SharedClient.WithdrawOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var assetName = request.Asset; if (request.Network != null && request.Network != request.Asset) @@ -851,30 +857,30 @@ async Task> IWithdrawRestClient.WithdrawAsync(Withdr request.Address, memo: request.AddressTag, ct: ct).ConfigureAwait(false); - if (!withdrawal) - return withdrawal.AsExchangeResult(Exchange, null, default); + if (!withdrawal.Success) + return HttpResult.Fail(withdrawal); - return withdrawal.AsExchangeResult(Exchange, TradingMode.Spot, new SharedId(withdrawal.Data.WithdrawId)); + return HttpResult.Ok(withdrawal, new SharedId(withdrawal.Data.WithdrawId)); } #endregion #region Fee Client - EndpointOptions IFeeRestClient.GetFeeOptions { get; } = new EndpointOptions(true); + GetFeeOptions IFeeRestClient.GetFeeOptions { get; } = new GetFeeOptions(_exchangeName, true); - async Task> IFeeRestClient.GetFeesAsync(GetFeeRequest request, CancellationToken ct) + async Task> IFeeRestClient.GetFeesAsync(GetFeeRequest request, CancellationToken ct) { - var validationError = ((IFeeRestClient)this).GetFeeOptions.ValidateRequest(Exchange, request, request.Symbol!.TradingMode, SupportedTradingModes); + var validationError = SharedClient.GetFeeOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); // Get data var result = await Account.GetSymbolTradeFeeAsync(request.Symbol!.GetSymbol(FormatSymbol), ct: ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult(Exchange, null, default); + if (!result.Success) + return HttpResult.Fail(result); // Return - return result.AsExchangeResult(Exchange, TradingMode.Spot, new SharedFee(result.Data.BuyMakerFeeRate * 100, result.Data.BuyTakerFeeRate * 100)); + return HttpResult.Ok(result, new SharedFee(result.Data.BuyMakerFeeRate * 100, result.Data.BuyTakerFeeRate * 100)); } #endregion diff --git a/BitMart.Net/Clients/SpotApi/BitMartRestClientSpotApiSubAccount.cs b/BitMart.Net/Clients/SpotApi/BitMartRestClientSpotApiSubAccount.cs index 29a88a0..81e6905 100644 --- a/BitMart.Net/Clients/SpotApi/BitMartRestClientSpotApiSubAccount.cs +++ b/BitMart.Net/Clients/SpotApi/BitMartRestClientSpotApiSubAccount.cs @@ -23,14 +23,14 @@ internal BitMartRestClientSpotApiSubAccount(BitMartRestClientSpotApi baseClient) #region Transfer Sub To Main For Main /// - public async Task TransferSubToMainForMainAsync(string clientOrderId, string asset, decimal quantity, string subAccount, CancellationToken ct = default) + public async Task TransferSubToMainForMainAsync(string clientOrderId, string asset, decimal quantity, string subAccount, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("requestNo", clientOrderId); parameters.Add("currency", asset); - parameters.AddString("amount", quantity); + parameters.Add("amount", quantity); parameters.Add("subAccount", subAccount); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/account/sub-account/main/v1/sub-to-main", BitMartExchange.RateLimiter.BitMart, 1, true, + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/account/sub-account/main/v1/sub-to-main", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(2, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; @@ -41,13 +41,13 @@ public async Task TransferSubToMainForMainAsync(string clientOrde #region Transfer Sub To Main For Sub /// - public async Task TransferSubToMainForSubAsync(string clientOrderId, string asset, decimal quantity, CancellationToken ct = default) + public async Task TransferSubToMainForSubAsync(string clientOrderId, string asset, decimal quantity, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("requestNo", clientOrderId); parameters.Add("currency", asset); - parameters.AddString("amount", quantity); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/account/sub-account/sub/v1/sub-to-main", BitMartExchange.RateLimiter.BitMart, 1, true, + parameters.Add("amount", quantity); + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/account/sub-account/sub/v1/sub-to-main", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(2, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; @@ -58,14 +58,14 @@ public async Task TransferSubToMainForSubAsync(string clientOrder #region Transfer Main To Sub Account /// - public async Task TransferMainToSubAccountAsync(string clientOrderId, string asset, decimal quantity, string subAccount, CancellationToken ct = default) + public async Task TransferMainToSubAccountAsync(string clientOrderId, string asset, decimal quantity, string subAccount, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("requestNo", clientOrderId); parameters.Add("currency", asset); - parameters.AddString("amount", quantity); + parameters.Add("amount", quantity); parameters.Add("subAccount", subAccount); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/account/sub-account/main/v1/main-to-sub", BitMartExchange.RateLimiter.BitMart, 1, true, + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/account/sub-account/main/v1/main-to-sub", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(2, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; @@ -76,15 +76,15 @@ public async Task TransferMainToSubAccountAsync(string clientOrde #region Transfer Sub Account To Sub Account /// - public async Task TransferSubAccountToSubAccountAsync(string clientOrderId, decimal quantity, string asset, string fromAccount, string toAccount, CancellationToken ct = default) + public async Task TransferSubAccountToSubAccountAsync(string clientOrderId, decimal quantity, string asset, string fromAccount, string toAccount, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("requestNo", clientOrderId); - parameters.AddString("quantity", quantity); + parameters.Add("quantity", quantity); parameters.Add("currency", asset); parameters.Add("fromAccount", fromAccount); parameters.Add("toAccount", toAccount); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/account/sub-account/main/v1/sub-to-sub", BitMartExchange.RateLimiter.BitMart, 1, true, + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/account/sub-account/main/v1/sub-to-sub", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(2, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; @@ -95,12 +95,12 @@ public async Task TransferSubAccountToSubAccountAsync(string clie #region Get Sub Account Transfer History For Main /// - public async Task> GetSubAccountTransferHistoryForMainAsync(int limit, string? account = null, CancellationToken ct = default) + public async Task> GetSubAccountTransferHistoryForMainAsync(int limit, string? account = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("N", limit); - parameters.AddOptional("accountName", account); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/account/sub-account/main/v1/transfer-list", BitMartExchange.RateLimiter.BitMart, 1, true, + parameters.Add("accountName", account); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/account/sub-account/main/v1/transfer-list", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(8, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; @@ -111,11 +111,11 @@ public async Task> GetSubAccountTransfe #region Get Sub Account Transfer History /// - public async Task> GetSubAccountTransferHistoryAsync(int limit, CancellationToken ct = default) + public async Task> GetSubAccountTransferHistoryAsync(int limit, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("N", limit); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/account/sub-account/v1/transfer-history", BitMartExchange.RateLimiter.BitMart, 1, true, + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/account/sub-account/v1/transfer-history", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(8, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; @@ -126,15 +126,18 @@ public async Task> GetSubAccountTransfe #region Get Sub Acccount Balance /// - public async Task> GetSubAcccountBalanceAsync(string subAccount, string? asset = null, CancellationToken ct = default) + public async Task> GetSubAccountBalanceAsync(string subAccount, string? asset = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("subAccount", subAccount); - parameters.AddOptional("currency", asset); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/account/sub-account/main/v1/wallet", BitMartExchange.RateLimiter.BitMart, 1, true, + parameters.Add("currency", asset); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/account/sub-account/main/v1/wallet", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(12, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); - return result.As(result.Data?.Wallet); + if (!result.Success) + return HttpResult.Fail(result); + + return HttpResult.Ok(result, result.Data.Wallet); } #endregion @@ -142,13 +145,16 @@ public async Task> GetSubAcccountBalan #region Get Sub Account List /// - public async Task> GetSubAccountListAsync(CancellationToken ct = default) + public async Task> GetSubAccountListAsync(CancellationToken ct = default) { - var parameters = new ParameterCollection(); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/account/sub-account/main/v1/subaccount-list", BitMartExchange.RateLimiter.BitMart, 1, true, + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/account/sub-account/main/v1/subaccount-list", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(8, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); - return result.As(result.Data?.SubAccountList); + if (!result.Success) + return HttpResult.Fail(result); + + return HttpResult.Ok(result, result.Data.SubAccountList); } #endregion diff --git a/BitMart.Net/Clients/SpotApi/BitMartRestClientSpotApiTrading.cs b/BitMart.Net/Clients/SpotApi/BitMartRestClientSpotApiTrading.cs index ecf3f80..a271196 100644 --- a/BitMart.Net/Clients/SpotApi/BitMartRestClientSpotApiTrading.cs +++ b/BitMart.Net/Clients/SpotApi/BitMartRestClientSpotApiTrading.cs @@ -31,7 +31,7 @@ internal BitMartRestClientSpotApiTrading(ILogger logger, BitMartRestClientSpotAp #region Place Order /// - public async Task> PlaceOrderAsync( + public async Task> PlaceOrderAsync( string symbol, OrderSide side, OrderType type, @@ -42,16 +42,16 @@ public async Task> PlaceOrderAsync( SelfTradePreventionMode? stpMode = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("symbol", symbol); - parameters.AddEnum("side", side); - parameters.AddEnum("type", type); - parameters.AddOptionalString("size", quantity); - parameters.AddOptionalString("price", price); - parameters.AddOptionalString("notional", quoteQuantity); - parameters.AddOptional("client_order_id", clientOrderId); - parameters.AddOptionalEnum("stpMode", stpMode); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/spot/v2/submit_order", BitMartExchange.RateLimiter.BitMart, 1, true, + parameters.Add("side", side); + parameters.Add("type", type); + parameters.Add("size", quantity); + parameters.Add("price", price); + parameters.Add("notional", quoteQuantity); + parameters.Add("client_order_id", clientOrderId); + parameters.Add("stpMode", stpMode); + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/spot/v2/submit_order", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(60, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct, additionalHeaders: new Dictionary { @@ -65,24 +65,24 @@ public async Task> PlaceOrderAsync( #region Place Multiple Orders /// - public async Task> PlaceMultipleOrdersAsync(string symbol, IEnumerable orders, CancellationToken ct = default) + public async Task> PlaceMultipleOrdersAsync(string symbol, IEnumerable orders, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("symbol", symbol); parameters.Add("orderParams", orders.ToArray()); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/spot/v4/batch_orders", BitMartExchange.RateLimiter.BitMart, 1, true, + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/spot/v4/batch_orders", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(20, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct, additionalHeaders: new Dictionary { { "X-BM-BROKER-ID", LibraryHelpers.GetClientReference(() => _baseClient.ClientOptions.BrokerId, _baseClient.Exchange) } }).ConfigureAwait(false); - if (!result) - return result.As(default); + if (!result.Success) + return HttpResult.Fail(result); if (result.Data.Code != 0) - return result.AsError(new ServerError(result.Data.Code, _baseClient.GetErrorInfo(result.Data.Code, result.Data.Message))); + return HttpResult.Fail(result, new ServerError(result.Data.Code, _baseClient.GetErrorInfo(result.Data.Code, result.Data.Message))); - return result.As(result.Data.Data); + return HttpResult.Ok(result, result.Data.Data); } #endregion @@ -90,16 +90,16 @@ public async Task> PlaceMultipleOrdersAsync(strin #region Cancel Order /// - public async Task CancelOrderAsync(string symbol, string? orderId = null, string? clientOrderId = null, CancellationToken ct = default) + public async Task CancelOrderAsync(string symbol, string? orderId = null, string? clientOrderId = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); - parameters.AddOptional("order_id", orderId); - parameters.AddOptional("client_order_id", clientOrderId); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); + parameters.Add("order_id", orderId); + parameters.Add("client_order_id", clientOrderId); parameters.Add("symbol", symbol); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/spot/v3/cancel_order", BitMartExchange.RateLimiter.BitMart, 1, true, + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/spot/v3/cancel_order", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(60, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); - return result.AsDataless(); + return result; } #endregion @@ -107,13 +107,13 @@ public async Task CancelOrderAsync(string symbol, string? orderId #region Cancel Orders /// - public async Task> CancelOrdersAsync(string symbol, IEnumerable? orderIds = null, IEnumerable? clientOrderIds = null, CancellationToken ct = default) + public async Task> CancelOrdersAsync(string symbol, IEnumerable? orderIds = null, IEnumerable? clientOrderIds = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("symbol", symbol); - parameters.AddOptional("orderIds", orderIds?.ToArray()); - parameters.AddOptional("clientOrderIds", clientOrderIds?.ToArray()); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/spot/v4/cancel_orders", BitMartExchange.RateLimiter.BitMart, 1, true, + parameters.AddArray("orderIds", orderIds?.ToArray()); + parameters.AddArray("clientOrderIds", clientOrderIds?.ToArray()); + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/spot/v4/cancel_orders", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(20, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; @@ -124,12 +124,12 @@ public async Task> CancelOrdersAsync(st #region Cancel Order /// - public async Task CancelAllOrderAsync(string? symbol = null, OrderSide? side = null, CancellationToken ct = default) + public async Task CancelAllOrderAsync(string? symbol = null, OrderSide? side = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); - parameters.AddOptional("symbol", symbol); - parameters.AddOptionalEnum("side", side); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/spot/v4/cancel_all", BitMartExchange.RateLimiter.BitMart, 1, true, + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); + parameters.Add("symbol", symbol); + parameters.Add("side", side); + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/spot/v4/cancel_all", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(1, TimeSpan.FromSeconds(3), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); return await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); } @@ -139,17 +139,17 @@ public async Task CancelAllOrderAsync(string? symbol = null, Orde #region Place Margin Order /// - public async Task> PlaceMarginOrderAsync(string symbol, OrderSide side, OrderType type, decimal? quantity = null, decimal? price = null, decimal? quoteQuantity = null, string? clientOrderId = null, CancellationToken ct = default) + public async Task> PlaceMarginOrderAsync(string symbol, OrderSide side, OrderType type, decimal? quantity = null, decimal? price = null, decimal? quoteQuantity = null, string? clientOrderId = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("symbol", symbol); - parameters.AddEnum("side", side); - parameters.AddEnum("type", type); - parameters.AddOptionalString("size", quantity); - parameters.AddOptionalString("price", price); - parameters.AddOptionalString("notional", quoteQuantity); - parameters.AddOptional("client_order_id", clientOrderId); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/spot/v1/margin/submit_order", BitMartExchange.RateLimiter.BitMart, 1, true, + parameters.Add("side", side); + parameters.Add("type", type); + parameters.Add("size", quantity); + parameters.Add("price", price); + parameters.Add("notional", quoteQuantity); + parameters.Add("client_order_id", clientOrderId); + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/spot/v1/margin/submit_order", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(20, TimeSpan.FromSeconds(1), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct, additionalHeaders: new Dictionary { @@ -163,12 +163,12 @@ public async Task> PlaceMarginOrderAsync(string sy #region Get Order /// - public async Task> GetOrderAsync(string orderId, OrderQueryState? orderQueryState = null, CancellationToken ct = default) + public async Task> GetOrderAsync(string orderId, OrderQueryState? orderQueryState = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("orderId", orderId); - parameters.AddOptionalEnum("queryState", orderQueryState); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/spot/v4/query/order", BitMartExchange.RateLimiter.BitMart, 1, true, + parameters.Add("queryState", orderQueryState); + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/spot/v4/query/order", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(60, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; @@ -179,12 +179,12 @@ public async Task> GetOrderAsync(string orderId, Ord #region Get Order By Client Order Id /// - public async Task> GetOrderByClientOrderIdAsync(string clientOrderId, OrderQueryState? orderQueryState = null, CancellationToken ct = default) + public async Task> GetOrderByClientOrderIdAsync(string clientOrderId, OrderQueryState? orderQueryState = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("clientOrderId", clientOrderId); - parameters.AddOptionalEnum("queryState", orderQueryState); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/spot/v4/query/client-order", BitMartExchange.RateLimiter.BitMart, 1, true, + parameters.Add("queryState", orderQueryState); + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/spot/v4/query/client-order", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(60, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; @@ -195,15 +195,15 @@ public async Task> GetOrderByClientOrderIdAsync(stri #region Get Open Orders /// - public async Task> GetOpenOrdersAsync(string? symbol = null, SpotMode? spotOrderMode = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default) + public async Task> GetOpenOrdersAsync(string? symbol = null, SpotMode? spotOrderMode = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); - parameters.AddOptional("symbol", symbol); - parameters.AddOptionalEnum("orderMode", spotOrderMode); - parameters.AddOptionalMilliseconds("startTime", startTime); - parameters.AddOptionalMilliseconds("endTime", endTime); - parameters.AddOptional("limit", limit); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/spot/v4/query/open-orders", BitMartExchange.RateLimiter.BitMart, 1, true, + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); + parameters.Add("symbol", symbol); + parameters.Add("orderMode", spotOrderMode); + parameters.Add("startTime", startTime); + parameters.Add("endTime", endTime); + parameters.Add("limit", limit); + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/spot/v4/query/open-orders", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(12, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; @@ -214,15 +214,15 @@ public async Task> GetOpenOrdersAsync(string? symb #region Get Closed Orders /// - public async Task> GetClosedOrdersAsync(string? symbol = null, SpotMode? spotOrderMode = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default) + public async Task> GetClosedOrdersAsync(string? symbol = null, SpotMode? spotOrderMode = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); - parameters.AddOptional("symbol", symbol); - parameters.AddOptionalEnum("orderMode", spotOrderMode); - parameters.AddOptionalMilliseconds("startTime", startTime); - parameters.AddOptionalMilliseconds("endTime", endTime); - parameters.AddOptional("limit", limit); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/spot/v4/query/history-orders", BitMartExchange.RateLimiter.BitMart, 1, true, + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); + parameters.Add("symbol", symbol); + parameters.Add("orderMode", spotOrderMode); + parameters.Add("startTime", startTime); + parameters.Add("endTime", endTime); + parameters.Add("limit", limit); + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/spot/v4/query/history-orders", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(12, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; @@ -233,15 +233,15 @@ public async Task> GetClosedOrdersAsync(string? sy #region Get User Trades /// - public async Task> GetUserTradesAsync(string? symbol = null, SpotMode? spotOrderMode = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default) + public async Task> GetUserTradesAsync(string? symbol = null, SpotMode? spotOrderMode = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); - parameters.AddOptional("symbol", symbol); - parameters.AddOptionalEnum("orderMode", spotOrderMode); - parameters.AddOptionalMilliseconds("startTime", startTime); - parameters.AddOptionalMilliseconds("endTime", endTime); - parameters.AddOptional("limit", limit); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/spot/v4/query/trades", BitMartExchange.RateLimiter.BitMart, 1, true, + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); + parameters.Add("symbol", symbol); + parameters.Add("orderMode", spotOrderMode); + parameters.Add("startTime", startTime); + parameters.Add("endTime", endTime); + parameters.Add("limit", limit); + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/spot/v4/query/trades", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(12, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; @@ -252,11 +252,11 @@ public async Task> GetUserTradesAsync(string? #region Get Order Trades /// - public async Task> GetOrderTradesAsync(string orderId, CancellationToken ct = default) + public async Task> GetOrderTradesAsync(string orderId, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("orderId", orderId); - var request = _definitions.GetOrCreate(HttpMethod.Post, "spot/v4/query/order-trades", BitMartExchange.RateLimiter.BitMart, 1, true, + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "spot/v4/query/order-trades", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(12, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; diff --git a/BitMart.Net/Clients/SpotApi/BitMartSocketClientSpotApi.cs b/BitMart.Net/Clients/SpotApi/BitMartSocketClientSpotApi.cs index 2fde002..1ca3ee8 100644 --- a/BitMart.Net/Clients/SpotApi/BitMartSocketClientSpotApi.cs +++ b/BitMart.Net/Clients/SpotApi/BitMartSocketClientSpotApi.cs @@ -43,8 +43,8 @@ internal partial class BitMartSocketClientSpotApi : SocketApiClient /// ctor /// - internal BitMartSocketClientSpotApi(ILogger logger, BitMartSocketOptions options) : - base(logger, options.Environment.SocketClientSpotAddress!, options, options.SpotOptions) + internal BitMartSocketClientSpotApi(ILoggerFactory? loggerFactory, BitMartSocketOptions options) : + base(loggerFactory, BitMartExchange.Metadata.Id, options.Environment.SocketClientSpotAddress!, options, options.SpotOptions) { KeepAliveInterval = TimeSpan.Zero; MaxIndividualSubscriptionsPerConnection = 115; @@ -77,11 +77,11 @@ protected override BitMartAuthenticationProvider CreateAuthenticationProvider(Bi => new BitMartAuthenticationProvider(credentials); /// - public Task> SubscribeToTickerUpdatesAsync(string symbol, Action> onMessage, CancellationToken ct = default) + public Task> SubscribeToTickerUpdatesAsync(string symbol, Action> onMessage, CancellationToken ct = default) => SubscribeToTickerUpdatesAsync(new[] { symbol }, onMessage, ct); /// - public async Task> SubscribeToTickerUpdatesAsync(IEnumerable symbols, Action> onMessage, CancellationToken ct = default) + public async Task> SubscribeToTickerUpdatesAsync(IEnumerable symbols, Action> onMessage, CancellationToken ct = default) { var handler = new Action>((receiveTime, originalData, data) => { @@ -103,11 +103,11 @@ public async Task> SubscribeToTickerUpdatesAsync( } /// - public Task> SubscribeToKlineUpdatesAsync(string symbol, KlineStreamInterval interval, Action> onMessage, CancellationToken ct = default) + public Task> SubscribeToKlineUpdatesAsync(string symbol, KlineStreamInterval interval, Action> onMessage, CancellationToken ct = default) => SubscribeToKlineUpdatesAsync(new[] { symbol }, interval, onMessage, ct); /// - public async Task> SubscribeToKlineUpdatesAsync(IEnumerable symbols, KlineStreamInterval interval, Action> onMessage, CancellationToken ct = default) + public async Task> SubscribeToKlineUpdatesAsync(IEnumerable symbols, KlineStreamInterval interval, Action> onMessage, CancellationToken ct = default) { var intervalStr = EnumConverter.GetString(interval); var handler = new Action>((receiveTime, originalData, data) => @@ -125,11 +125,11 @@ public async Task> SubscribeToKlineUpdatesAsync(I } /// - public Task> SubscribeToPartialOrderBookUpdatesAsync(string symbol, int depth, Action> onMessage, CancellationToken ct = default) + public Task> SubscribeToPartialOrderBookUpdatesAsync(string symbol, int depth, Action> onMessage, CancellationToken ct = default) => SubscribeToPartialOrderBookUpdatesAsync(new[] { symbol }, depth, onMessage, ct); /// - public async Task> SubscribeToPartialOrderBookUpdatesAsync(IEnumerable symbols, int depth, Action> onMessage, CancellationToken ct = default) + public async Task> SubscribeToPartialOrderBookUpdatesAsync(IEnumerable symbols, int depth, Action> onMessage, CancellationToken ct = default) { depth.ValidateIntValues(nameof(depth), 5, 20, 50); @@ -151,11 +151,11 @@ public async Task> SubscribeToPartialOrderBookUpd } /// - public Task> SubscribeToOrderBookUpdatesAsync(string symbol, Action> onMessage, CancellationToken ct = default) + public Task> SubscribeToOrderBookUpdatesAsync(string symbol, Action> onMessage, CancellationToken ct = default) => SubscribeToOrderBookUpdatesAsync(new[] { symbol }, onMessage, ct); /// - public async Task> SubscribeToOrderBookUpdatesAsync(IEnumerable symbols, Action> onMessage, CancellationToken ct = default) + public async Task> SubscribeToOrderBookUpdatesAsync(IEnumerable symbols, Action> onMessage, CancellationToken ct = default) { var handler = new Action>((receiveTime, originalData, data) => { @@ -177,11 +177,11 @@ public async Task> SubscribeToOrderBookUpdatesAsy } /// - public Task> SubscribeToTradeUpdatesAsync(string symbol, Action> onMessage, CancellationToken ct = default) + public Task> SubscribeToTradeUpdatesAsync(string symbol, Action> onMessage, CancellationToken ct = default) => SubscribeToTradeUpdatesAsync(new[] { symbol }, onMessage, ct); /// - public async Task> SubscribeToTradeUpdatesAsync(IEnumerable symbols, Action> onMessage, CancellationToken ct = default) + public async Task> SubscribeToTradeUpdatesAsync(IEnumerable symbols, Action> onMessage, CancellationToken ct = default) { var handler = new Action>((receiveTime, originalData, data) => { @@ -198,11 +198,11 @@ public async Task> SubscribeToTradeUpdatesAsync(I } /// - public Task> SubscribeToBookTickerUpdatesAsync(string symbol, Action> onMessage, CancellationToken ct = default) + public Task> SubscribeToBookTickerUpdatesAsync(string symbol, Action> onMessage, CancellationToken ct = default) => SubscribeToBookTickerUpdatesAsync(new[] { symbol }, onMessage, ct); /// - public async Task> SubscribeToBookTickerUpdatesAsync(IEnumerable symbols, Action> onMessage, CancellationToken ct = default) + public async Task> SubscribeToBookTickerUpdatesAsync(IEnumerable symbols, Action> onMessage, CancellationToken ct = default) { var handler = new Action>((receiveTime, originalData, data) => { @@ -220,7 +220,7 @@ public async Task> SubscribeToBookTickerUpdatesAs /// - public async Task> SubscribeToOrderUpdatesAsync(Action> onMessage, CancellationToken ct = default) + public async Task> SubscribeToOrderUpdatesAsync(Action> onMessage, CancellationToken ct = default) { var handler = new Action>((receiveTime, originalData, data) => { @@ -241,7 +241,7 @@ public async Task> SubscribeToOrderUpdatesAsync(A } /// - public async Task> SubscribeToBalanceUpdatesAsync(Action> onMessage, CancellationToken ct = default) + public async Task> SubscribeToBalanceUpdatesAsync(Action> onMessage, CancellationToken ct = default) { var handler = new Action>((receiveTime, originalData, data) => { diff --git a/BitMart.Net/Clients/SpotApi/BitMartSocketClientSpotApiShared.cs b/BitMart.Net/Clients/SpotApi/BitMartSocketClientSpotApiShared.cs index 1c00cd7..a5d7678 100644 --- a/BitMart.Net/Clients/SpotApi/BitMartSocketClientSpotApiShared.cs +++ b/BitMart.Net/Clients/SpotApi/BitMartSocketClientSpotApiShared.cs @@ -14,105 +14,111 @@ namespace BitMart.Net.Clients.SpotApi internal partial class BitMartSocketClientSpotApi : IBitMartSocketClientSpotApiShared { private const string _topicId = "BitMartSpot"; - public string Exchange => BitMartExchange.ExchangeName; + private const string _exchangeName = "BitMart"; public TradingMode[] SupportedTradingModes { get; } = new[] { TradingMode.Spot }; public void SetDefaultExchangeParameter(string key, object value) => ExchangeParameters.SetStaticParameter(Exchange, key, value); public void ResetDefaultExchangeParameters() => ExchangeParameters.ResetStaticParameters(); + public SharedClientInfo Discover() => SharedUtils.GetClientInfo(BitMartExchange.Metadata, this); #region Ticker client - SubscribeTickerOptions ITickerSocketClient.SubscribeTickerOptions { get; } = new SubscribeTickerOptions() + SubscribeTickerOptions ITickerSocketClient.SubscribeTickerOptions { get; } = new SubscribeTickerOptions(_exchangeName) { SupportsMultipleSymbols = true, MaxSymbolCount = 20 }; - async Task> ITickerSocketClient.SubscribeToTickerUpdatesAsync(SubscribeTickerRequest request, Action> handler, CancellationToken ct) + async Task> ITickerSocketClient.SubscribeToTickerUpdatesAsync(SubscribeTickerRequest request, Action> handler, CancellationToken ct) { - var validationError = ((ITickerSocketClient)this).SubscribeTickerOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); + var validationError = SharedClient.SubscribeTickerOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeResult(Exchange, validationError); + return WebSocketResult.Fail(_exchangeName, validationError); var symbols = request.Symbols?.Length > 0 ? request.Symbols.Select(x => x.GetSymbol(FormatSymbol)).ToArray() : [request.Symbol!.GetSymbol(FormatSymbol)]; - var result = await SubscribeToTickerUpdatesAsync(symbols, update => handler(update.ToType(new SharedSpotTicker(ExchangeSymbolCache.ParseSymbol(_topicId, update.Data.Symbol), update.Data.Symbol, update.Data.LastPrice, update.Data.HighPrice, update.Data.LowPrice, update.Data.Volume24h, update.Data.Change * 100) + var result = await SubscribeToTickerUpdatesAsync(symbols, update => handler(update.ToType(new SharedSpotTicker(ExchangeSymbolCache.ParseSymbol(_topicId, EnvironmentName, null, update.Data.Symbol), update.Data.Symbol, update.Data.LastPrice, update.Data.HighPrice, update.Data.LowPrice, update.Data.Volume24h, update.Data.Change * 100) { QuoteVolume = update.Data.QuoteVolume24h })), ct).ConfigureAwait(false); - return new ExchangeResult(Exchange, result); + return result; } #endregion #region Trade client - EndpointOptions ITradeSocketClient.SubscribeTradeOptions { get; } = new EndpointOptions(false) + SubscribeTradeOptions ITradeSocketClient.SubscribeTradeOptions { get; } = new SubscribeTradeOptions(_exchangeName, false) { SupportsMultipleSymbols = true, MaxSymbolCount = 20 }; - async Task> ITradeSocketClient.SubscribeToTradeUpdatesAsync(SubscribeTradeRequest request, Action> handler, CancellationToken ct) + async Task> ITradeSocketClient.SubscribeToTradeUpdatesAsync(SubscribeTradeRequest request, Action> handler, CancellationToken ct) { - var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); + var validationError = SharedClient.SubscribeTradeOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeResult(Exchange, validationError); + return WebSocketResult.Fail(_exchangeName, validationError); var symbols = request.Symbols?.Length > 0 ? request.Symbols.Select(x => x.GetSymbol(FormatSymbol)).ToArray() : [request.Symbol!.GetSymbol(FormatSymbol)]; var result = await SubscribeToTradeUpdatesAsync(symbols, update => handler(update.ToType(update.Data.Select(x => - new SharedTrade(ExchangeSymbolCache.ParseSymbol(_topicId, x.Symbol), x.Symbol, x.Quantity, x.Price, x.Timestamp) + new SharedTrade(ExchangeSymbolCache.ParseSymbol(_topicId, EnvironmentName, null, x.Symbol), x.Symbol, x.Quantity, x.Price, x.Timestamp) { Side = x.Side == Enums.OrderSide.Buy ? SharedOrderSide.Buy : SharedOrderSide.Sell }).ToArray())), ct).ConfigureAwait(false); - return new ExchangeResult(Exchange, result); + return result; } #endregion #region Book Ticker client - EndpointOptions IBookTickerSocketClient.SubscribeBookTickerOptions { get; } = new EndpointOptions(false); - async Task> IBookTickerSocketClient.SubscribeToBookTickerUpdatesAsync(SubscribeBookTickerRequest request, Action> handler, CancellationToken ct) + SubscribeBookTickerOptions IBookTickerSocketClient.SubscribeBookTickerOptions { get; } = new SubscribeBookTickerOptions(_exchangeName, false); + async Task> IBookTickerSocketClient.SubscribeToBookTickerUpdatesAsync(SubscribeBookTickerRequest request, Action> handler, CancellationToken ct) { - var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); + var validationError = SharedClient.SubscribeBookTickerOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeResult(Exchange, validationError); + return WebSocketResult.Fail(_exchangeName, validationError); var symbols = request.Symbols?.Length > 0 ? request.Symbols.Select(x => x.GetSymbol(FormatSymbol)).ToArray() : [request.Symbol!.GetSymbol(FormatSymbol)]; - var result = await SubscribeToBookTickerUpdatesAsync(symbols, update => handler(update.ToType(new SharedBookTicker(ExchangeSymbolCache.ParseSymbol(_topicId, update.Data.Symbol), update.Data.Symbol, update.Data.BestAskPrice, update.Data.BestAskQuantity, update.Data.BestBidPrice, update.Data.BestBidQuantity))), ct).ConfigureAwait(false); + var result = await SubscribeToBookTickerUpdatesAsync(symbols, update => handler(update.ToType(new SharedBookTicker(ExchangeSymbolCache.ParseSymbol(_topicId, EnvironmentName, null, update.Data.Symbol), update.Data.Symbol, update.Data.BestAskPrice, update.Data.BestAskQuantity, update.Data.BestBidPrice, update.Data.BestBidQuantity))), ct).ConfigureAwait(false); - return new ExchangeResult(Exchange, result); + return result; } #endregion #region Balance client - EndpointOptions IBalanceSocketClient.SubscribeBalanceOptions { get; } = new EndpointOptions(false); - async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(SubscribeBalancesRequest request, Action> handler, CancellationToken ct) + SubscribeBalanceOptions IBalanceSocketClient.SubscribeBalanceOptions { get; } = new SubscribeBalanceOptions(_exchangeName, false); + async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(SubscribeBalancesRequest request, Action> handler, CancellationToken ct) { - var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); + var validationError = SharedClient.SubscribeBalanceOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeResult(Exchange, validationError); + return WebSocketResult.Fail(_exchangeName, validationError); var result = await SubscribeToBalanceUpdatesAsync( - update => handler(update.ToType(update.Data.Balances.Select(x => new SharedBalance(x.Asset, x.Available, x.Available + x.Frozen)).ToArray())), + update => handler(update.ToType(update.Data.Balances.Select(x => + new SharedBalance( + SupportedTradingModes, + x.Asset, + x.Available, + x.Available + x.Frozen)).ToArray())), ct: ct).ConfigureAwait(false); - return new ExchangeResult(Exchange, result); + return result; } #endregion #region Spot Order client - EndpointOptions ISpotOrderSocketClient.SubscribeSpotOrderOptions { get; } = new EndpointOptions(false); - async Task> ISpotOrderSocketClient.SubscribeToSpotOrderUpdatesAsync(SubscribeSpotOrderRequest request, Action> handler, CancellationToken ct) + SubscribeSpotOrderOptions ISpotOrderSocketClient.SubscribeSpotOrderOptions { get; } = new SubscribeSpotOrderOptions(_exchangeName, false); + async Task> ISpotOrderSocketClient.SubscribeToSpotOrderUpdatesAsync(SubscribeSpotOrderRequest request, Action> handler, CancellationToken ct) { - var validationError = ((ISpotOrderSocketClient)this).SubscribeSpotOrderOptions.ValidateRequest(Exchange, request, TradingMode.Spot, SupportedTradingModes); + var validationError = SharedClient.SubscribeSpotOrderOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeResult(Exchange, validationError); + return WebSocketResult.Fail(_exchangeName, validationError); var result = await SubscribeToOrderUpdatesAsync( update => handler(update.ToType(new[] { new SharedSpotOrder( - ExchangeSymbolCache.ParseSymbol(_topicId, update.Data.Symbol), + ExchangeSymbolCache.ParseSymbol(_topicId, EnvironmentName, null, update.Data.Symbol), update.Data.Symbol, update.Data.OrderId.ToString(), update.Data.OrderType == Enums.OrderType.Limit ? SharedOrderType.Limit : update.Data.OrderType == Enums.OrderType.Market ? SharedOrderType.Market : SharedOrderType.Other, @@ -127,7 +133,7 @@ async Task> ISpotOrderSocketClient.SubscribeT UpdateTime = update.Data.UpdateTime, OrderPrice = update.Data.Price == 0 ? null : update.Data.Price, FeeAsset = update.Data.FeeAsset, - LastTrade = update.Data.LastTradeId == null ? null : new SharedUserTrade(ExchangeSymbolCache.ParseSymbol(_topicId, update.Data.Symbol), update.Data.Symbol, update.Data.OrderId, update.Data.LastTradeId, update.Data.Side == Enums.OrderSide.Buy ? SharedOrderSide.Buy : SharedOrderSide.Sell, update.Data.LastTradeQuantity, update.Data.LastTradePrice, update.Data.LastTradeTime!.Value) + LastTrade = update.Data.LastTradeId == null ? null : new SharedUserTrade(ExchangeSymbolCache.ParseSymbol(_topicId, EnvironmentName, null, update.Data.Symbol), update.Data.Symbol, update.Data.OrderId, update.Data.LastTradeId, update.Data.Side == Enums.OrderSide.Buy ? SharedOrderSide.Buy : SharedOrderSide.Sell, update.Data.LastTradeQuantity, update.Data.LastTradePrice, update.Data.LastTradeTime!.Value) { ClientOrderId = update.Data.ClientOrderId, Role = update.Data.LastTradeRole == Enums.TradeRole.Taker ? SharedRole.Taker : SharedRole.Maker, @@ -138,7 +144,7 @@ async Task> ISpotOrderSocketClient.SubscribeT })), ct: ct).ConfigureAwait(false); - return new ExchangeResult(Exchange, result); + return result; } private SharedOrderStatus ParseOrderStatus(OrderStatus status) @@ -152,7 +158,7 @@ private SharedOrderStatus ParseOrderStatus(OrderStatus status) #endregion #region Kline client - SubscribeKlineOptions IKlineSocketClient.SubscribeKlineOptions { get; } = new SubscribeKlineOptions(false, + SubscribeKlineOptions IKlineSocketClient.SubscribeKlineOptions { get; } = new SubscribeKlineOptions(_exchangeName, false, SharedKlineInterval.OneMinute, SharedKlineInterval.ThreeMinutes, SharedKlineInterval.FiveMinutes, @@ -168,43 +174,40 @@ private SharedOrderStatus ParseOrderStatus(OrderStatus status) SupportsMultipleSymbols = true, MaxSymbolCount = 20 }; - async Task> IKlineSocketClient.SubscribeToKlineUpdatesAsync(SubscribeKlineRequest request, Action> handler, CancellationToken ct) + async Task> IKlineSocketClient.SubscribeToKlineUpdatesAsync(SubscribeKlineRequest request, Action> handler, CancellationToken ct) { var interval = (Enums.KlineStreamInterval)request.Interval; - if (!Enum.IsDefined(typeof(Enums.KlineStreamInterval), interval)) - return new ExchangeResult(Exchange, ArgumentError.Invalid(nameof(GetKlinesRequest.Interval), "Interval not supported")); - - var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); + var validationError = SharedClient.SubscribeKlineOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeResult(Exchange, validationError); + return WebSocketResult.Fail(_exchangeName, validationError); var symbols = request.Symbols?.Length > 0 ? request.Symbols.Select(x => x.GetSymbol(FormatSymbol)).ToArray() : [request.Symbol!.GetSymbol(FormatSymbol)]; var result = await SubscribeToKlineUpdatesAsync(symbols, interval, update => { foreach (var item in update.Data) - handler(update.ToType(new SharedKline(ExchangeSymbolCache.ParseSymbol(_topicId, item.Symbol), item.Symbol, item.Kline.OpenTime, item.Kline.ClosePrice, item.Kline.HighPrice, item.Kline.LowPrice, item.Kline.OpenPrice, item.Kline.Volume))); + handler(update.ToType(new SharedKline(ExchangeSymbolCache.ParseSymbol(_topicId, EnvironmentName, null, item.Symbol), item.Symbol, item.Kline.OpenTime, item.Kline.ClosePrice, item.Kline.HighPrice, item.Kline.LowPrice, item.Kline.OpenPrice, item.Kline.Volume))); }, ct).ConfigureAwait(false); - return new ExchangeResult(Exchange, result); + return result; } #endregion #region Order Book client - SubscribeOrderBookOptions IOrderBookSocketClient.SubscribeOrderBookOptions { get; } = new SubscribeOrderBookOptions(false, new[] { 5, 20, 50 }) + SubscribeOrderBookOptions IOrderBookSocketClient.SubscribeOrderBookOptions { get; } = new SubscribeOrderBookOptions(_exchangeName, false, new[] { 5, 20, 50 }) { SupportsMultipleSymbols = true, MaxSymbolCount = 20 }; - async Task> IOrderBookSocketClient.SubscribeToOrderBookUpdatesAsync(SubscribeOrderBookRequest request, Action> handler, CancellationToken ct) + async Task> IOrderBookSocketClient.SubscribeToOrderBookUpdatesAsync(SubscribeOrderBookRequest request, Action> handler, CancellationToken ct) { - var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); + var validationError = SharedClient.SubscribeOrderBookOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeResult(Exchange, validationError); + return WebSocketResult.Fail(_exchangeName, validationError); var symbols = request.Symbols?.Length > 0 ? request.Symbols.Select(x => x.GetSymbol(FormatSymbol)).ToArray() : [request.Symbol!.GetSymbol(FormatSymbol)]; var result = await SubscribeToPartialOrderBookUpdatesAsync(symbols, request.Limit ?? 20, update => handler(update.ToType(new SharedOrderBook(update.Data.Asks, update.Data.Bids))), ct).ConfigureAwait(false); - return new ExchangeResult(Exchange, result); + return result; } #endregion } diff --git a/BitMart.Net/Clients/UsdFuturesApi/BitMartRestClientUsdFuturesApi.cs b/BitMart.Net/Clients/UsdFuturesApi/BitMartRestClientUsdFuturesApi.cs index e5aaea5..dead52b 100644 --- a/BitMart.Net/Clients/UsdFuturesApi/BitMartRestClientUsdFuturesApi.cs +++ b/BitMart.Net/Clients/UsdFuturesApi/BitMartRestClientUsdFuturesApi.cs @@ -48,13 +48,13 @@ internal partial class BitMartRestClientUsdFuturesApi : RestApiClient new BitMartAuthenticationProvider(credentials); - internal Task SendAsync(RequestDefinition definition, ParameterCollection? parameters, CancellationToken cancellationToken, int? weight = null) - => SendToAddressAsync(BaseAddress, definition, parameters, cancellationToken, weight); - - internal async Task SendToAddressAsync(string baseAddress, RequestDefinition definition, ParameterCollection? parameters, CancellationToken cancellationToken, int? weight = null) + internal async Task SendAsync(RequestDefinition definition, Parameters? parameters, CancellationToken cancellationToken, int? weight = null) { - var result = await base.SendAsync(baseAddress, definition, parameters, cancellationToken, null, weight).ConfigureAwait(false); - if (!result) - return result.AsDataless(); + var result = await base.SendAsync(definition, parameters, cancellationToken, null, weight).ConfigureAwait(false); + if (!result.Success) + return result; if (result.Data.Code != 1000) - return result.AsDatalessError(new ServerError(result.Data.Code, GetErrorInfo(result.Data.Code, result.Data.Message))); + return HttpResult.Fail(result, new ServerError(result.Data.Code, GetErrorInfo(result.Data.Code, result.Data.Message))); - return result.AsDataless(); + return result; } - internal Task> SendAsync(RequestDefinition definition, ParameterCollection? parameters, CancellationToken cancellationToken, int? weight = null, Dictionary? additionalHeaders = null) where T : class - => SendToAddressAsync(BaseAddress, definition, parameters, cancellationToken, weight, additionalHeaders); - - internal async Task> SendToAddressAsync(string baseAddress, RequestDefinition definition, ParameterCollection? parameters, CancellationToken cancellationToken, int? weight = null, Dictionary? additionalHeaders = null) where T : class + internal async Task> SendAsync(RequestDefinition definition, Parameters? parameters, CancellationToken cancellationToken, int? weight = null, Dictionary? additionalHeaders = null) where T : class { - var result = await base.SendAsync>(baseAddress, definition, parameters, cancellationToken, additionalHeaders, weight).ConfigureAwait(false); - if (!result) - return result.As(default); + var result = await base.SendAsync>(definition, parameters, cancellationToken, additionalHeaders, weight).ConfigureAwait(false); + if (!result.Success) + return HttpResult.Fail(result); if (result.Data.Code != 1000) - return result.AsError(new ServerError(result.Data.Code, GetErrorInfo(result.Data.Code, result.Data.Message))); + return HttpResult.Fail(result, new ServerError(result.Data.Code, GetErrorInfo(result.Data.Code, result.Data.Message))); - return result.As(result.Data.Data); + return HttpResult.Ok(result, result.Data.Data); } /// - protected override Task> GetServerTimestampAsync() + protected override Task> GetServerTimestampAsync() => _baseClient.SpotApi.ExchangeData.GetServerTimeAsync(); /// diff --git a/BitMart.Net/Clients/UsdFuturesApi/BitMartRestClientUsdFuturesApiAccount.cs b/BitMart.Net/Clients/UsdFuturesApi/BitMartRestClientUsdFuturesApiAccount.cs index 853603b..7ebe9ee 100644 --- a/BitMart.Net/Clients/UsdFuturesApi/BitMartRestClientUsdFuturesApiAccount.cs +++ b/BitMart.Net/Clients/UsdFuturesApi/BitMartRestClientUsdFuturesApiAccount.cs @@ -24,10 +24,10 @@ internal BitMartRestClientUsdFuturesApiAccount(BitMartRestClientUsdFuturesApi ba #region Get Balances /// - public async Task> GetBalancesAsync(CancellationToken ct = default) + public async Task> GetBalancesAsync(CancellationToken ct = default) { - var parameters = new ParameterCollection(); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/contract/private/assets-detail", BitMartExchange.RateLimiter.BitMart, 1, true, + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/contract/private/assets-detail", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(12, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); return await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); @@ -38,18 +38,21 @@ public async Task> GetBalancesAsync(Cance #region Get Transfer History /// - public async Task> GetTransferHistoryAsync(string? asset = null, DateTime? startTime = null, DateTime? endTime = null, int? page = null, int? limit = null, CancellationToken ct = default) + public async Task> GetTransferHistoryAsync(string? asset = null, DateTime? startTime = null, DateTime? endTime = null, int? page = null, int? limit = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); - parameters.AddOptional("currency", asset); - parameters.AddOptionalMillisecondsString("time_start", startTime); - parameters.AddOptionalMillisecondsString("time_end", endTime); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); + parameters.Add("currency", asset); + parameters.Add("time_start", startTime); + parameters.Add("time_end", endTime); parameters.Add("page", page ?? 1); parameters.Add("limit", limit ?? 10); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/account/v1/transfer-contract-list", BitMartExchange.RateLimiter.BitMart, 1, true, + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/account/v1/transfer-contract-list", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(1, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); - return result.As(result.Data?.Records); + if (!result.Success) + return HttpResult.Fail(result); + + return HttpResult.Ok(result, result.Data.Records); } #endregion @@ -57,13 +60,13 @@ public async Task> GetTransferHistoryAsy #region Transfer /// - public async Task> TransferAsync(string asset, decimal quantity, FuturesTransferType type, CancellationToken ct = default) + public async Task> TransferAsync(string asset, decimal quantity, FuturesTransferType type, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("currency", asset); - parameters.AddString("amount", quantity); - parameters.AddEnum("type", type); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/account/v1/transfer-contract", BitMartExchange.RateLimiter.BitMart, 1, true, + parameters.Add("amount", quantity); + parameters.Add("type", type); + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/account/v1/transfer-contract", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(1, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; @@ -74,13 +77,13 @@ public async Task> TransferAsync(string ass #region Set Leverage /// - public async Task> SetLeverageAsync(string symbol, decimal leverage, MarginType marginType, CancellationToken ct = default) + public async Task> SetLeverageAsync(string symbol, decimal leverage, MarginType marginType, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("symbol", symbol); - parameters.AddString("leverage", leverage); - parameters.AddEnum("open_type", marginType); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/contract/private/submit-leverage", BitMartExchange.RateLimiter.BitMart, 1, true, + parameters.Add("leverage", leverage); + parameters.Add("open_type", marginType); + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/contract/private/submit-leverage", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(24, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; @@ -91,13 +94,13 @@ public async Task> SetLeverageAsync(string symbol #region Get Symbol Trade Fee /// - public async Task> GetSymbolTradeFeeAsync(string symbol, CancellationToken ct = default) + public async Task> GetSymbolTradeFeeAsync(string symbol, CancellationToken ct = default) { - var parameters = new ParameterCollection() + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings) { { "symbol", symbol } }; - var request = _definitions.GetOrCreate(HttpMethod.Get, "/contract/private/trade-fee-rate", BitMartExchange.RateLimiter.BitMart, 1, true, + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/contract/private/trade-fee-rate", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(2, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); return await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); @@ -108,15 +111,15 @@ public async Task> GetSymbolTradeFeeAsync(s #region Get Transaction History /// - public async Task> GetTransactionHistoryAsync(string? symbol = null, FlowType? flowType = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default) + public async Task> GetTransactionHistoryAsync(string? symbol = null, FlowType? flowType = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); - parameters.AddOptional("symbol", symbol); - parameters.AddOptionalEnum("flow_type", flowType); - parameters.AddOptionalMillisecondsString("time_start", startTime); - parameters.AddOptionalMillisecondsString("time_end", endTime); - parameters.AddOptional("page_size", limit); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/contract/private/transaction-history", BitMartExchange.RateLimiter.BitMart, 1, true, + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); + parameters.Add("symbol", symbol); + parameters.Add("flow_type", flowType); + parameters.Add("time_start", startTime); + parameters.Add("time_end", endTime); + parameters.Add("page_size", limit); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/contract/private/transaction-history", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(6, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); return await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); } @@ -126,11 +129,11 @@ public async Task> GetTransactionHist #region Set Position Mode /// - public async Task> SetPositionModeAsync(PositionMode positionMode, CancellationToken ct = default) + public async Task> SetPositionModeAsync(PositionMode positionMode, CancellationToken ct = default) { - var parameters = new ParameterCollection(); - parameters.AddEnum("position_mode", positionMode); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/contract/private/set-position-mode", BitMartExchange.RateLimiter.BitMart, 1, true, + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); + parameters.Add("position_mode", positionMode); + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/contract/private/set-position-mode", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(2, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; @@ -141,10 +144,10 @@ public async Task> SetPositionModeAsync(Posit #region Get Position Mode /// - public async Task> GetPositionModeAsync(CancellationToken ct = default) + public async Task> GetPositionModeAsync(CancellationToken ct = default) { - var parameters = new ParameterCollection(); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/contract/private/get-position-mode", BitMartExchange.RateLimiter.BitMart, 1, true, + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/contract/private/get-position-mode", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(2, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; diff --git a/BitMart.Net/Clients/UsdFuturesApi/BitMartRestClientUsdFuturesApiExchangeData.cs b/BitMart.Net/Clients/UsdFuturesApi/BitMartRestClientUsdFuturesApiExchangeData.cs index 916c134..7f5ecc8 100644 --- a/BitMart.Net/Clients/UsdFuturesApi/BitMartRestClientUsdFuturesApiExchangeData.cs +++ b/BitMart.Net/Clients/UsdFuturesApi/BitMartRestClientUsdFuturesApiExchangeData.cs @@ -25,14 +25,17 @@ internal BitMartRestClientUsdFuturesApiExchangeData(ILogger logger, BitMartRestC #region Get Contracts /// - public async Task> GetContractsAsync(string? symbol = null, CancellationToken ct = default) + public async Task> GetContractsAsync(string? symbol = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); - parameters.AddOptional("symbol", symbol); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/contract/public/details", BitMartExchange.RateLimiter.BitMart, 1, false, + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); + parameters.Add("symbol", symbol); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/contract/public/details", BitMartExchange.RateLimiter.BitMart, 1, false, new SingleLimitGuard(12, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); - return result.As(result.Data?.Symbols); + if (!result.Success) + return HttpResult.Fail(result); + + return HttpResult.Ok(result, result.Data.Symbols); } #endregion @@ -40,11 +43,11 @@ public async Task> GetContractsAsync(string? sy #region Get Order Book /// - public async Task> GetOrderBookAsync(string symbol, CancellationToken ct = default) + public async Task> GetOrderBookAsync(string symbol, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("symbol", symbol); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/contract/public/depth", BitMartExchange.RateLimiter.BitMart, 1, false, + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/contract/public/depth", BitMartExchange.RateLimiter.BitMart, 1, false, new SingleLimitGuard(12, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; @@ -55,11 +58,11 @@ public async Task> GetOrderBookAsync(string symb #region Get Open Interest /// - public async Task> GetOpenInterestAsync(string symbol, CancellationToken ct = default) + public async Task> GetOpenInterestAsync(string symbol, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("symbol", symbol); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/contract/public/open-interest", BitMartExchange.RateLimiter.BitMart, 1, false, + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/contract/public/open-interest", BitMartExchange.RateLimiter.BitMart, 1, false, new SingleLimitGuard(2, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; @@ -70,11 +73,11 @@ public async Task> GetOpenInterestAsync(strin #region Get Current Funding Rate /// - public async Task> GetCurrentFundingRateAsync(string symbol, CancellationToken ct = default) + public async Task> GetCurrentFundingRateAsync(string symbol, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("symbol", symbol); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/contract/public/funding-rate", BitMartExchange.RateLimiter.BitMart, 1, false, + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/contract/public/funding-rate", BitMartExchange.RateLimiter.BitMart, 1, false, new SingleLimitGuard(2, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; @@ -85,15 +88,18 @@ public async Task> GetCurrentFundingRateAsync( #region Get Funding Rate History /// - public async Task> GetFundingRateHistoryAsync(string symbol, int? limit = null, CancellationToken ct = default) + public async Task> GetFundingRateHistoryAsync(string symbol, int? limit = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("symbol", symbol); - parameters.AddOptional("limit", limit); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/contract/public/funding-rate-history", BitMartExchange.RateLimiter.BitMart, 1, false, + parameters.Add("limit", limit); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/contract/public/funding-rate-history", BitMartExchange.RateLimiter.BitMart, 1, false, new SingleLimitGuard(12, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); - return result.As(result.Data?.History); + if (!result.Success) + return HttpResult.Fail(result); + + return HttpResult.Ok(result, result.Data.History); } #endregion @@ -101,14 +107,14 @@ public async Task> GetFundingRateHist #region Get Klines /// - public async Task> GetKlinesAsync(string symbol, FuturesKlineInterval klineInterval, DateTime startTime, DateTime endTime, CancellationToken ct = default) + public async Task> GetKlinesAsync(string symbol, FuturesKlineInterval klineInterval, DateTime startTime, DateTime endTime, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("symbol", symbol); - parameters.AddEnum("step", klineInterval); - parameters.AddSeconds("start_time", startTime); - parameters.AddSeconds("end_time", endTime); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/contract/public/kline", BitMartExchange.RateLimiter.BitMart, 1, false, + parameters.Add("step", klineInterval); + parameters.Add("start_time", startTime, DateTimeSerialization.SecondsString); + parameters.Add("end_time", endTime, DateTimeSerialization.SecondsString); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/contract/public/kline", BitMartExchange.RateLimiter.BitMart, 1, false, new SingleLimitGuard(12, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; @@ -119,14 +125,14 @@ public async Task> GetKlinesAsync(string sy #region Get Mark Klines /// - public async Task> GetMarkKlinesAsync(string symbol, FuturesKlineInterval klineInterval, DateTime startTime, DateTime endTime, CancellationToken ct = default) + public async Task> GetMarkKlinesAsync(string symbol, FuturesKlineInterval klineInterval, DateTime startTime, DateTime endTime, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("symbol", symbol); - parameters.AddEnum("step", klineInterval); - parameters.AddSeconds("start_time", startTime); - parameters.AddSeconds("end_time", endTime); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/contract/public/markprice-kline", BitMartExchange.RateLimiter.BitMart, 1, false, + parameters.Add("step", klineInterval); + parameters.Add("start_time", startTime, DateTimeSerialization.SecondsString); + parameters.Add("end_time", endTime, DateTimeSerialization.SecondsString); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/contract/public/markprice-kline", BitMartExchange.RateLimiter.BitMart, 1, false, new SingleLimitGuard(12, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; @@ -137,14 +143,17 @@ public async Task> GetMarkKlinesAsync(strin #region Get Leverage Brackets /// - public async Task> GetLeverageBracketsAsync(string? symbol = null, CancellationToken ct = default) + public async Task> GetLeverageBracketsAsync(string? symbol = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); - parameters.AddOptional("symbol", symbol); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/contract/public/leverage-bracket", BitMartExchange.RateLimiter.BitMart, 1, false, + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); + parameters.Add("symbol", symbol); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/contract/public/leverage-bracket", BitMartExchange.RateLimiter.BitMart, 1, false, new SingleLimitGuard(12, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); - return result.As(result.Data?.Rules); + if (!result.Success) + return HttpResult.Fail(result); + + return HttpResult.Ok(result, result.Data.Rules); } #endregion @@ -152,12 +161,12 @@ public async Task> GetLeverageBracketsAsyn #region Get Recent Trades /// - public async Task> GetRecentTradesAsync(string symbol, int? limit = null, CancellationToken ct = default) + public async Task> GetRecentTradesAsync(string symbol, int? limit = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("symbol", symbol); - parameters.AddOptional("limit", limit); - var request = _definitions.GetOrCreate(HttpMethod.Get, "contract/public/market-trade", BitMartExchange.RateLimiter.BitMart, 1, false); + parameters.Add("limit", limit); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "contract/public/market-trade", BitMartExchange.RateLimiter.BitMart, 1, false); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; } diff --git a/BitMart.Net/Clients/UsdFuturesApi/BitMartRestClientUsdFuturesApiShared.cs b/BitMart.Net/Clients/UsdFuturesApi/BitMartRestClientUsdFuturesApiShared.cs index d8cf995..261ade9 100644 --- a/BitMart.Net/Clients/UsdFuturesApi/BitMartRestClientUsdFuturesApiShared.cs +++ b/BitMart.Net/Clients/UsdFuturesApi/BitMartRestClientUsdFuturesApiShared.cs @@ -16,54 +16,59 @@ namespace BitMart.Net.Clients.UsdFuturesApi internal partial class BitMartRestClientUsdFuturesApi : IBitMartRestClientUsdFuturesApiShared { private const string _topicId = "BitMartFutures"; - public string Exchange => BitMartExchange.ExchangeName; + private const string _exchangeName = "BitMart"; public TradingMode[] SupportedTradingModes { get; } = new[] { TradingMode.PerpetualLinear, TradingMode.DeliveryLinear }; public void SetDefaultExchangeParameter(string key, object value) => ExchangeParameters.SetStaticParameter(Exchange, key, value); public void ResetDefaultExchangeParameters() => ExchangeParameters.ResetStaticParameters(); + public SharedClientInfo Discover() => SharedUtils.GetClientInfo(BitMartExchange.Metadata, this); #region Balance client - GetBalancesOptions IBalanceRestClient.GetBalancesOptions { get; } = new GetBalancesOptions(AccountTypeFilter.Futures); + GetBalancesOptions IBalanceRestClient.GetBalancesOptions { get; } = new GetBalancesOptions(_exchangeName, AccountTypeFilter.Futures); - async Task> IBalanceRestClient.GetBalancesAsync(GetBalancesRequest request, CancellationToken ct) + async Task> IBalanceRestClient.GetBalancesAsync(GetBalancesRequest request, CancellationToken ct) { - var validationError = ((IBalanceRestClient)this).GetBalancesOptions.ValidateRequest(Exchange, request, SupportedTradingModes); + var validationError = SharedClient.GetBalancesOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var result = await Account.GetBalancesAsync(ct: ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult(Exchange, null, default); + if (!result.Success) + return HttpResult.Fail(result); - return result.AsExchangeResult(Exchange, SupportedTradingModes, result.Data.Select(x => new SharedBalance(x.Asset, x.AvailableBalance, x.Equity)).ToArray()); + return HttpResult.Ok(result, result.Data.Select(x => + new SharedBalance( + SupportedTradingModes, + x.Asset, + x.AvailableBalance, + x.Equity)).ToArray()); } #endregion #region Futures Ticker client - GetTickerOptions IFuturesTickerRestClient.GetFuturesTickerOptions { get; } = new GetTickerOptions(); - async Task> IFuturesTickerRestClient.GetFuturesTickerAsync(GetTickerRequest request, CancellationToken ct) + GetFuturesTickerOptions IFuturesTickerRestClient.GetFuturesTickerOptions { get; } = new GetFuturesTickerOptions(_exchangeName); + async Task> IFuturesTickerRestClient.GetFuturesTickerAsync(GetTickerRequest request, CancellationToken ct) { - var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickerOptions.ValidateRequest(Exchange, request, request.Symbol!.TradingMode, SupportedTradingModes); + var validationError = SharedClient.GetFuturesTickerOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var resultTicker = ExchangeData.GetContractsAsync(request.Symbol!.GetSymbol(FormatSymbol), ct); var resultFundingRate = ExchangeData.GetCurrentFundingRateAsync(request.Symbol!.GetSymbol(FormatSymbol), ct); await Task.WhenAll(resultTicker, resultFundingRate).ConfigureAwait(false); - if (!resultTicker.Result) - return resultTicker.Result.AsExchangeResult(Exchange, null, default); - if (!resultFundingRate.Result) - return resultFundingRate.Result.AsExchangeResult(Exchange, null, default); + if (!resultTicker.Result.Success) + return HttpResult.Fail(resultTicker.Result); + if (!resultFundingRate.Result.Success) + return HttpResult.Fail(resultFundingRate.Result); var symbol = resultTicker.Result.Data.SingleOrDefault(); if (symbol == null) - return resultTicker.Result.AsExchangeError(Exchange, new ServerError(new ErrorInfo(ErrorType.UnknownSymbol, "Symbol not found"))); + return HttpResult.Fail(Exchange, new ServerError(new ErrorInfo(ErrorType.UnknownSymbol, "Symbol not found"))); - return resultTicker.Result.AsExchangeResult(Exchange, SupportedTradingModes, - new SharedFuturesTicker( - ExchangeSymbolCache.ParseSymbol(_topicId, symbol.Symbol), + return HttpResult.Ok(resultTicker.Result, new SharedFuturesTicker( + ExchangeSymbolCache.ParseSymbol(_topicId, EnvironmentName, null, symbol.Symbol), symbol.Symbol, symbol.LastPrice, symbol.HighPrice, @@ -77,24 +82,24 @@ async Task> IFuturesTickerRestClient.GetF }); } - GetTickersOptions IFuturesTickerRestClient.GetFuturesTickersOptions { get; } = new GetTickersOptions(); + GetFuturesTickersOptions IFuturesTickerRestClient.GetFuturesTickersOptions { get; } = new GetFuturesTickersOptions(_exchangeName); - async Task> IFuturesTickerRestClient.GetFuturesTickersAsync(GetTickersRequest request, CancellationToken ct) + async Task> IFuturesTickerRestClient.GetFuturesTickersAsync(GetTickersRequest request, CancellationToken ct) { - var validationError = ((IFuturesTickerRestClient)this).GetFuturesTickersOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); + var validationError = SharedClient.GetFuturesTickersOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var resultTicker = await ExchangeData.GetContractsAsync(ct: ct).ConfigureAwait(false); - if (!resultTicker) - return resultTicker.AsExchangeResult(Exchange, null, default); + if (!resultTicker.Success) + return HttpResult.Fail(resultTicker); IEnumerable data = resultTicker.Data; if (request.TradingMode != null) data = data.Where(x => request.TradingMode == TradingMode.PerpetualLinear ? x.ProductType == ContractType.Perpetual : x.ProductType == ContractType.Futures); - return resultTicker.AsExchangeResult(Exchange, request.TradingMode == null ? SupportedTradingModes : new[] { request.TradingMode.Value }, data.Select(x => - new SharedFuturesTicker(ExchangeSymbolCache.ParseSymbol(_topicId, x.Symbol), x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume24h, x.Change24h * 100) + return HttpResult.Ok(resultTicker, data.Select(x => + new SharedFuturesTicker(ExchangeSymbolCache.ParseSymbol(_topicId, EnvironmentName, null, x.Symbol), x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume24h, x.Change24h * 100) { FundingRate = x.FundingRate, IndexPrice = x.IndexPrice @@ -106,19 +111,19 @@ async Task> IFuturesTickerRestClient.Ge #region Book Ticker client - EndpointOptions IBookTickerRestClient.GetBookTickerOptions { get; } = new EndpointOptions(false); - async Task> IBookTickerRestClient.GetBookTickerAsync(GetBookTickerRequest request, CancellationToken ct) + GetBookTickerOptions IBookTickerRestClient.GetBookTickerOptions { get; } = new GetBookTickerOptions(_exchangeName, false); + async Task> IBookTickerRestClient.GetBookTickerAsync(GetBookTickerRequest request, CancellationToken ct) { - var validationError = ((IBookTickerRestClient)this).GetBookTickerOptions.ValidateRequest(Exchange, request, request.Symbol!.TradingMode, SupportedTradingModes); + var validationError = SharedClient.GetBookTickerOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var resultTicker = await ExchangeData.GetOrderBookAsync(request.Symbol!.GetSymbol(FormatSymbol), ct: ct).ConfigureAwait(false); - if (!resultTicker) - return resultTicker.AsExchangeResult(Exchange, null, default); + if (!resultTicker.Success) + return HttpResult.Fail(resultTicker); - return resultTicker.AsExchangeResult(Exchange, request.Symbol!.TradingMode, new SharedBookTicker( - ExchangeSymbolCache.ParseSymbol(_topicId, resultTicker.Data.Symbol), + return HttpResult.Ok(resultTicker, new SharedBookTicker( + ExchangeSymbolCache.ParseSymbol(_topicId, EnvironmentName, null, resultTicker.Data.Symbol), resultTicker.Data.Symbol, resultTicker.Data.Asks[0].Price, resultTicker.Data.Asks[0].Quantity, @@ -129,23 +134,23 @@ async Task> IBookTickerRestClient.GetBookTic #endregion #region Recent Trade client - GetRecentTradesOptions IRecentTradeRestClient.GetRecentTradesOptions { get; } = new GetRecentTradesOptions(100, false); + GetRecentTradesOptions IRecentTradeRestClient.GetRecentTradesOptions { get; } = new GetRecentTradesOptions(_exchangeName, 100, false); - async Task> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, CancellationToken ct) + async Task> IRecentTradeRestClient.GetRecentTradesAsync(GetRecentTradesRequest request, CancellationToken ct) { - var validationError = ((IRecentTradeRestClient)this).GetRecentTradesOptions.ValidateRequest(Exchange, request, request.Symbol!.TradingMode, SupportedTradingModes); + var validationError = SharedClient.GetRecentTradesOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var symbol = request.Symbol!.GetSymbol(FormatSymbol); var result = await ExchangeData.GetRecentTradesAsync( symbol, limit: request.Limit, ct: ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult(Exchange, null, default); + if (!result.Success) + return HttpResult.Fail(result); - return result.AsExchangeResult(Exchange, request.Symbol!.TradingMode, result.Data.Select(x => + return HttpResult.Ok(result, result.Data.Select(x => new SharedTrade(request.Symbol, symbol, x.Quantity, x.Price, x.Timestamp) { Side = x.IsBuyerMaker ? SharedOrderSide.Sell : SharedOrderSide.Buy, @@ -156,21 +161,21 @@ async Task> IRecentTradeRestClient.GetRecentTra #region Futures Symbol client - EndpointOptions IFuturesSymbolRestClient.GetFuturesSymbolsOptions { get; } = new EndpointOptions(false); - async Task> IFuturesSymbolRestClient.GetFuturesSymbolsAsync(GetSymbolsRequest request, CancellationToken ct) + GetFuturesSymbolsOptions IFuturesSymbolRestClient.GetFuturesSymbolsOptions { get; } = new GetFuturesSymbolsOptions(_exchangeName, false); + async Task> IFuturesSymbolRestClient.GetFuturesSymbolsAsync(GetSymbolsRequest request, CancellationToken ct) { - var validationError = ((IFuturesSymbolRestClient)this).GetFuturesSymbolsOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); + var validationError = SharedClient.GetFuturesSymbolsOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var result = await ExchangeData.GetContractsAsync(ct: ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult(Exchange, null, default); + if (!result.Success) + return HttpResult.Fail(result); IEnumerable data = result.Data; if (request.TradingMode != null) data = data.Where(x => request.TradingMode == TradingMode.PerpetualLinear ? x.ProductType == ContractType.Perpetual : x.ProductType != ContractType.Perpetual); - var response = result.AsExchangeResult(Exchange, request.TradingMode == null ? SupportedTradingModes : new[] { request.TradingMode.Value }, data.Select(s => + var response = HttpResult.Ok(result, data.Select(s => new SharedFuturesSymbol( s.ProductType == ContractType.Perpetual ? TradingMode.PerpetualLinear : TradingMode.DeliveryLinear, s.BaseAsset, @@ -188,70 +193,70 @@ async Task> IFuturesSymbolRestClient.Ge MaxShortLeverage = s.MaxLeverage }).ToArray()); - ExchangeSymbolCache.UpdateSymbolInfo(_topicId, response.Data); + ExchangeSymbolCache.UpdateSymbolInfo(_topicId, EnvironmentName, null, response.Data!); return response; } - async Task> IFuturesSymbolRestClient.GetFuturesSymbolsForBaseAssetAsync(string baseAsset) + async Task> IFuturesSymbolRestClient.GetFuturesSymbolsForBaseAssetAsync(string baseAsset) { - if (!ExchangeSymbolCache.HasCached(_topicId)) + if (!ExchangeSymbolCache.HasCached(_topicId, EnvironmentName, null)) { var symbols = await ((IFuturesSymbolRestClient)this).GetFuturesSymbolsAsync(new GetSymbolsRequest()).ConfigureAwait(false); - if (!symbols) - return new ExchangeResult(Exchange, symbols.Error!); + if (!symbols.Success) + return ExchangeCallResult.Fail(Exchange, symbols.Error!); } - return new ExchangeResult(Exchange, ExchangeSymbolCache.GetSymbolsForBaseAsset(_topicId, baseAsset)); + return ExchangeCallResult.Ok(Exchange, ExchangeSymbolCache.GetSymbolsForBaseAsset(_topicId, EnvironmentName, null, baseAsset)); } - async Task> IFuturesSymbolRestClient.SupportsFuturesSymbolAsync(SharedSymbol symbol) + async Task> IFuturesSymbolRestClient.SupportsFuturesSymbolAsync(SharedSymbol symbol) { if (symbol.TradingMode == TradingMode.Spot) throw new ArgumentException(nameof(symbol), "Spot symbols not allowed"); - if (!ExchangeSymbolCache.HasCached(_topicId)) + if (!ExchangeSymbolCache.HasCached(_topicId, EnvironmentName, null)) { var symbols = await ((IFuturesSymbolRestClient)this).GetFuturesSymbolsAsync(new GetSymbolsRequest()).ConfigureAwait(false); - if (!symbols) - return new ExchangeResult(Exchange, symbols.Error!); + if (!symbols.Success) + return ExchangeCallResult.Fail(Exchange, symbols.Error!); } - return new ExchangeResult(Exchange, ExchangeSymbolCache.SupportsSymbol(_topicId, symbol)); + return ExchangeCallResult.Ok(Exchange, ExchangeSymbolCache.SupportsSymbol(_topicId, EnvironmentName, null, symbol)); } - async Task> IFuturesSymbolRestClient.SupportsFuturesSymbolAsync(string symbolName) + async Task> IFuturesSymbolRestClient.SupportsFuturesSymbolAsync(string symbolName) { - if (!ExchangeSymbolCache.HasCached(_topicId)) + if (!ExchangeSymbolCache.HasCached(_topicId, EnvironmentName, null)) { var symbols = await ((IFuturesSymbolRestClient)this).GetFuturesSymbolsAsync(new GetSymbolsRequest()).ConfigureAwait(false); - if (!symbols) - return new ExchangeResult(Exchange, symbols.Error!); + if (!symbols.Success) + return ExchangeCallResult.Fail(Exchange, symbols.Error!); } - return new ExchangeResult(Exchange, ExchangeSymbolCache.SupportsSymbol(_topicId, symbolName)); + return ExchangeCallResult.Ok(Exchange, ExchangeSymbolCache.SupportsSymbol(_topicId, EnvironmentName, null, symbolName)); } #endregion #region Futures Client Id Order Client - EndpointOptions IFuturesOrderClientIdRestClient.GetFuturesOrderByClientOrderIdOptions { get; } = new EndpointOptions(true) + GetFuturesOrderByClientOrderIdOptions IFuturesOrderClientIdRestClient.GetFuturesOrderByClientOrderIdOptions { get; } = new GetFuturesOrderByClientOrderIdOptions(_exchangeName, true) { }; - async Task> IFuturesOrderClientIdRestClient.GetFuturesOrderByClientOrderIdAsync(GetOrderRequest request, CancellationToken ct) + async Task> IFuturesOrderClientIdRestClient.GetFuturesOrderByClientOrderIdAsync(GetOrderRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderOptions.ValidateRequest(Exchange, request, request.Symbol!.TradingMode, SupportedTradingModes); + var validationError = SharedClient.GetFuturesOrderOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var orders = await Trading.GetClosedOrdersAsync(request.Symbol!.GetSymbol(FormatSymbol), clientOrderId: request.OrderId, ct: ct).ConfigureAwait(false); - if (!orders) - return orders.AsExchangeResult(Exchange, null, default); + if (!orders.Success) + return HttpResult.Fail(orders); var order = orders.Data.FirstOrDefault(); if (order == null) - return orders.AsExchangeError(Exchange, new ServerError(new ErrorInfo(ErrorType.UnknownOrder, "Order not found"))); + return HttpResult.Fail(Exchange, new ServerError(new ErrorInfo(ErrorType.UnknownOrder, "Order not found"))); - return orders.AsExchangeResult(Exchange, request.Symbol!.TradingMode, new SharedFuturesOrder( - ExchangeSymbolCache.ParseSymbol(_topicId, order.Symbol), + return HttpResult.Ok(orders, new SharedFuturesOrder( + ExchangeSymbolCache.ParseSymbol(_topicId, EnvironmentName, null, order.Symbol), order.Symbol, order.OrderId, ParseOrderType(order.OrderType), @@ -274,24 +279,24 @@ async Task> IFuturesOrderClientIdRestClien }); } - EndpointOptions IFuturesOrderClientIdRestClient.CancelFuturesOrderByClientOrderIdOptions { get; } = new EndpointOptions(true); - async Task> IFuturesOrderClientIdRestClient.CancelFuturesOrderByClientOrderIdAsync(CancelOrderRequest request, CancellationToken ct) + CancelFuturesOrderByClientOrderIdOptions IFuturesOrderClientIdRestClient.CancelFuturesOrderByClientOrderIdOptions { get; } = new CancelFuturesOrderByClientOrderIdOptions(_exchangeName, true); + async Task> IFuturesOrderClientIdRestClient.CancelFuturesOrderByClientOrderIdAsync(CancelOrderRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).CancelFuturesOrderOptions.ValidateRequest(Exchange, request, request.Symbol!.TradingMode, SupportedTradingModes); + var validationError = SharedClient.CancelFuturesOrderOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var order = await Trading.CancelOrderAsync(request.Symbol!.GetSymbol(FormatSymbol), clientOrderId: request.OrderId, ct: ct).ConfigureAwait(false); - if (!order) - return order.AsExchangeResult(Exchange, null, default); + if (!order.Success) + return HttpResult.Fail(order); - return order.AsExchangeResult(Exchange, request.Symbol!.TradingMode, new SharedId(request.OrderId)); + return HttpResult.Ok(order, new SharedId(request.OrderId)); } #endregion #region Klines client - GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(true, true, true, 500, false, + GetKlinesOptions IKlineRestClient.GetKlinesOptions { get; } = new GetKlinesOptions(_exchangeName, true, true, true, 500, false, SharedKlineInterval.OneMinute, SharedKlineInterval.FiveMinutes, SharedKlineInterval.FifteenMinutes, @@ -307,18 +312,15 @@ async Task> IFuturesOrderClientIdRestClient.CancelFu MaxTotalDataPoints = 500 }; - async Task> IKlineRestClient.GetKlinesAsync(GetKlinesRequest request, PageRequest? pageRequest, CancellationToken ct) + async Task> IKlineRestClient.GetKlinesAsync(GetKlinesRequest request, PageRequest? pageRequest, CancellationToken ct) { var interval = (Enums.FuturesKlineInterval)request.Interval; - if (!Enum.IsDefined(typeof(Enums.FuturesKlineInterval), interval)) - return new ExchangeWebResult(Exchange, ArgumentError.Invalid(nameof(GetKlinesRequest.Interval), "Interval not supported")); - - var validationError = ((IKlineRestClient)this).GetKlinesOptions.ValidateRequest(Exchange, request, request.Symbol!.TradingMode, SupportedTradingModes); + var validationError = SharedClient.GetKlinesOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); // No pagination available, always returns the full data up to 500 data points - var symbol = request.Symbol.GetSymbol(FormatSymbol); + var symbol = request.Symbol!.GetSymbol(FormatSymbol); var result = await ExchangeData.GetKlinesAsync( symbol, interval, @@ -326,13 +328,10 @@ async Task> IKlineRestClient.GetKlinesAsync(Get endTime: request.EndTime ?? DateTime.UtcNow, ct: ct ).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult(Exchange, null, default); + if (!result.Success) + return HttpResult.Fail(result); - return result.AsExchangeResult( - Exchange, - request.Symbol.TradingMode, - ExchangeHelpers.ApplyFilter(result.Data, x => x.Timestamp!.Value, request.StartTime, request.EndTime, request.Direction ?? DataDirection.Descending) + return HttpResult.Ok(result, ExchangeHelpers.ApplyFilter(result.Data, x => x.Timestamp!.Value, request.StartTime, request.EndTime, request.Direction ?? DataDirection.Descending) .Select(x => new SharedKline(request.Symbol, symbol, x.Timestamp!.Value, x.ClosePrice, x.HighPrice, x.LowPrice, x.OpenPrice, x.Volume)) .ToArray()); @@ -343,43 +342,43 @@ async Task> IKlineRestClient.GetKlinesAsync(Get #region Leverage client SharedLeverageSettingMode ILeverageRestClient.LeverageSettingType => SharedLeverageSettingMode.PerSymbol; - EndpointOptions ILeverageRestClient.GetLeverageOptions { get; } = new EndpointOptions(true); - async Task> ILeverageRestClient.GetLeverageAsync(GetLeverageRequest request, CancellationToken ct) + GetLeverageOptions ILeverageRestClient.GetLeverageOptions { get; } = new GetLeverageOptions(_exchangeName, true); + async Task> ILeverageRestClient.GetLeverageAsync(GetLeverageRequest request, CancellationToken ct) { - var validationError = ((ILeverageRestClient)this).GetLeverageOptions.ValidateRequest(Exchange, request, request.Symbol!.TradingMode, SupportedTradingModes); + var validationError = SharedClient.GetLeverageOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var result = await Trading.GetPositionRiskAsync( symbol: request.Symbol!.GetSymbol(FormatSymbol), ct: ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult(Exchange, null, default); + if (!result.Success) + return HttpResult.Fail(result); var position = result.Data.FirstOrDefault(x => x.PositionSide == (request.PositionSide == SharedPositionSide.Short ? PositionSide.Short : PositionSide.Long)) ?? result.Data.First(); - return result.AsExchangeResult(Exchange, request.Symbol!.TradingMode, new SharedLeverage(position.Leverage) + return HttpResult.Ok(result, new SharedLeverage(position.Leverage) { MarginMode = position.MarginType == MarginType.CrossMargin ? SharedMarginMode.Cross : SharedMarginMode.Isolated }); } - SetLeverageOptions ILeverageRestClient.SetLeverageOptions { get; } = new SetLeverageOptions(); - async Task> ILeverageRestClient.SetLeverageAsync(SetLeverageRequest request, CancellationToken ct) + SetLeverageOptions ILeverageRestClient.SetLeverageOptions { get; } = new SetLeverageOptions(_exchangeName); + async Task> ILeverageRestClient.SetLeverageAsync(SetLeverageRequest request, CancellationToken ct) { - var validationError = ((ILeverageRestClient)this).SetLeverageOptions.ValidateRequest(Exchange, request, request.Symbol!.TradingMode, SupportedTradingModes); + var validationError = SharedClient.SetLeverageOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var result = await Account.SetLeverageAsync( symbol: request.Symbol!.GetSymbol(FormatSymbol), request.Leverage, request.MarginMode == SharedMarginMode.Isolated ? MarginType.IsolatedMargin : MarginType.CrossMargin, ct: ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult(Exchange, null, default); + if (!result.Success) + return HttpResult.Fail(result); - return result.AsExchangeResult(Exchange, request.Symbol!.TradingMode, new SharedLeverage(request.Leverage) + return HttpResult.Ok(result, new SharedLeverage(request.Leverage) { MarginMode = result.Data.MarginType == MarginType.CrossMargin ? SharedMarginMode.Cross : SharedMarginMode.Isolated }); @@ -387,38 +386,38 @@ async Task> ILeverageRestClient.SetLeverageAsy #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, CancellationToken ct) + GetOrderBookOptions IOrderBookRestClient.GetOrderBookOptions { get; } = new GetOrderBookOptions(_exchangeName, 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!.TradingMode, SupportedTradingModes); + var validationError = SharedClient.GetOrderBookOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var result = await ExchangeData.GetOrderBookAsync( request.Symbol!.GetSymbol(FormatSymbol), ct: ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult(Exchange, null, default); + if (!result.Success) + return HttpResult.Fail(result); - return result.AsExchangeResult(Exchange, request.Symbol!.TradingMode, new SharedOrderBook(result.Data.Asks, result.Data.Bids)); + return HttpResult.Ok(result, new SharedOrderBook(result.Data.Asks, result.Data.Bids)); } #endregion #region Open Interest client - EndpointOptions IOpenInterestRestClient.GetOpenInterestOptions { get; } = new EndpointOptions(true); - async Task> IOpenInterestRestClient.GetOpenInterestAsync(GetOpenInterestRequest request, CancellationToken ct) + GetOpenInterestOptions IOpenInterestRestClient.GetOpenInterestOptions { get; } = new GetOpenInterestOptions(_exchangeName, true); + async Task> IOpenInterestRestClient.GetOpenInterestAsync(GetOpenInterestRequest request, CancellationToken ct) { - var validationError = ((IOpenInterestRestClient)this).GetOpenInterestOptions.ValidateRequest(Exchange, request, request.Symbol!.TradingMode, SupportedTradingModes); + var validationError = SharedClient.GetOpenInterestOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var result = await ExchangeData.GetOpenInterestAsync(request.Symbol!.GetSymbol(FormatSymbol), ct: ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult(Exchange, null, default); + if (!result.Success) + return HttpResult.Fail(result); - return result.AsExchangeResult(Exchange, request.Symbol!.TradingMode, new SharedOpenInterest(result.Data.OpenInterest)); + return HttpResult.Ok(result, new SharedOpenInterest(result.Data.OpenInterest)); } #endregion @@ -437,25 +436,18 @@ async Task> IOpenInterestRestClient.GetOpe string IFuturesOrderRestClient.GenerateClientOrderId() => ExchangeHelpers.RandomString(32); - PlaceFuturesOrderOptions IFuturesOrderRestClient.PlaceFuturesOrderOptions { get; } = new PlaceFuturesOrderOptions(true) + PlaceFuturesOrderOptions IFuturesOrderRestClient.PlaceFuturesOrderOptions { get; } = new PlaceFuturesOrderOptions(_exchangeName, true) { RequiredOptionalParameters = new List { new ParameterDescription(nameof(PlaceFuturesOrderRequest.PositionSide), typeof(SharedPositionSide), "Position side for the order", SharedPositionSide.Long) } }; - async Task> IFuturesOrderRestClient.PlaceFuturesOrderAsync(PlaceFuturesOrderRequest request, CancellationToken ct) + async Task> IFuturesOrderRestClient.PlaceFuturesOrderAsync(PlaceFuturesOrderRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).PlaceFuturesOrderOptions.ValidateRequest( - Exchange, - request, - request.Symbol!.TradingMode, - SupportedTradingModes, - ((IFuturesOrderRestClient)this).FuturesSupportedOrderTypes, - ((IFuturesOrderRestClient)this).FuturesSupportedTimeInForce, - ((IFuturesOrderRestClient)this).FuturesSupportedOrderQuantity); + var validationError = SharedClient.PlaceFuturesOrderOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var result = await Trading.PlaceOrderAsync( request.Symbol!.GetSymbol(FormatSymbol), @@ -471,25 +463,25 @@ async Task> IFuturesOrderRestClient.PlaceFuturesOrde presetStopLossPrice: request.StopLossPrice, ct: ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult(Exchange, null, default); + if (!result.Success) + return HttpResult.Fail(result); - return result.AsExchangeResult(Exchange, request.Symbol!.TradingMode, new SharedId(result.Data.OrderId.ToString())); + return HttpResult.Ok(result, new SharedId(result.Data.OrderId.ToString())); } - EndpointOptions IFuturesOrderRestClient.GetFuturesOrderOptions { get; } = new EndpointOptions(true); - async Task> IFuturesOrderRestClient.GetFuturesOrderAsync(GetOrderRequest request, CancellationToken ct) + GetFuturesOrderOptions IFuturesOrderRestClient.GetFuturesOrderOptions { get; } = new GetFuturesOrderOptions(_exchangeName, true); + async Task> IFuturesOrderRestClient.GetFuturesOrderAsync(GetOrderRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderOptions.ValidateRequest(Exchange, request, request.Symbol!.TradingMode, SupportedTradingModes); + var validationError = SharedClient.GetFuturesOrderOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var order = await Trading.GetOrderAsync(request.Symbol!.GetSymbol(FormatSymbol), request.OrderId, ct: ct).ConfigureAwait(false); - if (!order) - return order.AsExchangeResult(Exchange, null, default); + if (!order.Success) + return HttpResult.Fail(order); - return order.AsExchangeResult(Exchange, request.Symbol!.TradingMode, new SharedFuturesOrder( - ExchangeSymbolCache.ParseSymbol(_topicId, order.Data.Symbol), + return HttpResult.Ok(order, new SharedFuturesOrder( + ExchangeSymbolCache.ParseSymbol(_topicId, EnvironmentName, null, order.Data.Symbol), order.Data.Symbol, order.Data.OrderId, ParseOrderType(order.Data.OrderType), @@ -512,20 +504,20 @@ async Task> IFuturesOrderRestClient.GetFut }); } - EndpointOptions IFuturesOrderRestClient.GetOpenFuturesOrdersOptions { get; } = new EndpointOptions(true); - async Task> IFuturesOrderRestClient.GetOpenFuturesOrdersAsync(GetOpenOrdersRequest request, CancellationToken ct) + GetOpenFuturesOrdersOptions IFuturesOrderRestClient.GetOpenFuturesOrdersOptions { get; } = new GetOpenFuturesOrdersOptions(_exchangeName, true); + async Task> IFuturesOrderRestClient.GetOpenFuturesOrdersAsync(GetOpenOrdersRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetOpenFuturesOrdersOptions.ValidateRequest(Exchange, request, request.Symbol?.TradingMode ?? request.TradingMode, SupportedTradingModes); + var validationError = SharedClient.GetOpenFuturesOrdersOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var symbol = request.Symbol?.GetSymbol(FormatSymbol); var orders = await Trading.GetOpenOrdersAsync(symbol, ct: ct).ConfigureAwait(false); - if (!orders) - return orders.AsExchangeResult(Exchange, null, default); + if (!orders.Success) + return HttpResult.Fail(orders); - return orders.AsExchangeResult(Exchange, request.Symbol == null ? SupportedTradingModes : new[] { request.Symbol!.TradingMode }, orders.Data.Select(x => new SharedFuturesOrder( - ExchangeSymbolCache.ParseSymbol(_topicId, x.Symbol), + return HttpResult.Ok(orders, orders.Data.Select(x => new SharedFuturesOrder( + ExchangeSymbolCache.ParseSymbol(_topicId, EnvironmentName, null, x.Symbol), x.Symbol, x.OrderId, ParseOrderType(x.OrderType), @@ -548,12 +540,12 @@ async Task> IFuturesOrderRestClient.GetO }).ToArray()); } - GetClosedOrdersOptions IFuturesOrderRestClient.GetClosedFuturesOrdersOptions { get; } = new GetClosedOrdersOptions(false, true, true, 200); - async Task> IFuturesOrderRestClient.GetClosedFuturesOrdersAsync(GetClosedOrdersRequest request, PageRequest? pageRequest, CancellationToken ct) + GetFuturesClosedOrdersOptions IFuturesOrderRestClient.GetClosedFuturesOrdersOptions { get; } = new GetFuturesClosedOrdersOptions(_exchangeName, false, true, true, 200); + async Task> IFuturesOrderRestClient.GetClosedFuturesOrdersAsync(GetClosedOrdersRequest request, PageRequest? pageRequest, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetClosedFuturesOrdersOptions.ValidateRequest(Exchange, request, request.Symbol!.TradingMode, SupportedTradingModes); + var validationError = SharedClient.GetClosedFuturesOrdersOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var direction = DataDirection.Descending; var limit = 200; @@ -564,8 +556,8 @@ async Task> IFuturesOrderRestClient.GetC startTime: pageParams.StartTime, endTime: pageParams.EndTime, ct: ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult(Exchange, null, default); + if (!result.Success) + return HttpResult.Fail(result); var nextPageRequest = Pagination.GetNextPageRequest( // Filtering is done in seconds, so need to adjust to previous second instead of previous milliseconds @@ -577,13 +569,10 @@ async Task> IFuturesOrderRestClient.GetC pageParams, maxPeriod: TimeSpan.FromDays(90)); - return result.AsExchangeResult( - Exchange, - request.Symbol.TradingMode, - ExchangeHelpers.ApplyFilter(result.Data, x => x.CreateTime, request.StartTime, request.EndTime, direction) + return HttpResult.Ok(result, ExchangeHelpers.ApplyFilter(result.Data, x => x.CreateTime, request.StartTime, request.EndTime, direction) .Select(x => new SharedFuturesOrder( - ExchangeSymbolCache.ParseSymbol(_topicId, x.Symbol), + ExchangeSymbolCache.ParseSymbol(_topicId, EnvironmentName, null, x.Symbol), x.Symbol, x.OrderId, ParseOrderType(x.OrderType), @@ -607,25 +596,25 @@ async Task> IFuturesOrderRestClient.GetC .ToArray(), nextPageRequest); } - EndpointOptions IFuturesOrderRestClient.GetFuturesOrderTradesOptions { get; } = new EndpointOptions(true) + GetFuturesOrderTradesOptions IFuturesOrderRestClient.GetFuturesOrderTradesOptions { get; } = new GetFuturesOrderTradesOptions(_exchangeName, true) { RequestNotes = "Can only request trades for the past 7 days" }; - async Task> IFuturesOrderRestClient.GetFuturesOrderTradesAsync(GetOrderTradesRequest request, CancellationToken ct) + async Task> IFuturesOrderRestClient.GetFuturesOrderTradesAsync(GetOrderTradesRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetFuturesOrderTradesOptions.ValidateRequest(Exchange, request, request.Symbol!.TradingMode, SupportedTradingModes); + var validationError = SharedClient.GetFuturesOrderTradesOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); if (!long.TryParse(request.OrderId, out var orderId)) - return new ExchangeWebResult(Exchange, ArgumentError.Invalid(nameof(GetOrderTradesRequest.OrderId), "Invalid order id")); + return HttpResult.Fail(Exchange, ArgumentError.Invalid(nameof(GetOrderTradesRequest.OrderId), "Invalid order id")); var orders = await Trading.GetUserTradesAsync(request.Symbol!.GetSymbol(FormatSymbol), ct: ct).ConfigureAwait(false); - if (!orders) - return orders.AsExchangeResult(Exchange, null, default); + if (!orders.Success) + return HttpResult.Fail(orders); - return orders.AsExchangeResult(Exchange, request.Symbol!.TradingMode,orders.Data.Where(x => x.OrderId == request.OrderId).Select(x => new SharedUserTrade( - ExchangeSymbolCache.ParseSymbol(_topicId, x.Symbol), + return HttpResult.Ok(orders, orders.Data.Where(x => x.OrderId == request.OrderId).Select(x => new SharedUserTrade( + ExchangeSymbolCache.ParseSymbol(_topicId, EnvironmentName, null, x.Symbol), x.Symbol, x.OrderId.ToString(), x.TradeId, @@ -639,25 +628,25 @@ async Task> IFuturesOrderRestClient.GetFutu }).ToArray()); } - GetUserTradesOptions IFuturesOrderRestClient.GetFuturesUserTradesOptions { get; } = new GetUserTradesOptions(false, true, true, 200); - async Task> IFuturesOrderRestClient.GetFuturesUserTradesAsync(GetUserTradesRequest request, PageRequest? pageRequest, CancellationToken ct) + GetFuturesUserTradesOptions IFuturesOrderRestClient.GetFuturesUserTradesOptions { get; } = new GetFuturesUserTradesOptions(_exchangeName, false, true, true, 200); + async Task> IFuturesOrderRestClient.GetFuturesUserTradesAsync(GetUserTradesRequest request, PageRequest? pageRequest, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetFuturesUserTradesOptions.ValidateRequest(Exchange, request, request.Symbol!.TradingMode, SupportedTradingModes); + var validationError = SharedClient.GetFuturesUserTradesOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var direction = DataDirection.Descending; var limit = request.Limit ?? 200; var pageParams = Pagination.GetPaginationParameters(direction, limit, request.StartTime ?? DateTime.UtcNow.AddDays(-7), request.EndTime ?? DateTime.UtcNow, pageRequest, maxPeriod: TimeSpan.FromDays(90)); // Get data - var result = await Trading.GetUserTradesAsync(request.Symbol.GetSymbol(FormatSymbol), + var result = await Trading.GetUserTradesAsync(request.Symbol!.GetSymbol(FormatSymbol), startTime: pageParams.StartTime, endTime: pageParams.EndTime, ct: ct ).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult(Exchange, null, default); + if (!result.Success) + return HttpResult.Fail(result); var nextPageRequest = Pagination.GetNextPageRequest( () => Pagination.NextPageFromTime(pageParams, result.Data.Min(x => x.CreateTime)), @@ -668,13 +657,10 @@ async Task> IFuturesOrderRestClient.GetFutu pageParams, maxPeriod: TimeSpan.FromDays(90)); - return result.AsExchangeResult( - Exchange, - request.Symbol.TradingMode, - ExchangeHelpers.ApplyFilter(result.Data, x => x.CreateTime, request.StartTime, request.EndTime, direction) + return HttpResult.Ok(result, ExchangeHelpers.ApplyFilter(result.Data, x => x.CreateTime, request.StartTime, request.EndTime, direction) .Select(x => new SharedUserTrade( - ExchangeSymbolCache.ParseSymbol(_topicId, x.Symbol), + ExchangeSymbolCache.ParseSymbol(_topicId, EnvironmentName, null, x.Symbol), x.Symbol, x.OrderId.ToString(), x.TradeId.ToString(), @@ -691,32 +677,32 @@ async Task> IFuturesOrderRestClient.GetFutu .ToArray(), nextPageRequest); } - EndpointOptions IFuturesOrderRestClient.CancelFuturesOrderOptions { get; } = new EndpointOptions(true); - async Task> IFuturesOrderRestClient.CancelFuturesOrderAsync(CancelOrderRequest request, CancellationToken ct) + CancelFuturesOrderOptions IFuturesOrderRestClient.CancelFuturesOrderOptions { get; } = new CancelFuturesOrderOptions(_exchangeName, true); + async Task> IFuturesOrderRestClient.CancelFuturesOrderAsync(CancelOrderRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).CancelFuturesOrderOptions.ValidateRequest(Exchange, request, request.Symbol!.TradingMode, SupportedTradingModes); + var validationError = SharedClient.CancelFuturesOrderOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var order = await Trading.CancelOrderAsync(request.Symbol!.GetSymbol(FormatSymbol), request.OrderId, ct: ct).ConfigureAwait(false); - if (!order) - return order.AsExchangeResult(Exchange, null, default); + if (!order.Success) + return HttpResult.Fail(order); - return order.AsExchangeResult(Exchange, request.Symbol!.TradingMode, new SharedId(request.OrderId)); + return HttpResult.Ok(order, new SharedId(request.OrderId)); } - EndpointOptions IFuturesOrderRestClient.GetPositionsOptions { get; } = new EndpointOptions(true); - async Task> IFuturesOrderRestClient.GetPositionsAsync(GetPositionsRequest request, CancellationToken ct) + GetPositionsOptions IFuturesOrderRestClient.GetPositionsOptions { get; } = new GetPositionsOptions(_exchangeName, true); + async Task> IFuturesOrderRestClient.GetPositionsAsync(GetPositionsRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).GetPositionsOptions.ValidateRequest(Exchange, request, request.Symbol?.TradingMode ?? request.TradingMode, SupportedTradingModes); + var validationError = SharedClient.GetPositionsOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var result = await Trading.GetPositionsAsync(symbol: request.Symbol?.GetSymbol(FormatSymbol), ct: ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult(Exchange, null, default); + if (!result.Success) + return HttpResult.Fail(result); - return result.AsExchangeResult(Exchange, request.Symbol == null ? SupportedTradingModes : new[] { request.Symbol!.TradingMode }, result.Data.Select(x => new SharedPosition(ExchangeSymbolCache.ParseSymbol(_topicId, x.Symbol), x.Symbol, x.CurrentQuantity ?? 0, x.Timestamp) + return HttpResult.Ok(result, result.Data.Select(x => new SharedPosition(ExchangeSymbolCache.ParseSymbol(_topicId, EnvironmentName, null, x.Symbol), x.Symbol, x.CurrentQuantity ?? 0, x.Timestamp) { UnrealizedPnl = x.UnrealizedPnl, AverageOpenPrice = x.OpenAveragePrice, @@ -726,18 +712,18 @@ async Task> IFuturesOrderRestClient.GetPosit }).ToArray()); } - EndpointOptions IFuturesOrderRestClient.ClosePositionOptions { get; } = new EndpointOptions(true) + ClosePositionOptions IFuturesOrderRestClient.ClosePositionOptions { get; } = new ClosePositionOptions(_exchangeName, true) { RequiredOptionalParameters = new List { new ParameterDescription(nameof(ClosePositionRequest.Quantity), typeof(decimal), "Quantity of position to close", 1m) } }; - async Task> IFuturesOrderRestClient.ClosePositionAsync(ClosePositionRequest request, CancellationToken ct) + async Task> IFuturesOrderRestClient.ClosePositionAsync(ClosePositionRequest request, CancellationToken ct) { - var validationError = ((IFuturesOrderRestClient)this).ClosePositionOptions.ValidateRequest(Exchange, request, request.Symbol!.TradingMode, SupportedTradingModes); + var validationError = SharedClient.ClosePositionOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var symbol = request.Symbol!.GetSymbol(FormatSymbol); var result = await Trading.PlaceOrderAsync( @@ -746,10 +732,10 @@ async Task> IFuturesOrderRestClient.ClosePositionAsy FuturesOrderType.Market, (int)request.Quantity!.Value, ct: ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult(Exchange, null, default); + if (!result.Success) + return HttpResult.Fail(result); - return result.AsExchangeResult(Exchange, request.Symbol!.TradingMode, new SharedId(result.Data.OrderId.ToString())); + return HttpResult.Ok(result, new SharedId(result.Data.OrderId.ToString())); } private FuturesSide GetFuturesSide(PlaceFuturesOrderRequest request) @@ -802,35 +788,35 @@ private SharedOrderType ParseOrderType(FuturesOrderType type) #endregion #region Fee Client - EndpointOptions IFeeRestClient.GetFeeOptions { get; } = new EndpointOptions(true); + GetFeeOptions IFeeRestClient.GetFeeOptions { get; } = new GetFeeOptions(_exchangeName, true); - async Task> IFeeRestClient.GetFeesAsync(GetFeeRequest request, CancellationToken ct) + async Task> IFeeRestClient.GetFeesAsync(GetFeeRequest request, CancellationToken ct) { - var validationError = ((IFeeRestClient)this).GetFeeOptions.ValidateRequest(Exchange, request, request.Symbol!.TradingMode, SupportedTradingModes); + var validationError = SharedClient.GetFeeOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); // Get data var result = await Account.GetSymbolTradeFeeAsync(request.Symbol!.GetSymbol(FormatSymbol), ct: ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult(Exchange, null, default); + if (!result.Success) + return HttpResult.Fail(result); // Return - return result.AsExchangeResult(Exchange, SupportedTradingModes, new SharedFee(result.Data.MakerFeeRateA, result.Data.TakerFeeRateA)); + return HttpResult.Ok(result, new SharedFee(result.Data.MakerFeeRateA, result.Data.TakerFeeRateA)); } #endregion #region Trigger Order Client - PlaceFuturesTriggerOrderOptions IFuturesTriggerOrderRestClient.PlaceFuturesTriggerOrderOptions { get; } = new PlaceFuturesTriggerOrderOptions(false) + PlaceFuturesTriggerOrderOptions IFuturesTriggerOrderRestClient.PlaceFuturesTriggerOrderOptions { get; } = new PlaceFuturesTriggerOrderOptions(_exchangeName, false) { }; - async Task> IFuturesTriggerOrderRestClient.PlaceFuturesTriggerOrderAsync(PlaceFuturesTriggerOrderRequest request, CancellationToken ct) + async Task> IFuturesTriggerOrderRestClient.PlaceFuturesTriggerOrderAsync(PlaceFuturesTriggerOrderRequest request, CancellationToken ct) { var side = GetFuturesSide(request); - var validationError = ((IFuturesTriggerOrderRestClient)this).PlaceFuturesTriggerOrderOptions.ValidateRequest(Exchange, request, request.Symbol!.TradingMode, SupportedTradingModes, (side == FuturesSide.BuyCloseShort || side == FuturesSide.BuyOpenLong) ? SharedOrderSide.Buy : SharedOrderSide.Sell, ((IFuturesOrderRestClient)this).FuturesSupportedOrderQuantity); + var validationError = SharedClient.PlaceFuturesTriggerOrderOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var result = await Trading.PlaceTriggerOrderAsync( request.Symbol!.GetSymbol(FormatSymbol), @@ -844,36 +830,36 @@ async Task> IFuturesTriggerOrderRestClient.PlaceFutu request.TriggerPriceType == null || request.TriggerPriceType == SharedTriggerPriceType.LastPrice ? TriggerPriceType.LastPrice: TriggerPriceType.FairPrice, orderPrice: request.OrderPrice, ct: ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult(Exchange, null, default); + if (!result.Success) + return HttpResult.Fail(result); // Return - return result.AsExchangeResult(Exchange, SupportedTradingModes, new SharedId(result.Data.OrderId.ToString())); + return HttpResult.Ok(result, new SharedId(result.Data.OrderId.ToString())); } - EndpointOptions IFuturesTriggerOrderRestClient.GetFuturesTriggerOrderOptions { get; } = new EndpointOptions(true) + GetFuturesTriggerOrderOptions IFuturesTriggerOrderRestClient.GetFuturesTriggerOrderOptions { get; } = new GetFuturesTriggerOrderOptions(_exchangeName, true) { RequestNotes = "Only pending trigger orders can be requested, executed trigger orders are not available in the API" }; - async Task> IFuturesTriggerOrderRestClient.GetFuturesTriggerOrderAsync(GetOrderRequest request, CancellationToken ct) + async Task> IFuturesTriggerOrderRestClient.GetFuturesTriggerOrderAsync(GetOrderRequest request, CancellationToken ct) { - var validationError = ((IFuturesTriggerOrderRestClient)this).GetFuturesTriggerOrderOptions.ValidateRequest(Exchange, request, request.Symbol!.TradingMode, SupportedTradingModes); + var validationError = SharedClient.GetFuturesTriggerOrderOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var orders = await Trading.GetTriggerOrdersAsync( request.Symbol!.GetSymbol(FormatSymbol), planType: TriggerPlanType.Plan, ct: ct).ConfigureAwait(false); - if (!orders) - return orders.AsExchangeResult(Exchange, null, default); + if (!orders.Success) + return HttpResult.Fail(orders); var order = orders.Data.SingleOrDefault(x => x.OrderId == request.OrderId); if (order == null) - return orders.AsExchangeError(Exchange, new ServerError(new ErrorInfo(ErrorType.UnknownOrder, "Order not found"))); + return HttpResult.Fail(Exchange, new ServerError(new ErrorInfo(ErrorType.UnknownOrder, "Order not found"))); - return orders.AsExchangeResult(Exchange, SupportedTradingModes, new SharedFuturesTriggerOrder( - ExchangeSymbolCache.ParseSymbol(_topicId, order.Symbol), + return HttpResult.Ok(orders, new SharedFuturesTriggerOrder( + ExchangeSymbolCache.ParseSymbol(_topicId, EnvironmentName, null, order.Symbol), order.Symbol, order.OrderId.ToString(), order.OrderPrice > 0 ? SharedOrderType.Limit : SharedOrderType.Market, @@ -891,21 +877,21 @@ async Task> IFuturesTriggerOrderRes }); } - EndpointOptions IFuturesTriggerOrderRestClient.CancelFuturesTriggerOrderOptions { get; } = new EndpointOptions(true); - async Task> IFuturesTriggerOrderRestClient.CancelFuturesTriggerOrderAsync(CancelOrderRequest request, CancellationToken ct) + CancelFuturesTriggerOrderOptions IFuturesTriggerOrderRestClient.CancelFuturesTriggerOrderOptions { get; } = new CancelFuturesTriggerOrderOptions(_exchangeName, true); + async Task> IFuturesTriggerOrderRestClient.CancelFuturesTriggerOrderAsync(CancelOrderRequest request, CancellationToken ct) { - var validationError = ((IFuturesTriggerOrderRestClient)this).CancelFuturesTriggerOrderOptions.ValidateRequest(Exchange, request, request.Symbol!.TradingMode, SupportedTradingModes); + var validationError = SharedClient.CancelFuturesTriggerOrderOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var order = await Trading.CancelTriggerOrderAsync( request.Symbol!.GetSymbol(FormatSymbol), request.OrderId, ct: ct).ConfigureAwait(false); - if (!order) - return order.AsExchangeResult(Exchange, null, default); + if (!order.Success) + return HttpResult.Fail(order); - return order.AsExchangeResult(Exchange, SupportedTradingModes, new SharedId(request.OrderId)); + return HttpResult.Ok(order, new SharedId(request.OrderId)); } private FuturesSide GetFuturesSide(PlaceFuturesTriggerOrderRequest request) @@ -924,7 +910,7 @@ private FuturesSide GetFuturesSide(PlaceFuturesTriggerOrderRequest request) #endregion #region Tp/SL Client - EndpointOptions IFuturesTpSlRestClient.SetFuturesTpSlOptions { get; } = new EndpointOptions(true) + SetFuturesTpSlOptions IFuturesTpSlRestClient.SetFuturesTpSlOptions { get; } = new SetFuturesTpSlOptions(_exchangeName, true) { RequiredOptionalParameters = new List { @@ -932,11 +918,11 @@ private FuturesSide GetFuturesSide(PlaceFuturesTriggerOrderRequest request) } }; - async Task> IFuturesTpSlRestClient.SetFuturesTpSlAsync(SetTpSlRequest request, CancellationToken ct) + async Task> IFuturesTpSlRestClient.SetFuturesTpSlAsync(SetTpSlRequest request, CancellationToken ct) { - var validationError = ((IFuturesTpSlRestClient)this).SetFuturesTpSlOptions.ValidateRequest(Exchange, request, request.Symbol!.TradingMode, SupportedTradingModes); + var validationError = SharedClient.SetFuturesTpSlOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var result = await Trading.PlaceTpSlOrderAsync( request.Symbol!.GetSymbol(FormatSymbol), @@ -949,14 +935,14 @@ async Task> IFuturesTpSlRestClient.SetFuturesTpSlAsy triggerOrderType: OrderType.Market, ct: ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult(Exchange, null, default); + if (!result.Success) + return HttpResult.Fail(result); // Return - return result.AsExchangeResult(Exchange, SupportedTradingModes, new SharedId(result.Data.OrderId.ToString())); + return HttpResult.Ok(result, new SharedId(result.Data.OrderId.ToString())); } - EndpointOptions IFuturesTpSlRestClient.CancelFuturesTpSlOptions { get; } = new EndpointOptions(true) + CancelFuturesTpSlOptions IFuturesTpSlRestClient.CancelFuturesTpSlOptions { get; } = new CancelFuturesTpSlOptions(_exchangeName, true) { RequiredOptionalParameters = new List { @@ -964,21 +950,21 @@ async Task> IFuturesTpSlRestClient.SetFuturesTpSlAsy } }; - async Task> IFuturesTpSlRestClient.CancelFuturesTpSlAsync(CancelTpSlRequest request, CancellationToken ct) + async Task> IFuturesTpSlRestClient.CancelFuturesTpSlAsync(CancelTpSlRequest request, CancellationToken ct) { - var validationError = ((IFuturesTpSlRestClient)this).CancelFuturesTpSlOptions.ValidateRequest(Exchange, request, request.Symbol!.TradingMode, SupportedTradingModes); + var validationError = SharedClient.CancelFuturesTpSlOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var result = await Trading.CancelTriggerOrderAsync( symbol: request.Symbol!.GetSymbol(FormatSymbol), orderId: request.OrderId!, ct: ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult(Exchange, null, default); + if (!result.Success) + return HttpResult.Fail(result); // Return - return result.AsExchangeResult(Exchange, request.Symbol!.TradingMode, true); + return HttpResult.Ok(result, true); } #endregion @@ -986,32 +972,32 @@ async Task> IFuturesTpSlRestClient.CancelFuturesTpSlAsyn #region Position Mode client SharedPositionModeSelection IPositionModeRestClient.PositionModeSettingType => SharedPositionModeSelection.PerAccount; - GetPositionModeOptions IPositionModeRestClient.GetPositionModeOptions { get; } = new GetPositionModeOptions(); - async Task> IPositionModeRestClient.GetPositionModeAsync(GetPositionModeRequest request, CancellationToken ct) + GetPositionModeOptions IPositionModeRestClient.GetPositionModeOptions { get; } = new GetPositionModeOptions(_exchangeName); + async Task> IPositionModeRestClient.GetPositionModeAsync(GetPositionModeRequest request, CancellationToken ct) { - var validationError = ((IPositionModeRestClient)this).GetPositionModeOptions.ValidateRequest(Exchange, request, request.Symbol?.TradingMode ?? request.TradingMode, SupportedTradingModes); + var validationError = SharedClient.GetPositionModeOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var result = await Account.GetPositionModeAsync(ct: ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult(Exchange, null, default); + if (!result.Success) + return HttpResult.Fail(result); - return result.AsExchangeResult(Exchange, SupportedTradingModes, new SharedPositionModeResult(result.Data.PositionMode == PositionMode.HedgeMode ? SharedPositionMode.HedgeMode : SharedPositionMode.OneWay)); + return HttpResult.Ok(result, new SharedPositionModeResult(result.Data.PositionMode == PositionMode.HedgeMode ? SharedPositionMode.HedgeMode : SharedPositionMode.OneWay)); } - SetPositionModeOptions IPositionModeRestClient.SetPositionModeOptions { get; } = new SetPositionModeOptions(); - async Task> IPositionModeRestClient.SetPositionModeAsync(SetPositionModeRequest request, CancellationToken ct) + SetPositionModeOptions IPositionModeRestClient.SetPositionModeOptions { get; } = new SetPositionModeOptions(_exchangeName); + async Task> IPositionModeRestClient.SetPositionModeAsync(SetPositionModeRequest request, CancellationToken ct) { - var validationError = ((IPositionModeRestClient)this).SetPositionModeOptions.ValidateRequest(Exchange, request, request.Symbol?.TradingMode ?? request.TradingMode, SupportedTradingModes); + var validationError = SharedClient.SetPositionModeOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeWebResult(Exchange, validationError); + return HttpResult.Fail(Exchange, validationError); var result = await Account.SetPositionModeAsync(request.PositionMode == SharedPositionMode.HedgeMode ? PositionMode.HedgeMode : PositionMode.OneWayMode, ct: ct).ConfigureAwait(false); - if (!result) - return result.AsExchangeResult(Exchange, null, default); + if (!result.Success) + return HttpResult.Fail(result); - return result.AsExchangeResult(Exchange, SupportedTradingModes, new SharedPositionModeResult(request.PositionMode)); + return HttpResult.Ok(result, new SharedPositionModeResult(request.PositionMode)); } #endregion diff --git a/BitMart.Net/Clients/UsdFuturesApi/BitMartRestClientUsdFuturesApiSubAccount.cs b/BitMart.Net/Clients/UsdFuturesApi/BitMartRestClientUsdFuturesApiSubAccount.cs index 6e0a728..f2f609d 100644 --- a/BitMart.Net/Clients/UsdFuturesApi/BitMartRestClientUsdFuturesApiSubAccount.cs +++ b/BitMart.Net/Clients/UsdFuturesApi/BitMartRestClientUsdFuturesApiSubAccount.cs @@ -23,14 +23,14 @@ internal BitMartRestClientUsdFuturesApiSubAccount(BitMartRestClientUsdFuturesApi #region Transfer Sub To Main For Main /// - public async Task TransferSubToMainForMainAsync(string asset, decimal quantity, string subAccount, string clientOrderId, CancellationToken ct = default) + public async Task TransferSubToMainForMainAsync(string asset, decimal quantity, string subAccount, string clientOrderId, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("currency", asset); - parameters.AddString("amount", quantity); + parameters.Add("amount", quantity); parameters.Add("subAccount", subAccount); parameters.Add("requestNo", clientOrderId); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/account/contract/sub-account/main/v1/sub-to-main", BitMartExchange.RateLimiter.BitMart, 1, true, + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/account/contract/sub-account/main/v1/sub-to-main", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(8, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; @@ -41,14 +41,14 @@ public async Task TransferSubToMainForMainAsync(string asset, dec #region Transfer Main To Sub For Main /// - public async Task TransferMainToSubForMainAsync(string asset, decimal quantity, string subAccount, string clientOrderId, CancellationToken ct = default) + public async Task TransferMainToSubForMainAsync(string asset, decimal quantity, string subAccount, string clientOrderId, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("currency", asset); - parameters.AddString("amount", quantity); + parameters.Add("amount", quantity); parameters.Add("subAccount", subAccount); parameters.Add("requestNo", clientOrderId); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/account/contract/sub-account/main/v1/main-to-sub", BitMartExchange.RateLimiter.BitMart, 1, true, + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/account/contract/sub-account/main/v1/main-to-sub", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(8, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; @@ -59,13 +59,13 @@ public async Task TransferMainToSubForMainAsync(string asset, dec #region Transfer Sub To Main For Sub /// - public async Task TransferSubToMainForSubAsync(string asset, decimal quantity, string clientOrderId, CancellationToken ct = default) + public async Task TransferSubToMainForSubAsync(string asset, decimal quantity, string clientOrderId, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("currency", asset); - parameters.AddString("amount", quantity); + parameters.Add("amount", quantity); parameters.Add("requestNo", clientOrderId); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/account/contract/sub-account/sub/v1/sub-to-main", BitMartExchange.RateLimiter.BitMart, 1, true, + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/account/contract/sub-account/sub/v1/sub-to-main", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(8, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; @@ -76,15 +76,18 @@ public async Task TransferSubToMainForSubAsync(string asset, deci #region Get Sub Acccount Balance /// - public async Task> GetSubAcccountBalanceAsync(string subAccount, string? asset = null, CancellationToken ct = default) + public async Task> GetSubAccountBalanceAsync(string subAccount, string? asset = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("subAccount", subAccount); - parameters.AddOptional("currency", asset); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/account/contract/sub-account/main/v1/wallet", BitMartExchange.RateLimiter.BitMart, 1, true, + parameters.Add("currency", asset); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/account/contract/sub-account/main/v1/wallet", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(12, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); - return result.As(result.Data?.Wallet); + if (!result.Success) + return HttpResult.Fail(result); + + return HttpResult.Ok(result, result.Data.Wallet); } #endregion @@ -92,12 +95,12 @@ public async Task> GetSubAcccountBalan #region Get Sub Account Transfer History /// - public async Task> GetSubAccountTransferHistoryForMainAsync(string subAccount, int limit, CancellationToken ct = default) + public async Task> GetSubAccountTransferHistoryForMainAsync(string subAccount, int limit, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("subAccount", subAccount); parameters.Add("limit", limit); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/account/contract/sub-account/main/v1/transfer-list", BitMartExchange.RateLimiter.BitMart, 1, true, + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/account/contract/sub-account/main/v1/transfer-list", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(8, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; @@ -108,11 +111,11 @@ public async Task> GetSubAccountTransferHist #region Get Sub Account Transfer History /// - public async Task> GetSubAccountTransferHistoryAsync(int limit, CancellationToken ct = default) + public async Task> GetSubAccountTransferHistoryAsync(int limit, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("limit", limit); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/account/contract/sub-account/v1/transfer-history", BitMartExchange.RateLimiter.BitMart, 1, true, + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/account/contract/sub-account/v1/transfer-history", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(8, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; diff --git a/BitMart.Net/Clients/UsdFuturesApi/BitMartRestClientUsdFuturesApiTrading.cs b/BitMart.Net/Clients/UsdFuturesApi/BitMartRestClientUsdFuturesApiTrading.cs index cdd12a2..18c9768 100644 --- a/BitMart.Net/Clients/UsdFuturesApi/BitMartRestClientUsdFuturesApiTrading.cs +++ b/BitMart.Net/Clients/UsdFuturesApi/BitMartRestClientUsdFuturesApiTrading.cs @@ -29,12 +29,12 @@ internal BitMartRestClientUsdFuturesApiTrading(ILogger logger, BitMartRestClient #region Get Order /// - public async Task> GetOrderAsync(string symbol, string orderId, CancellationToken ct = default) + public async Task> GetOrderAsync(string symbol, string orderId, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("symbol", symbol); parameters.Add("order_id", orderId); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/contract/private/order", BitMartExchange.RateLimiter.BitMart, 1, true, + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/contract/private/order", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(50, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; @@ -45,18 +45,21 @@ public async Task> GetOrderAsync(string symbo #region Get Closed Orders /// - public async Task> GetClosedOrdersAsync(string symbol, string? orderId = null, string? clientOrderId = null, DateTime? startTime = null, DateTime? endTime = null, CancellationToken ct = default) + public async Task> GetClosedOrdersAsync(string symbol, string? orderId = null, string? clientOrderId = null, DateTime? startTime = null, DateTime? endTime = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("symbol", symbol); - parameters.AddOptional("order_id", orderId); - parameters.AddOptional("client_order_id", clientOrderId); - parameters.AddOptionalSeconds("start_time", startTime); - parameters.AddOptionalSeconds("end_time", endTime); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/contract/private/order-history", BitMartExchange.RateLimiter.BitMart, 1, true, + parameters.Add("order_id", orderId); + parameters.Add("client_order_id", clientOrderId); + parameters.Add("start_time", startTime, DateTimeSerialization.SecondsNumber); + parameters.Add("end_time", endTime, DateTimeSerialization.SecondsNumber); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/contract/private/order-history", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(6, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); - return result.As(result.Data ?? Array.Empty()); + if (!result.Success) + return HttpResult.Fail(result); + + return HttpResult.Ok(result, result.Data ?? Array.Empty()); } #endregion @@ -64,17 +67,20 @@ public async Task> GetClosedOrdersAsync(str #region Get Open Orders /// - public async Task> GetOpenOrdersAsync(string? symbol = null, FuturesOrderType? orderType = null, OrderStatusQuery? status = null, int? limit = null, CancellationToken ct = default) + public async Task> GetOpenOrdersAsync(string? symbol = null, FuturesOrderType? orderType = null, OrderStatusQuery? status = null, int? limit = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); - parameters.AddOptional("symbol", symbol); - parameters.AddOptionalEnum("type", orderType); - parameters.AddOptionalEnum("order_state", status); - parameters.AddOptional("limit", limit); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/contract/private/get-open-orders", BitMartExchange.RateLimiter.BitMart, 1, true, + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); + parameters.Add("symbol", symbol); + parameters.Add("type", orderType); + parameters.Add("order_state", status); + parameters.Add("limit", limit); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/contract/private/get-open-orders", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(50, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); - return result.As(result.Data ?? Array.Empty()); + if (!result.Success) + return HttpResult.Fail(result); + + return HttpResult.Ok(result, result.Data ?? Array.Empty()); } #endregion @@ -82,14 +88,14 @@ public async Task> GetOpenOrdersAsync(strin #region Get Trigger Orders /// - public async Task> GetTriggerOrdersAsync(string? symbol = null, OrderType? type = null, int? limit = null, TriggerPlanType? planType = null, CancellationToken ct = default) + public async Task> GetTriggerOrdersAsync(string? symbol = null, OrderType? type = null, int? limit = null, TriggerPlanType? planType = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); - parameters.AddOptional("symbol", symbol); - parameters.AddOptionalEnum("type", type); - parameters.AddOptional("limit", limit); - parameters.AddOptionalEnum("plan_type", planType); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/contract/private/current-plan-order", BitMartExchange.RateLimiter.BitMart, 1, true, + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); + parameters.Add("symbol", symbol); + parameters.Add("type", type); + parameters.Add("limit", limit); + parameters.Add("plan_type", planType); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/contract/private/current-plan-order", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(50, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; @@ -100,11 +106,11 @@ public async Task> GetTriggerOrdersAsync(st #region Get Positions /// - public async Task> GetPositionsAsync(string? symbol = null, CancellationToken ct = default) + public async Task> GetPositionsAsync(string? symbol = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); - parameters.AddOptional("symbol", symbol); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/contract/private/position", BitMartExchange.RateLimiter.BitMart, 1, true, + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); + parameters.Add("symbol", symbol); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/contract/private/position", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(6, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; @@ -115,11 +121,11 @@ public async Task> GetPositionsAsync(string? sy #region Get Position Risk /// - public async Task> GetPositionRiskAsync(string? symbol = null, CancellationToken ct = default) + public async Task> GetPositionRiskAsync(string? symbol = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); - parameters.AddOptional("symbol", symbol); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/contract/private/position-risk", BitMartExchange.RateLimiter.BitMart, 1, true, + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); + parameters.Add("symbol", symbol); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/contract/private/position-risk", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(24, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; @@ -130,7 +136,7 @@ public async Task> GetPositionRiskAsync(str #region Get User Trades /// - public async Task> GetUserTradesAsync( + public async Task> GetUserTradesAsync( string? symbol = null, DateTime? startTime = null, DateTime? endTime = null, @@ -138,13 +144,13 @@ public async Task> GetUserTradesAsync( string? clientOrderId = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); - parameters.AddOptional("symbol", symbol); - parameters.AddOptionalSeconds("start_time", startTime); - parameters.AddOptionalSeconds("end_time", endTime); - parameters.AddOptional("order_id", orderId); - parameters.AddOptional("client_order_id", clientOrderId); - var request = _definitions.GetOrCreate(HttpMethod.Get, "/contract/private/trades", BitMartExchange.RateLimiter.BitMart, 1, true, + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); + parameters.Add("symbol", symbol); + parameters.Add("start_time", startTime, DateTimeSerialization.SecondsNumber); + parameters.Add("end_time", endTime, DateTimeSerialization.SecondsNumber); + parameters.Add("order_id", orderId); + parameters.Add("client_order_id", clientOrderId); + var request = _definitions.GetOrCreate(HttpMethod.Get, _baseClient.BaseAddress, "/contract/private/trades", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(6, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; @@ -155,24 +161,24 @@ public async Task> GetUserTradesAsync( #region Place Order /// - public async Task> PlaceOrderAsync(string symbol, FuturesSide side, FuturesOrderType type, int quantity, decimal? price = null, string? clientOrderId = null, decimal? leverage = null, MarginType? marginType = null, OrderMode? orderMode = null, TriggerPriceType? presetTakeProfitPriceType = null, TriggerPriceType? presetStopLossPriceType = null, decimal? presetTakeProfitPrice = null, decimal? presetStopLossPrice = null, StpMode? stpMode = null, CancellationToken ct = default) + public async Task> PlaceOrderAsync(string symbol, FuturesSide side, FuturesOrderType type, int quantity, decimal? price = null, string? clientOrderId = null, decimal? leverage = null, MarginType? marginType = null, OrderMode? orderMode = null, TriggerPriceType? presetTakeProfitPriceType = null, TriggerPriceType? presetStopLossPriceType = null, decimal? presetTakeProfitPrice = null, decimal? presetStopLossPrice = null, StpMode? stpMode = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("symbol", symbol); - parameters.AddEnumAsInt("side", side); - parameters.AddEnum("type", type); + parameters.Add("side", side, EnumSerialization.Number); + parameters.Add("type", type); parameters.Add("size", quantity); - parameters.AddOptionalString("price", price); - parameters.AddOptional("client_order_id", clientOrderId); - parameters.AddOptionalString("leverage", leverage); - parameters.AddOptionalEnum("open_type", marginType); - parameters.AddOptionalEnumAsInt("mode", orderMode); - parameters.AddOptionalEnum("preset_take_profit_price_type", presetTakeProfitPriceType); - parameters.AddOptionalEnum("preset_stop_loss_price_type", presetStopLossPriceType); - parameters.AddOptionalString("preset_take_profit_price", presetTakeProfitPrice); - parameters.AddOptionalString("preset_stop_loss_price", presetStopLossPrice); - parameters.AddOptionalEnum("stp_mode", stpMode); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/contract/private/submit-order", BitMartExchange.RateLimiter.BitMart, 1, true, + parameters.Add("price", price); + parameters.Add("client_order_id", clientOrderId); + parameters.Add("leverage", leverage); + parameters.Add("open_type", marginType); + parameters.Add("mode", orderMode, EnumSerialization.Number); + parameters.Add("preset_take_profit_price_type", presetTakeProfitPriceType); + parameters.Add("preset_stop_loss_price_type", presetStopLossPriceType); + parameters.Add("preset_take_profit_price", presetTakeProfitPrice); + parameters.Add("preset_stop_loss_price", presetStopLossPrice); + parameters.Add("stp_mode", stpMode); + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/contract/private/submit-order", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(24, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct, additionalHeaders:new Dictionary { @@ -186,7 +192,7 @@ public async Task> PlaceOrderAsync(st #region Place Trailing Order /// - public async Task> PlaceTrailingOrderAsync( + public async Task> PlaceTrailingOrderAsync( string symbol, FuturesSide side, int quantity, @@ -197,16 +203,16 @@ public async Task> PlaceTrailingOrderAsync( TriggerPriceType triggerPriceType, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("symbol", symbol); - parameters.AddEnumAsInt("side", side); - parameters.AddOptionalString("leverage", leverage); - parameters.AddEnum("open_type", marginType); + parameters.Add("side", side, EnumSerialization.Number); + parameters.Add("leverage", leverage); + parameters.Add("open_type", marginType); parameters.Add("size", quantity); - parameters.AddOptionalString("activation_price", triggerPrice); - parameters.AddOptionalString("callback_rate", callbackRate); - parameters.AddEnum("activation_price_type", triggerPriceType); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/contract/private/submit-trail-order", BitMartExchange.RateLimiter.BitMart, 1, true, + parameters.Add("activation_price", triggerPrice); + parameters.Add("callback_rate", callbackRate); + parameters.Add("activation_price_type", triggerPriceType); + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/contract/private/submit-trail-order", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(24, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct, additionalHeaders: new Dictionary { @@ -220,12 +226,12 @@ public async Task> PlaceTrailingOrderAsync( #region Cancel Trailing Order /// - public async Task CancelTrailingOrderAsync(string symbol, string orderId, CancellationToken ct = default) + public async Task CancelTrailingOrderAsync(string symbol, string orderId, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("symbol", symbol); parameters.Add("order_id", orderId); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/contract/private/cancel-trail-order", BitMartExchange.RateLimiter.BitMart, 1, true, + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/contract/private/cancel-trail-order", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(40, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; @@ -236,13 +242,13 @@ public async Task CancelTrailingOrderAsync(string symbol, string #region Cancel Order /// - public async Task CancelOrderAsync(string symbol, string? orderId = null, string? clientOrderId = null, CancellationToken ct = default) + public async Task CancelOrderAsync(string symbol, string? orderId = null, string? clientOrderId = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("symbol", symbol); - parameters.AddOptional("order_id", orderId); - parameters.AddOptional("client_order_id", clientOrderId); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/contract/private/cancel-order", BitMartExchange.RateLimiter.BitMart, 1, true, + parameters.Add("order_id", orderId); + parameters.Add("client_order_id", clientOrderId); + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/contract/private/cancel-order", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(40, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; @@ -253,11 +259,11 @@ public async Task CancelOrderAsync(string symbol, string? orderId #region Cancel Orders /// - public async Task CancelOrdersAsync(string symbol, CancellationToken ct = default) + public async Task CancelOrdersAsync(string symbol, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("symbol", symbol); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/contract/private/cancel-orders", BitMartExchange.RateLimiter.BitMart, 1, true, + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/contract/private/cancel-orders", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(2, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; @@ -268,26 +274,26 @@ public async Task CancelOrdersAsync(string symbol, CancellationTo #region Place Trigger Order /// - public async Task> PlaceTriggerOrderAsync(string symbol, OrderType orderType, FuturesSide side, int quantity, decimal leverage, MarginType marginType, decimal triggerPrice, PriceDirection priceDirection, TriggerPriceType triggerPriceType, OrderMode? orderMode = null, decimal? orderPrice = null, PlanCategory? planCategory = null, decimal? takeProfitPrice = null, decimal? stopLossPrice = null, TriggerPriceType? takeProfitPriceType = null, TriggerPriceType? stopLossPriceType = null, CancellationToken ct = default) + public async Task> PlaceTriggerOrderAsync(string symbol, OrderType orderType, FuturesSide side, int quantity, decimal leverage, MarginType marginType, decimal triggerPrice, PriceDirection priceDirection, TriggerPriceType triggerPriceType, OrderMode? orderMode = null, decimal? orderPrice = null, PlanCategory? planCategory = null, decimal? takeProfitPrice = null, decimal? stopLossPrice = null, TriggerPriceType? takeProfitPriceType = null, TriggerPriceType? stopLossPriceType = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("symbol", symbol); - parameters.AddEnum("type", orderType); - parameters.AddEnumAsInt("side", side); + parameters.Add("type", orderType); + parameters.Add("side", side, EnumSerialization.Number); parameters.Add("size", quantity); - parameters.AddString("leverage", leverage); - parameters.AddEnum("open_type", marginType); - parameters.AddString("trigger_price", triggerPrice); + parameters.Add("leverage", leverage); + parameters.Add("open_type", marginType); + parameters.Add("trigger_price", triggerPrice); parameters.Add("price_way", priceDirection == PriceDirection.ShortDirection ? 2 : 1); - parameters.AddEnumAsInt("price_type", triggerPriceType); - parameters.AddOptionalEnumAsInt("mode", orderMode); - parameters.AddOptionalString("executive_price", orderPrice); - parameters.AddOptionalEnumAsInt("plan_category", planCategory); - parameters.AddOptionalString("preset_take_profit_price", takeProfitPrice); - parameters.AddOptionalString("preset_stop_loss_price", stopLossPrice); - parameters.AddOptionalEnumAsInt("preset_take_profit_price_type", takeProfitPriceType); - parameters.AddOptionalEnumAsInt("preset_stop_loss_price_type", stopLossPriceType); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/contract/private/submit-plan-order", BitMartExchange.RateLimiter.BitMart, 1, true, + parameters.Add("price_type", triggerPriceType, EnumSerialization.Number); + parameters.Add("mode", orderMode, EnumSerialization.Number); + parameters.Add("executive_price", orderPrice); + parameters.Add("plan_category", planCategory, EnumSerialization.Number); + parameters.Add("preset_take_profit_price", takeProfitPrice); + parameters.Add("preset_stop_loss_price", stopLossPrice); + parameters.Add("preset_take_profit_price_type", takeProfitPriceType, EnumSerialization.Number); + parameters.Add("preset_stop_loss_price_type", stopLossPriceType, EnumSerialization.Number); + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/contract/private/submit-plan-order", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(24, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct, additionalHeaders: new Dictionary { @@ -301,13 +307,13 @@ public async Task> PlaceTriggerOrderAsync(s #region Cancel Trigger Order /// - public async Task CancelTriggerOrderAsync(string symbol, string? orderId = null, string? clientOrderId = null, CancellationToken ct = default) + public async Task CancelTriggerOrderAsync(string symbol, string? orderId = null, string? clientOrderId = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("symbol", symbol); - parameters.AddOptional("order_id", orderId); - parameters.AddOptional("client_order_id", clientOrderId); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/contract/private/cancel-plan-order", BitMartExchange.RateLimiter.BitMart, 1, true, + parameters.Add("order_id", orderId); + parameters.Add("client_order_id", clientOrderId); + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/contract/private/cancel-plan-order", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(40, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; @@ -318,23 +324,23 @@ public async Task CancelTriggerOrderAsync(string symbol, string? #region Place Tp Sl Order /// - public async Task> PlaceTpSlOrderAsync(string symbol, TplSlOrderType tpSlType, FuturesSide orderSide, decimal triggerPrice, TriggerPriceType priceType, PlanCategory planCategory, decimal? executionPrice = null, int? quantity = null, string? clientOrderId = null, OrderType? triggerOrderType = null, CancellationToken ct = default) + public async Task> PlaceTpSlOrderAsync(string symbol, TplSlOrderType tpSlType, FuturesSide orderSide, decimal triggerPrice, TriggerPriceType priceType, PlanCategory planCategory, decimal? executionPrice = null, int? quantity = null, string? clientOrderId = null, OrderType? triggerOrderType = null, CancellationToken ct = default) { if (orderSide != FuturesSide.BuyCloseShort && orderSide != FuturesSide.SellCloseLong) throw new ArgumentException("Order side should be either BuyCloseShort or SellCloseLong"); - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("symbol", symbol); - parameters.AddEnum("type", tpSlType); - parameters.AddEnumAsInt("side", orderSide); - parameters.AddString("trigger_price", triggerPrice); - parameters.AddEnumAsInt("price_type", priceType); - parameters.AddEnumAsInt("plan_category", planCategory); - parameters.AddOptionalString("executive_price", executionPrice); - parameters.AddOptional("size", quantity); - parameters.AddOptional("client_order_id", clientOrderId); - parameters.AddOptionalEnum("category", triggerOrderType); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/contract/private/submit-tp-sl-order", BitMartExchange.RateLimiter.BitMart, 1, true); + parameters.Add("type", tpSlType); + parameters.Add("side", orderSide, EnumSerialization.Number); + parameters.Add("trigger_price", triggerPrice); + parameters.Add("price_type", priceType, EnumSerialization.Number); + parameters.Add("plan_category", planCategory, EnumSerialization.Number); + parameters.Add("executive_price", executionPrice); + parameters.Add("size", quantity); + parameters.Add("client_order_id", clientOrderId); + parameters.Add("category", triggerOrderType); + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/contract/private/submit-tp-sl-order", BitMartExchange.RateLimiter.BitMart, 1, true); var result = await _baseClient.SendAsync(request, parameters, ct, additionalHeaders: new Dictionary { { "X-BM-BROKER-ID", LibraryHelpers.GetClientReference(() => _baseClient.ClientOptions.BrokerId, _baseClient.Exchange) } @@ -347,15 +353,15 @@ public async Task> PlaceTpSlOrderAsync(string symb #region Edit Order /// - public async Task> EditOrderAsync(string symbol, long? orderId = null, string? clientOrderId = null, decimal? price = null, decimal? quantity = null, CancellationToken ct = default) + public async Task> EditOrderAsync(string symbol, long? orderId = null, string? clientOrderId = null, decimal? price = null, decimal? quantity = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("symbol", symbol); - parameters.AddOptional("orderId", orderId); - parameters.AddOptional("client_order_id", clientOrderId); - parameters.AddOptionalString("price", price); - parameters.AddOptionalString("size", quantity); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/contract/private/modify-limit-order", BitMartExchange.RateLimiter.BitMart, 1, true); + parameters.Add("orderId", orderId); + parameters.Add("client_order_id", clientOrderId); + parameters.Add("price", price); + parameters.Add("size", quantity); + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/contract/private/modify-limit-order", BitMartExchange.RateLimiter.BitMart, 1, true); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; } @@ -365,17 +371,17 @@ public async Task> EditOrderAsync(string symbol, l #region Edit Tp Sl Order /// - public async Task> EditTpSlOrderAsync(string symbol, decimal triggerPrice, TriggerPriceType priceType, PlanCategory planCategory, OrderType orderType, string? orderId = null, decimal? executionPrice = null, CancellationToken ct = default) + public async Task> EditTpSlOrderAsync(string symbol, decimal triggerPrice, TriggerPriceType priceType, PlanCategory planCategory, OrderType orderType, string? orderId = null, decimal? executionPrice = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("symbol", symbol); - parameters.AddString("trigger_price", triggerPrice); - parameters.AddEnumAsInt("price_type", priceType); - parameters.AddEnumAsInt("plan_category", planCategory); - parameters.AddEnum("category", orderType); - parameters.AddOptional("orderId", orderId); - parameters.AddOptionalString("executive_price", executionPrice); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/contract/private/modify-tp-sl-order", BitMartExchange.RateLimiter.BitMart, 1, true); + parameters.Add("trigger_price", triggerPrice); + parameters.Add("price_type", priceType, EnumSerialization.Number); + parameters.Add("plan_category", planCategory, EnumSerialization.Number); + parameters.Add("category", orderType); + parameters.Add("orderId", orderId); + parameters.Add("executive_price", executionPrice); + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/contract/private/modify-tp-sl-order", BitMartExchange.RateLimiter.BitMart, 1, true); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; } @@ -385,17 +391,17 @@ public async Task> EditTpSlOrderAsync(string symbo #region Edit Trigger Order /// - public async Task> EditTriggerOrderAsync(string symbol, decimal triggerPrice, TriggerPriceType priceType, OrderType orderType, string? orderId = null, string? clientOrderId = null, decimal? executionPrice = null, CancellationToken ct = default) + public async Task> EditTriggerOrderAsync(string symbol, decimal triggerPrice, TriggerPriceType priceType, OrderType orderType, string? orderId = null, string? clientOrderId = null, decimal? executionPrice = null, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("symbol", symbol); - parameters.AddString("trigger_price", triggerPrice); - parameters.AddEnumAsInt("price_type", priceType); - parameters.AddEnum("type", orderType); - parameters.AddOptional("orderId", orderId); - parameters.AddOptional("client_order_id", clientOrderId); - parameters.AddOptionalString("executive_price", executionPrice); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/contract/private/modify-plan-order", BitMartExchange.RateLimiter.BitMart, 1, true); + parameters.Add("trigger_price", triggerPrice); + parameters.Add("price_type", priceType, EnumSerialization.Number); + parameters.Add("type", orderType); + parameters.Add("orderId", orderId); + parameters.Add("client_order_id", clientOrderId); + parameters.Add("executive_price", executionPrice); + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/contract/private/modify-plan-order", BitMartExchange.RateLimiter.BitMart, 1, true); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; } @@ -405,16 +411,16 @@ public async Task> EditTriggerOrderAsync(string sy #region Edit Preset Trigger Order /// - public async Task> EditPresetTriggerOrderAsync(string symbol, string orderId, TriggerPriceType takeProfitPriceType, TriggerPriceType stopLossPriceType, decimal takeProfitPrice, decimal stopLossPrice, CancellationToken ct = default) + public async Task> EditPresetTriggerOrderAsync(string symbol, string orderId, TriggerPriceType takeProfitPriceType, TriggerPriceType stopLossPriceType, decimal takeProfitPrice, decimal stopLossPrice, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("symbol", symbol); parameters.Add("order_id", orderId); - parameters.AddEnumAsInt("preset_take_profit_price_type", takeProfitPriceType); - parameters.AddEnumAsInt("preset_stop_loss_price_type", stopLossPriceType); - parameters.AddString("preset_take_profit_price", takeProfitPrice); - parameters.AddString("preset_stop_loss_price", stopLossPrice); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/contract/private/modify-preset-plan-order", BitMartExchange.RateLimiter.BitMart, 1, true); + parameters.Add("preset_take_profit_price_type", takeProfitPriceType, EnumSerialization.Number); + parameters.Add("preset_stop_loss_price_type", stopLossPriceType, EnumSerialization.Number); + parameters.Add("preset_take_profit_price", takeProfitPrice); + parameters.Add("preset_stop_loss_price", stopLossPrice); + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/contract/private/modify-preset-plan-order", BitMartExchange.RateLimiter.BitMart, 1, true); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; } @@ -424,12 +430,12 @@ public async Task> EditPresetTriggerOrderAsync(str #region Cancel All After /// - public async Task> CancelAllAfterAsync(string symbol, TimeSpan timespan, CancellationToken ct = default) + public async Task> CancelAllAfterAsync(string symbol, TimeSpan timespan, CancellationToken ct = default) { - var parameters = new ParameterCollection(); + var parameters = new Parameters(BitMartExchange._parameterSerializationSettings); parameters.Add("symbol", symbol); parameters.Add("timeout", (int)timespan.TotalSeconds); - var request = _definitions.GetOrCreate(HttpMethod.Post, "/contract/private/cancel-all-after", BitMartExchange.RateLimiter.BitMart, 1, true, + var request = _definitions.GetOrCreate(HttpMethod.Post, _baseClient.BaseAddress, "/contract/private/cancel-all-after", BitMartExchange.RateLimiter.BitMart, 1, true, new SingleLimitGuard(4, TimeSpan.FromSeconds(2), RateLimitWindowType.Sliding, keySelector: SingleLimitGuard.PerApiKey)); var result = await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); return result; diff --git a/BitMart.Net/Clients/UsdFuturesApi/BitMartSocketClientUsdFuturesApi.cs b/BitMart.Net/Clients/UsdFuturesApi/BitMartSocketClientUsdFuturesApi.cs index b17fb09..fc057e4 100644 --- a/BitMart.Net/Clients/UsdFuturesApi/BitMartSocketClientUsdFuturesApi.cs +++ b/BitMart.Net/Clients/UsdFuturesApi/BitMartSocketClientUsdFuturesApi.cs @@ -38,8 +38,8 @@ internal partial class BitMartSocketClientUsdFuturesApi : SocketApiClient /// ctor /// - internal BitMartSocketClientUsdFuturesApi(ILogger logger, BitMartSocketOptions options) : - base(logger, options.Environment.SocketClientPerpetualFuturesAddress!, options, options.UsdFuturesOptions) + internal BitMartSocketClientUsdFuturesApi(ILoggerFactory? loggerFactory, BitMartSocketOptions options) : + base(loggerFactory, BitMartExchange.Metadata.Id, options.Environment.SocketClientPerpetualFuturesAddress!, options, options.UsdFuturesOptions) { KeepAliveInterval = TimeSpan.Zero; @@ -71,11 +71,11 @@ protected override BitMartAuthenticationProvider CreateAuthenticationProvider(Bi => new BitMartAuthenticationProvider(credentials); - public async Task> SubscribeToTickerUpdatesAsync(string symbol, Action> onMessage, CancellationToken ct = default) + public async Task> SubscribeToTickerUpdatesAsync(string symbol, Action> onMessage, CancellationToken ct = default) => await SubscribeToTickerUpdatesAsync([symbol], onMessage, ct).ConfigureAwait(false); /// - public async Task> SubscribeToTickerUpdatesAsync(IEnumerable symbols, Action> onMessage, CancellationToken ct = default) + public async Task> SubscribeToTickerUpdatesAsync(IEnumerable symbols, Action> onMessage, CancellationToken ct = default) { var handler = new Action>((receiveTime, originalData, data) => { @@ -92,7 +92,7 @@ public async Task> SubscribeToTickerUpdatesAsync( } /// - public async Task> SubscribeToTickerUpdatesAsync(Action> onMessage, CancellationToken ct = default) + public async Task> SubscribeToTickerUpdatesAsync(Action> onMessage, CancellationToken ct = default) { var handler = new Action>((receiveTime, originalData, data) => { @@ -109,11 +109,11 @@ public async Task> SubscribeToTickerUpdatesAsync( } /// - public Task> SubscribeToFundingRateUpdatesAsync(string symbol, Action> onMessage, CancellationToken ct = default) + public Task> SubscribeToFundingRateUpdatesAsync(string symbol, Action> onMessage, CancellationToken ct = default) => SubscribeToFundingRateUpdatesAsync(new[] { symbol }, onMessage, ct); /// - public async Task> SubscribeToFundingRateUpdatesAsync(IEnumerable symbols, Action> onMessage, CancellationToken ct = default) + public async Task> SubscribeToFundingRateUpdatesAsync(IEnumerable symbols, Action> onMessage, CancellationToken ct = default) { var handler = new Action>((receiveTime, originalData, data) => { @@ -133,11 +133,11 @@ public async Task> SubscribeToFundingRateUpdatesA } /// - public Task> SubscribeToTradeUpdatesAsync(string symbol, Action> onMessage, CancellationToken ct = default) + public Task> SubscribeToTradeUpdatesAsync(string symbol, Action> onMessage, CancellationToken ct = default) => SubscribeToTradeUpdatesAsync(new[] { symbol }, onMessage, ct); /// - public async Task> SubscribeToTradeUpdatesAsync(IEnumerable symbols, Action> onMessage, CancellationToken ct = default) + public async Task> SubscribeToTradeUpdatesAsync(IEnumerable symbols, Action> onMessage, CancellationToken ct = default) { var handler = new Action>((receiveTime, originalData, data) => { @@ -155,11 +155,11 @@ public async Task> SubscribeToTradeUpdatesAsync(I } /// - public Task> SubscribeToOrderBookUpdatesAsync(string symbol, int depth, Action> onMessage, CancellationToken ct = default) + public Task> SubscribeToOrderBookUpdatesAsync(string symbol, int depth, Action> onMessage, CancellationToken ct = default) => SubscribeToOrderBookUpdatesAsync(new[] { symbol }, depth, onMessage, ct); /// - public async Task> SubscribeToOrderBookUpdatesAsync(IEnumerable symbols, int depth, Action> onMessage, CancellationToken ct = default) + public async Task> SubscribeToOrderBookUpdatesAsync(IEnumerable symbols, int depth, Action> onMessage, CancellationToken ct = default) { var handler = new Action>((receiveTime, originalData, data) => { @@ -179,11 +179,11 @@ public async Task> SubscribeToOrderBookUpdatesAsy } /// - public Task> SubscribeToOrderBookSnapshotUpdatesAsync(string symbol, int depth, Action> onMessage, CancellationToken ct = default) + public Task> SubscribeToOrderBookSnapshotUpdatesAsync(string symbol, int depth, Action> onMessage, CancellationToken ct = default) => SubscribeToOrderBookSnapshotUpdatesAsync(new[] { symbol }, depth, onMessage, ct); /// - public async Task> SubscribeToOrderBookSnapshotUpdatesAsync(IEnumerable symbols, int depth, Action> onMessage, CancellationToken ct = default) + public async Task> SubscribeToOrderBookSnapshotUpdatesAsync(IEnumerable symbols, int depth, Action> onMessage, CancellationToken ct = default) { var handler = new Action>((receiveTime, originalData, data) => { @@ -203,11 +203,11 @@ public async Task> SubscribeToOrderBookSnapshotUp } /// - public Task> SubscribeToOrderBookIncrementalUpdatesAsync(string symbol, int depth, Action> onMessage, CancellationToken ct = default) + public Task> SubscribeToOrderBookIncrementalUpdatesAsync(string symbol, int depth, Action> onMessage, CancellationToken ct = default) => SubscribeToOrderBookIncrementalUpdatesAsync(new[] { symbol }, depth, onMessage, ct); /// - public async Task> SubscribeToOrderBookIncrementalUpdatesAsync(IEnumerable symbols, int depth, Action> onMessage, CancellationToken ct = default) + public async Task> SubscribeToOrderBookIncrementalUpdatesAsync(IEnumerable symbols, int depth, Action> onMessage, CancellationToken ct = default) { var handler = new Action>((receiveTime, originalData, data) => { @@ -227,11 +227,11 @@ public async Task> SubscribeToOrderBookIncrementa } /// - public Task> SubscribeToBookTickerUpdatesAsync(string symbol, Action> onMessage, CancellationToken ct = default) + public Task> SubscribeToBookTickerUpdatesAsync(string symbol, Action> onMessage, CancellationToken ct = default) => SubscribeToBookTickerUpdatesAsync(new[] { symbol }, onMessage, ct); /// - public async Task> SubscribeToBookTickerUpdatesAsync(IEnumerable symbols, Action> onMessage, CancellationToken ct = default) + public async Task> SubscribeToBookTickerUpdatesAsync(IEnumerable symbols, Action> onMessage, CancellationToken ct = default) { var handler = new Action>((receiveTime, originalData, data) => { @@ -250,11 +250,11 @@ public async Task> SubscribeToBookTickerUpdatesAs } /// - public Task> SubscribeToKlineUpdatesAsync(string symbol, FuturesStreamKlineInterval interval, Action> onMessage, CancellationToken ct = default) + public Task> SubscribeToKlineUpdatesAsync(string symbol, FuturesStreamKlineInterval interval, Action> onMessage, CancellationToken ct = default) => SubscribeToKlineUpdatesAsync(new[] { symbol }, interval, onMessage, ct); /// - public async Task> SubscribeToKlineUpdatesAsync(IEnumerable symbols, FuturesStreamKlineInterval interval, Action> onMessage, CancellationToken ct = default) + public async Task> SubscribeToKlineUpdatesAsync(IEnumerable symbols, FuturesStreamKlineInterval interval, Action> onMessage, CancellationToken ct = default) { var intervalStr = EnumConverter.GetString(interval); var handler = new Action>((receiveTime, originalData, data) => @@ -271,11 +271,11 @@ public async Task> SubscribeToKlineUpdatesAsync(I } /// - public Task> SubscribeToMarkKlineUpdatesAsync(string symbol, FuturesStreamKlineInterval interval, Action> onMessage, CancellationToken ct = default) + public Task> SubscribeToMarkKlineUpdatesAsync(string symbol, FuturesStreamKlineInterval interval, Action> onMessage, CancellationToken ct = default) => SubscribeToMarkKlineUpdatesAsync(new[] { symbol }, interval, onMessage, ct); /// - public async Task> SubscribeToMarkKlineUpdatesAsync(IEnumerable symbols, FuturesStreamKlineInterval interval, Action> onMessage, CancellationToken ct = default) + public async Task> SubscribeToMarkKlineUpdatesAsync(IEnumerable symbols, FuturesStreamKlineInterval interval, Action> onMessage, CancellationToken ct = default) { var intervalStr = EnumConverter.GetString(interval); var handler = new Action>((receiveTime, originalData, data) => @@ -292,7 +292,7 @@ public async Task> SubscribeToMarkKlineUpdatesAsy } /// - public async Task> SubscribeToBalanceUpdatesAsync(Action> onMessage, CancellationToken ct = default) + public async Task> SubscribeToBalanceUpdatesAsync(Action> onMessage, CancellationToken ct = default) { var handler = new Action>((receiveTime, originalData, data) => { @@ -307,7 +307,7 @@ public async Task> SubscribeToBalanceUpdatesAsync } /// - public async Task> SubscribeToPositionUpdatesAsync(Action> onMessage, CancellationToken ct = default) + public async Task> SubscribeToPositionUpdatesAsync(Action> onMessage, CancellationToken ct = default) { var handler = new Action>((receiveTime, originalData, data) => { @@ -328,7 +328,7 @@ public async Task> SubscribeToPositionUpdatesAsyn } /// - public async Task> SubscribeToOrderUpdatesAsync(Action> onMessage, CancellationToken ct = default) + public async Task> SubscribeToOrderUpdatesAsync(Action> onMessage, CancellationToken ct = default) { var handler = new Action>((receiveTime, originalData, data) => { diff --git a/BitMart.Net/Clients/UsdFuturesApi/BitMartSocketClientUsdFuturesApiShared.cs b/BitMart.Net/Clients/UsdFuturesApi/BitMartSocketClientUsdFuturesApiShared.cs index fff4e01..cf8461a 100644 --- a/BitMart.Net/Clients/UsdFuturesApi/BitMartSocketClientUsdFuturesApiShared.cs +++ b/BitMart.Net/Clients/UsdFuturesApi/BitMartSocketClientUsdFuturesApiShared.cs @@ -13,113 +13,119 @@ namespace BitMart.Net.Clients.UsdFuturesApi internal partial class BitMartSocketClientUsdFuturesApi : IBitMartSocketClientUsdFuturesApiShared { private const string _topicId = "BitMartFutures"; - public string Exchange => BitMartExchange.ExchangeName; + private const string _exchangeName = "BitMart"; public TradingMode[] SupportedTradingModes { get; } = new[] { TradingMode.PerpetualLinear, TradingMode.DeliveryLinear }; public void SetDefaultExchangeParameter(string key, object value) => ExchangeParameters.SetStaticParameter(Exchange, key, value); public void ResetDefaultExchangeParameters() => ExchangeParameters.ResetStaticParameters(); + public SharedClientInfo Discover() => SharedUtils.GetClientInfo(BitMartExchange.Metadata, this); #region Tickers client - SubscribeTickersOptions ITickersSocketClient.SubscribeAllTickersOptions { get; } = new SubscribeTickersOptions(); - async Task> ITickersSocketClient.SubscribeToAllTickersUpdatesAsync(SubscribeAllTickersRequest request, Action> handler, CancellationToken ct) + SubscribeTickersOptions ITickersSocketClient.SubscribeAllTickersOptions { get; } = new SubscribeTickersOptions(_exchangeName); + async Task> ITickersSocketClient.SubscribeToAllTickersUpdatesAsync(SubscribeAllTickersRequest request, Action> handler, CancellationToken ct) { - var validationError = ((ITickersSocketClient)this).SubscribeAllTickersOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); + var validationError = SharedClient.SubscribeAllTickersOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeResult(Exchange, validationError); + return WebSocketResult.Fail(_exchangeName, validationError); - var result = await SubscribeToTickerUpdatesAsync(update => handler(update.ToType(new[] { new SharedSpotTicker(ExchangeSymbolCache.ParseSymbol(_topicId, update.Data.Symbol), update.Data.Symbol, update.Data.LastPrice, null, null, update.Data.Volume24h, Math.Round(update.Data.PriceRange * 100, 2)) })), ct).ConfigureAwait(false); + var result = await SubscribeToTickerUpdatesAsync(update => handler(update.ToType(new[] { new SharedSpotTicker(ExchangeSymbolCache.ParseSymbol(_topicId, EnvironmentName, null, update.Data.Symbol), update.Data.Symbol, update.Data.LastPrice, null, null, update.Data.Volume24h, Math.Round(update.Data.PriceRange * 100, 2)) })), ct).ConfigureAwait(false); - return new ExchangeResult(Exchange, result); + return result; } #endregion #region Ticker client - SubscribeTickerOptions ITickerSocketClient.SubscribeTickerOptions { get; } = new SubscribeTickerOptions() + SubscribeTickerOptions ITickerSocketClient.SubscribeTickerOptions { get; } = new SubscribeTickerOptions(_exchangeName) { SupportsMultipleSymbols = true, MaxSymbolCount = 75 }; - async Task> ITickerSocketClient.SubscribeToTickerUpdatesAsync(SubscribeTickerRequest request, Action> handler, CancellationToken ct) + async Task> ITickerSocketClient.SubscribeToTickerUpdatesAsync(SubscribeTickerRequest request, Action> handler, CancellationToken ct) { - var validationError = ((ITickerSocketClient)this).SubscribeTickerOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); + var validationError = SharedClient.SubscribeTickerOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeResult(Exchange, validationError); + return WebSocketResult.Fail(_exchangeName, validationError); var symbols = request.Symbols?.Length > 0 ? request.Symbols.Select(x => x.GetSymbol(FormatSymbol)).ToArray() : [request.Symbol!.GetSymbol(FormatSymbol)]; var result = await SubscribeToTickerUpdatesAsync(symbols, update => { - handler(update.ToType(new SharedSpotTicker(ExchangeSymbolCache.ParseSymbol(_topicId, update.Data.Symbol), update.Data.Symbol, update.Data.LastPrice, null, null, update.Data.Volume24h, Math.Round(update.Data.PriceRange * 100, 2)))); + handler(update.ToType(new SharedSpotTicker(ExchangeSymbolCache.ParseSymbol(_topicId, EnvironmentName, null, update.Data.Symbol), update.Data.Symbol, update.Data.LastPrice, null, null, update.Data.Volume24h, Math.Round(update.Data.PriceRange * 100, 2)))); }, ct).ConfigureAwait(false); - return new ExchangeResult(Exchange, result); + return result; } #endregion #region Trade client - EndpointOptions ITradeSocketClient.SubscribeTradeOptions { get; } = new EndpointOptions(false) + SubscribeTradeOptions ITradeSocketClient.SubscribeTradeOptions { get; } = new SubscribeTradeOptions(_exchangeName, false) { SupportsMultipleSymbols = true, MaxSymbolCount = 80 }; - async Task> ITradeSocketClient.SubscribeToTradeUpdatesAsync(SubscribeTradeRequest request, Action> handler, CancellationToken ct) + async Task> ITradeSocketClient.SubscribeToTradeUpdatesAsync(SubscribeTradeRequest request, Action> handler, CancellationToken ct) { - var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); + var validationError = SharedClient.SubscribeTradeOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeResult(Exchange, validationError); + return WebSocketResult.Fail(_exchangeName, validationError); var symbols = request.Symbols?.Length > 0 ? request.Symbols.Select(x => x.GetSymbol(FormatSymbol)).ToArray() : [request.Symbol!.GetSymbol(FormatSymbol)]; var result = await SubscribeToTradeUpdatesAsync(symbols, update => handler(update.ToType(update.Data.Select(x => - new SharedTrade(ExchangeSymbolCache.ParseSymbol(_topicId, x.Symbol), x.Symbol, x.Quantity, x.Price, x.Timestamp) { Side = x.BuyerIsMaker ? SharedOrderSide.Sell : SharedOrderSide.Buy }).ToArray())), ct).ConfigureAwait(false); + new SharedTrade(ExchangeSymbolCache.ParseSymbol(_topicId, EnvironmentName, null, x.Symbol), x.Symbol, x.Quantity, x.Price, x.Timestamp) { Side = x.BuyerIsMaker ? SharedOrderSide.Sell : SharedOrderSide.Buy }).ToArray())), ct).ConfigureAwait(false); - return new ExchangeResult(Exchange, result); + return result; } #endregion #region Book Ticker client - EndpointOptions IBookTickerSocketClient.SubscribeBookTickerOptions { get; } = new EndpointOptions(false) + SubscribeBookTickerOptions IBookTickerSocketClient.SubscribeBookTickerOptions { get; } = new SubscribeBookTickerOptions(_exchangeName, false) { SupportsMultipleSymbols = true, MaxSymbolCount = 65 }; - async Task> IBookTickerSocketClient.SubscribeToBookTickerUpdatesAsync(SubscribeBookTickerRequest request, Action> handler, CancellationToken ct) + async Task> IBookTickerSocketClient.SubscribeToBookTickerUpdatesAsync(SubscribeBookTickerRequest request, Action> handler, CancellationToken ct) { - var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); + var validationError = SharedClient.SubscribeBookTickerOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeResult(Exchange, validationError); + return WebSocketResult.Fail(_exchangeName, validationError); var symbols = request.Symbols?.Length > 0 ? request.Symbols.Select(x => x.GetSymbol(FormatSymbol)).ToArray() : [request.Symbol!.GetSymbol(FormatSymbol)]; var result = await SubscribeToBookTickerUpdatesAsync(symbols, update => { - handler(update.ToType(new SharedBookTicker(ExchangeSymbolCache.ParseSymbol(_topicId, update.Data.Symbol), update.Data.Symbol, update.Data.BestAskPrice, update.Data.BestAskQuantity, update.Data.BestBidPrice, update.Data.BestBidQuantity))); + handler(update.ToType(new SharedBookTicker(ExchangeSymbolCache.ParseSymbol(_topicId, EnvironmentName, null, update.Data.Symbol), update.Data.Symbol, update.Data.BestAskPrice, update.Data.BestAskQuantity, update.Data.BestBidPrice, update.Data.BestBidQuantity))); }, ct).ConfigureAwait(false); - return new ExchangeResult(Exchange, result); + return result; } #endregion #region Balance client - EndpointOptions IBalanceSocketClient.SubscribeBalanceOptions { get; } = new EndpointOptions(false); - async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(SubscribeBalancesRequest request, Action> handler, CancellationToken ct) + SubscribeBalanceOptions IBalanceSocketClient.SubscribeBalanceOptions { get; } = new SubscribeBalanceOptions(_exchangeName, false); + async Task> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(SubscribeBalancesRequest request, Action> handler, CancellationToken ct) { - var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); + var validationError = SharedClient.SubscribeBalanceOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeResult(Exchange, validationError); + return WebSocketResult.Fail(_exchangeName, validationError); var result = await SubscribeToBalanceUpdatesAsync( - update => handler(update.ToType(new[] { new SharedBalance(update.Data.Asset, update.Data.Available, update.Data.Available + update.Data.Frozen) })), + update => handler(update.ToType(new[] { + new SharedBalance( + SupportedTradingModes, + update.Data.Asset, + update.Data.Available, + update.Data.Available + update.Data.Frozen) })), ct: ct).ConfigureAwait(false); - return new ExchangeResult(Exchange, result); + return result; } #endregion #region Kline client - SubscribeKlineOptions IKlineSocketClient.SubscribeKlineOptions { get; } = new SubscribeKlineOptions(false, + SubscribeKlineOptions IKlineSocketClient.SubscribeKlineOptions { get; } = new SubscribeKlineOptions(_exchangeName, false, SharedKlineInterval.OneMinute, SharedKlineInterval.ThreeMinutes, SharedKlineInterval.FiveMinutes, @@ -134,40 +140,37 @@ async Task> IBalanceSocketClient.SubscribeToB SupportsMultipleSymbols = true, MaxSymbolCount = 65 }; - async Task> IKlineSocketClient.SubscribeToKlineUpdatesAsync(SubscribeKlineRequest request, Action> handler, CancellationToken ct) + async Task> IKlineSocketClient.SubscribeToKlineUpdatesAsync(SubscribeKlineRequest request, Action> handler, CancellationToken ct) { var interval = (Enums.FuturesStreamKlineInterval)request.Interval; - if (!Enum.IsDefined(typeof(Enums.FuturesStreamKlineInterval), interval)) - return new ExchangeResult(Exchange, ArgumentError.Invalid(nameof(GetKlinesRequest.Interval), "Interval not supported")); - - var validationError = ((IKlineSocketClient)this).SubscribeKlineOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); + var validationError = SharedClient.SubscribeKlineOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeResult(Exchange, validationError); + return WebSocketResult.Fail(_exchangeName, validationError); var symbols = request.Symbols?.Length > 0 ? request.Symbols.Select(x => x.GetSymbol(FormatSymbol)).ToArray() : [request.Symbol!.GetSymbol(FormatSymbol)]; var result = await SubscribeToKlineUpdatesAsync(symbols, interval, update => { foreach (var item in update.Data.Klines) - handler(update.ToType(new SharedKline(ExchangeSymbolCache.ParseSymbol(_topicId, update.Symbol), update.Symbol!, item.Timestamp!.Value, item.ClosePrice, item.HighPrice, item.LowPrice, item.OpenPrice, item.Volume))); + handler(update.ToType(new SharedKline(ExchangeSymbolCache.ParseSymbol(_topicId, EnvironmentName, null, update.Symbol), update.Symbol!, item.Timestamp!.Value, item.ClosePrice, item.HighPrice, item.LowPrice, item.OpenPrice, item.Volume))); }, ct).ConfigureAwait(false); - return new ExchangeResult(Exchange, result); + return result; } #endregion #region Futures Order client - EndpointOptions IFuturesOrderSocketClient.SubscribeFuturesOrderOptions { get; } = new EndpointOptions(false); - async Task> IFuturesOrderSocketClient.SubscribeToFuturesOrderUpdatesAsync(SubscribeFuturesOrderRequest request, Action> handler, CancellationToken ct) + SubscribeFuturesOrderOptions IFuturesOrderSocketClient.SubscribeFuturesOrderOptions { get; } = new SubscribeFuturesOrderOptions(_exchangeName, false); + async Task> IFuturesOrderSocketClient.SubscribeToFuturesOrderUpdatesAsync(SubscribeFuturesOrderRequest request, Action> handler, CancellationToken ct) { - var validationError = ((IFuturesOrderSocketClient)this).SubscribeFuturesOrderOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); + var validationError = SharedClient.SubscribeFuturesOrderOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeResult(Exchange, validationError); + return WebSocketResult.Fail(_exchangeName, validationError); var result = await SubscribeToOrderUpdatesAsync( update => handler(update.ToType(update.Data.Select(x => new SharedFuturesOrder( - ExchangeSymbolCache.ParseSymbol(_topicId, x.Order.Symbol), + ExchangeSymbolCache.ParseSymbol(_topicId, EnvironmentName, null, x.Order.Symbol), x.Order.Symbol, x.Order.OrderId.ToString(), ParseOrderType(x.Order.OrderType, x.Order.Price), @@ -185,7 +188,7 @@ async Task> IFuturesOrderSocketClient.Subscri TriggerPrice = x.Order.TriggerPrice, IsTriggerOrder = x.Order.TriggerPrice > 0, PositionSide = (x.Order.Side == Enums.FuturesSide.SellCloseLong || x.Order.Side == Enums.FuturesSide.BuyOpenLong) ? SharedPositionSide.Long : SharedPositionSide.Short, - LastTrade = x.Order.LastTrade == null ? null : new SharedUserTrade(ExchangeSymbolCache.ParseSymbol(_topicId, x.Order.Symbol), x.Order.Symbol, x.Order.OrderId, x.Order.LastTrade.TradeId.ToString(), (x.Order.Side == Enums.FuturesSide.BuyCloseShort || x.Order.Side == Enums.FuturesSide.BuyOpenLong) ? SharedOrderSide.Buy : SharedOrderSide.Sell, x.Order.LastTrade.Quantity, x.Order.LastTrade.Price, x.Order.UpdateTime!.Value) + LastTrade = x.Order.LastTrade == null ? null : new SharedUserTrade(ExchangeSymbolCache.ParseSymbol(_topicId, EnvironmentName, null, x.Order.Symbol), x.Order.Symbol, x.Order.OrderId, x.Order.LastTrade.TradeId.ToString(), (x.Order.Side == Enums.FuturesSide.BuyCloseShort || x.Order.Side == Enums.FuturesSide.BuyOpenLong) ? SharedOrderSide.Buy : SharedOrderSide.Sell, x.Order.LastTrade.Quantity, x.Order.LastTrade.Price, x.Order.UpdateTime!.Value) { Fee = x.Order.LastTrade.Fee, FeeAsset = x.Order.LastTrade.FeeAsset, @@ -195,7 +198,7 @@ async Task> IFuturesOrderSocketClient.Subscri ).ToArray())), ct: ct).ConfigureAwait(false); - return new ExchangeResult(Exchange, result); + return result; } private SharedOrderStatus ParseOrderStatus(Enums.FuturesOrderStatus status, decimal remainingQuantity) @@ -218,15 +221,15 @@ private SharedOrderType ParseOrderType(Enums.FuturesOrderType type, decimal? ord #endregion #region Position client - EndpointOptions IPositionSocketClient.SubscribePositionOptions { get; } = new EndpointOptions(true); - async Task> IPositionSocketClient.SubscribeToPositionUpdatesAsync(SubscribePositionRequest request, Action> handler, CancellationToken ct) + SubscribePositionOptions IPositionSocketClient.SubscribePositionOptions { get; } = new SubscribePositionOptions(_exchangeName, true); + async Task> IPositionSocketClient.SubscribeToPositionUpdatesAsync(SubscribePositionRequest request, Action> handler, CancellationToken ct) { - var validationError = ((IPositionSocketClient)this).SubscribePositionOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); + var validationError = SharedClient.SubscribePositionOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeResult(Exchange, validationError); + return WebSocketResult.Fail(_exchangeName, validationError); var result = await SubscribeToPositionUpdatesAsync( - update => handler(update.ToType(update.Data.Select(x => new SharedPosition(ExchangeSymbolCache.ParseSymbol(_topicId, x.Symbol), x.Symbol, x.PositionSize, x.UpdateTime) + update => handler(update.ToType(update.Data.Select(x => new SharedPosition(ExchangeSymbolCache.ParseSymbol(_topicId, EnvironmentName, null, x.Symbol), x.Symbol, x.PositionSize, x.UpdateTime) { AverageOpenPrice = x.AverageOpenPrice, PositionMode = SharedPositionMode.HedgeMode, @@ -235,27 +238,27 @@ async Task> IPositionSocketClient.SubscribeTo }).ToArray())), ct: ct).ConfigureAwait(false); - return new ExchangeResult(Exchange, result); + return result; } #endregion #region Order Book client - SubscribeOrderBookOptions IOrderBookSocketClient.SubscribeOrderBookOptions { get; } = new SubscribeOrderBookOptions(false, new[] { 5, 20, 50 }) + SubscribeOrderBookOptions IOrderBookSocketClient.SubscribeOrderBookOptions { get; } = new SubscribeOrderBookOptions(_exchangeName, false, new[] { 5, 20, 50 }) { SupportsMultipleSymbols = true, MaxSymbolCount = 65 }; - async Task> IOrderBookSocketClient.SubscribeToOrderBookUpdatesAsync(SubscribeOrderBookRequest request, Action> handler, CancellationToken ct) + async Task> IOrderBookSocketClient.SubscribeToOrderBookUpdatesAsync(SubscribeOrderBookRequest request, Action> handler, CancellationToken ct) { - var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes); + var validationError = SharedClient.SubscribeOrderBookOptions.ValidateRequest(request, this); if (validationError != null) - return new ExchangeResult(Exchange, validationError); + return WebSocketResult.Fail(_exchangeName, validationError); var symbols = request.Symbols?.Length > 0 ? request.Symbols.Select(x => x.GetSymbol(FormatSymbol)).ToArray() : [request.Symbol!.GetSymbol(FormatSymbol)]; var result = await SubscribeToOrderBookSnapshotUpdatesAsync(symbols, request.Limit ?? 20, update => handler(update.ToType(new SharedOrderBook(update.Data.Asks, update.Data.Bids))), ct).ConfigureAwait(false); - return new ExchangeResult(Exchange, result); + return result; } #endregion } diff --git a/BitMart.Net/Converters/BitMartSourceGenerationContext.cs b/BitMart.Net/Converters/BitMartSourceGenerationContext.cs index 26ed39a..fedb287 100644 --- a/BitMart.Net/Converters/BitMartSourceGenerationContext.cs +++ b/BitMart.Net/Converters/BitMartSourceGenerationContext.cs @@ -1,5 +1,6 @@ using BitMart.Net.Objects.Internal; using BitMart.Net.Objects.Models; +using CryptoExchange.Net.Objects; using System; using System.Collections.Generic; using System.Text.Json.Serialization; @@ -159,12 +160,12 @@ namespace BitMart.Net.Converters [JsonSerializable(typeof(BitMartWithdrawalQuota[]))] [JsonSerializable(typeof(BitMartWithdrawId[]))] [JsonSerializable(typeof(BorrowInfoWrapper[]))] - [JsonSerializable(typeof(BorrowInfo[]))] + [JsonSerializable(typeof(BitMartBorrowInfo[]))] [JsonSerializable(typeof(BorrowInfoAsset[]))] [JsonSerializable(typeof(BorrowRecordWrapper[]))] - [JsonSerializable(typeof(BorrowRecord[]))] + [JsonSerializable(typeof(BitMartBorrowRecord[]))] [JsonSerializable(typeof(RepayRecordWrapper[]))] - [JsonSerializable(typeof(RepayRecord[]))] + [JsonSerializable(typeof(BitMartRepayRecord[]))] [JsonSerializable(typeof(SubAccountTransferHistory[]))] [JsonSerializable(typeof(BitMartFuturesLoginResponse))] [JsonSerializable(typeof(BitMartFuturesSocketOperation))] @@ -179,6 +180,8 @@ namespace BitMart.Net.Converters [JsonSerializable(typeof(decimal))] [JsonSerializable(typeof(DateTime))] [JsonSerializable(typeof(DateTime?))] + [JsonSerializable(typeof(Parameters))] + [JsonSerializable(typeof(Parameters[]))] internal partial class BitMartSourceGenerationContext : JsonSerializerContext { } diff --git a/BitMart.Net/Interfaces/Clients/IBitMartUserClientProvider.cs b/BitMart.Net/Interfaces/Clients/IBitMartUserClientProvider.cs index 4789a36..f8384c3 100644 --- a/BitMart.Net/Interfaces/Clients/IBitMartUserClientProvider.cs +++ b/BitMart.Net/Interfaces/Clients/IBitMartUserClientProvider.cs @@ -21,6 +21,11 @@ public interface IBitMartUserClientProvider : IExchangeService /// public void ClearUserClients(string userIdentifier); + /// + /// Clear all client from the cache + /// + void Clear(); + /// /// Get the Rest client for a specific user. In case the client does not exist yet it will be created and the should be provided, unless has been called prior for this user. /// diff --git a/BitMart.Net/Interfaces/Clients/SpotApi/IBitMartRestClientSpotApiAccount.cs b/BitMart.Net/Interfaces/Clients/SpotApi/IBitMartRestClientSpotApiAccount.cs index f1faf19..2a12302 100644 --- a/BitMart.Net/Interfaces/Clients/SpotApi/IBitMartRestClientSpotApiAccount.cs +++ b/BitMart.Net/Interfaces/Clients/SpotApi/IBitMartRestClientSpotApiAccount.cs @@ -24,7 +24,7 @@ public interface IBitMartRestClientSpotApiAccount /// ["currency"] Filter on asset, for example `ETH` /// ["needUsdValuation"] Include USD valuation /// Cancellation token - Task> GetFundingBalancesAsync(string? asset = null, bool? needUsdValuation = null, CancellationToken ct = default); + Task> GetFundingBalancesAsync(string? asset = null, bool? needUsdValuation = null, CancellationToken ct = default); /// /// Get spot account balances @@ -36,7 +36,7 @@ public interface IBitMartRestClientSpotApiAccount /// /// /// Cancellation token - Task> GetSpotBalancesAsync(CancellationToken ct = default); + Task> GetSpotBalancesAsync(CancellationToken ct = default); /// /// Get deposit address @@ -49,7 +49,7 @@ public interface IBitMartRestClientSpotApiAccount /// /// ["currency"] The asset, for example `ETH` /// Cancellation token - Task> GetDepositAddressAsync(string asset, CancellationToken ct = default); + Task> GetDepositAddressAsync(string asset, CancellationToken ct = default); /// /// Get withdrawal quotas @@ -62,7 +62,7 @@ public interface IBitMartRestClientSpotApiAccount /// /// ["currency"] Asset, for example `ETH` /// Cancellation token - Task> GetWithdrawalQuotaAsync(string asset, CancellationToken ct = default); + Task> GetWithdrawalQuotaAsync(string asset, CancellationToken ct = default); /// /// Withdraw funds @@ -82,7 +82,7 @@ public interface IBitMartRestClientSpotApiAccount /// ["value"] Target account /// ["areaCode"] Area phone code /// Cancellation token - Task> WithdrawAsync(string asset, decimal quantity, string? targetAddress = null, string? memo = null, string? remark = null, string? accountDestType = null, string? targetAccount = null, string? areaCode = null, CancellationToken ct = default); + Task> WithdrawAsync(string asset, decimal quantity, string? targetAddress = null, string? memo = null, string? remark = null, string? accountDestType = null, string? targetAccount = null, string? areaCode = null, CancellationToken ct = default); /// /// Get deposit history @@ -99,7 +99,7 @@ public interface IBitMartRestClientSpotApiAccount /// ["N"] Max number of results, max 1000 /// Cancellation token /// - Task> GetDepositHistoryAsync(string? asset = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default); + Task> GetDepositHistoryAsync(string? asset = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default); /// /// Get withdrawal history @@ -116,7 +116,7 @@ public interface IBitMartRestClientSpotApiAccount /// ["N"] Max number of results, max 1000 /// Cancellation token /// - Task> GetWithdrawalHistoryAsync(string? asset = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default); + Task> GetWithdrawalHistoryAsync(string? asset = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default); /// /// Get a specific withdrawal or deposit @@ -129,7 +129,7 @@ public interface IBitMartRestClientSpotApiAccount /// /// ["id"] The deposit or withdrawal id /// Cancellation token - Task> GetDepositWithdrawalAsync(string id, CancellationToken ct = default); + Task> GetDepositWithdrawalAsync(string id, CancellationToken ct = default); /// /// Get isolated margin account info @@ -142,7 +142,7 @@ public interface IBitMartRestClientSpotApiAccount /// /// ["symbol"] Filter by symbol, for example `ETH_USDT` /// Cancellation token - Task> GetIsolatedMarginAccountsAsync(string? symbol = null, CancellationToken ct = default); + Task> GetIsolatedMarginAccountsAsync(string? symbol = null, CancellationToken ct = default); /// /// Transfer asset between Spot and Isolated Margin account @@ -158,7 +158,7 @@ public interface IBitMartRestClientSpotApiAccount /// ["amount"] Quantity to transfer /// ["side"] Direction /// Cancellation token - Task> IsolatedMarginTransferAsync(string symbol, string asset, decimal quantity, TransferDirection direction, CancellationToken ct = default); + Task> IsolatedMarginTransferAsync(string symbol, string asset, decimal quantity, TransferDirection direction, CancellationToken ct = default); /// /// Get base trading fees @@ -170,7 +170,7 @@ public interface IBitMartRestClientSpotApiAccount /// /// /// Cancellation token - Task> GetBaseTradeFeesAsync(CancellationToken ct = default); + Task> GetBaseTradeFeesAsync(CancellationToken ct = default); /// /// Get trading fees for a specific symbol @@ -183,7 +183,7 @@ public interface IBitMartRestClientSpotApiAccount /// /// ["symbol"] The symbol, for example `ETH_USDT` /// Cancellation token - Task> GetSymbolTradeFeeAsync(string symbol, CancellationToken ct = default); + Task> GetSymbolTradeFeeAsync(string symbol, CancellationToken ct = default); /// /// Get withdrawal addresses @@ -195,6 +195,6 @@ public interface IBitMartRestClientSpotApiAccount /// /// /// Cancellation token - Task> GetWithdrawalAddressesAsync(CancellationToken ct = default); + Task> GetWithdrawalAddressesAsync(CancellationToken ct = default); } } diff --git a/BitMart.Net/Interfaces/Clients/SpotApi/IBitMartRestClientSpotApiExchangeData.cs b/BitMart.Net/Interfaces/Clients/SpotApi/IBitMartRestClientSpotApiExchangeData.cs index 2f8bed2..ab96b84 100644 --- a/BitMart.Net/Interfaces/Clients/SpotApi/IBitMartRestClientSpotApiExchangeData.cs +++ b/BitMart.Net/Interfaces/Clients/SpotApi/IBitMartRestClientSpotApiExchangeData.cs @@ -21,7 +21,7 @@ public interface IBitMartRestClientSpotApiExchangeData /// GET /system/service /// /// - Task> GetServerStatusAsync(CancellationToken ct = default); + Task> GetServerStatusAsync(CancellationToken ct = default); /// /// Get server time @@ -34,7 +34,7 @@ public interface IBitMartRestClientSpotApiExchangeData /// /// Cancellation token /// - Task> GetServerTimeAsync(CancellationToken ct = default); + Task> GetServerTimeAsync(CancellationToken ct = default); /// /// Get supported assets list @@ -47,7 +47,7 @@ public interface IBitMartRestClientSpotApiExchangeData /// /// Cancellation token /// - Task> GetAssetsAsync(CancellationToken ct = default); + Task> GetAssetsAsync(CancellationToken ct = default); /// /// Get supported symbols list @@ -60,7 +60,7 @@ public interface IBitMartRestClientSpotApiExchangeData /// /// Cancellation token /// - Task> GetSymbolsAsync( CancellationToken ct = default); + Task> GetSymbolsAsync( CancellationToken ct = default); /// /// Get a list of supported symbol names @@ -73,7 +73,7 @@ public interface IBitMartRestClientSpotApiExchangeData /// /// Cancellation token /// - Task> GetSymbolNamesAsync(CancellationToken ct = default); + Task> GetSymbolNamesAsync(CancellationToken ct = default); /// /// Get price ticker for a symbol @@ -86,7 +86,7 @@ public interface IBitMartRestClientSpotApiExchangeData /// /// ["symbol"] The symbol, for example `ETH_USDT` /// Cancellation token - Task> GetTickerAsync(string symbol, CancellationToken ct = default); + Task> GetTickerAsync(string symbol, CancellationToken ct = default); /// /// Get price tickers for all symbols @@ -99,7 +99,7 @@ public interface IBitMartRestClientSpotApiExchangeData /// /// Cancellation token /// - Task> GetTickersAsync(CancellationToken ct = default); + Task> GetTickersAsync(CancellationToken ct = default); /// /// Get deposit and withdrawal info for assets @@ -112,7 +112,7 @@ public interface IBitMartRestClientSpotApiExchangeData /// /// ["currencies"] Filter by asset. Can specify up to 20 assets comma separated /// Cancellation token - Task> GetAssetDepositWithdrawInfoAsync(string? asset = null, CancellationToken ct = default); + Task> GetAssetDepositWithdrawInfoAsync(string? asset = null, CancellationToken ct = default); /// /// Get kline/candlesticks @@ -129,7 +129,7 @@ public interface IBitMartRestClientSpotApiExchangeData /// ["before"] Filter by end time /// ["limit"] Max number of results /// Cancellation token - Task> GetKlinesAsync(string symbol, KlineInterval klineInterval, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default); + Task> GetKlinesAsync(string symbol, KlineInterval klineInterval, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default); /// /// Get historical klines @@ -146,7 +146,7 @@ public interface IBitMartRestClientSpotApiExchangeData /// ["before"] Filter by end time /// ["limit"] Max number of results /// Cancellation token - Task> GetKlineHistoryAsync(string symbol, KlineInterval klineInterval, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default); + Task> GetKlineHistoryAsync(string symbol, KlineInterval klineInterval, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default); /// /// Get recent trades @@ -160,7 +160,7 @@ public interface IBitMartRestClientSpotApiExchangeData /// ["symbol"] The symbol, for example `ETH_USDT` /// ["limit"] Max number of results /// Cancellation token - Task> GetTradesAsync(string symbol, int? limit = null, CancellationToken ct = default); + Task> GetTradesAsync(string symbol, int? limit = null, CancellationToken ct = default); /// /// Get the current order book @@ -175,7 +175,7 @@ public interface IBitMartRestClientSpotApiExchangeData /// ["limit"] Max number of rows in the book /// Cancellation token /// - Task> GetOrderBookAsync(string symbol, int? limit = null, CancellationToken ct = default); + Task> GetOrderBookAsync(string symbol, int? limit = null, CancellationToken ct = default); } } diff --git a/BitMart.Net/Interfaces/Clients/SpotApi/IBitMartRestClientSpotApiMargin.cs b/BitMart.Net/Interfaces/Clients/SpotApi/IBitMartRestClientSpotApiMargin.cs index ad83634..6c94597 100644 --- a/BitMart.Net/Interfaces/Clients/SpotApi/IBitMartRestClientSpotApiMargin.cs +++ b/BitMart.Net/Interfaces/Clients/SpotApi/IBitMartRestClientSpotApiMargin.cs @@ -24,7 +24,7 @@ public interface IBitMartRestClientSpotApiMargin /// The asset, for example `ETH` /// Quantity to borrow /// Cancellation token - Task> BorrowAsync(string symbol, string asset, decimal quantity, CancellationToken ct = default); + Task> BorrowAsync(string symbol, string asset, decimal quantity, CancellationToken ct = default); /// /// Repay an asset @@ -39,7 +39,7 @@ public interface IBitMartRestClientSpotApiMargin /// The asset, for example `ETH` /// Quantity to repay /// Cancellation token - Task> RepayAsync(string symbol, string asset, decimal quantity, CancellationToken ct = default); + Task> RepayAsync(string symbol, string asset, decimal quantity, CancellationToken ct = default); /// /// Get borrow history @@ -56,7 +56,7 @@ public interface IBitMartRestClientSpotApiMargin /// Filter by end time /// Max number of results /// Cancellation token - Task> GetBorrowHistoryAsync(string symbol, string? borrowId = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default); + Task> GetBorrowHistoryAsync(string symbol, string? borrowId = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default); /// /// Get repayment history @@ -74,7 +74,7 @@ public interface IBitMartRestClientSpotApiMargin /// Filter by end time /// Max number of results /// Cancellation token - Task> GetRepayHistoryAsync(string symbol, string? asset = null, string? repayId = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default); + Task> GetRepayHistoryAsync(string symbol, string? asset = null, string? repayId = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default); /// /// Get borrow rate and quantity info @@ -87,7 +87,7 @@ public interface IBitMartRestClientSpotApiMargin /// /// Filter by symbol, for example `ETH_USDT` /// Cancellation token - Task> GetBorrowInfoAsync(string? symbol = null, CancellationToken ct = default); + Task> GetBorrowInfoAsync(string? symbol = null, CancellationToken ct = default); } } diff --git a/BitMart.Net/Interfaces/Clients/SpotApi/IBitMartRestClientSpotApiSubAccount.cs b/BitMart.Net/Interfaces/Clients/SpotApi/IBitMartRestClientSpotApiSubAccount.cs index 5594a1e..82d00b8 100644 --- a/BitMart.Net/Interfaces/Clients/SpotApi/IBitMartRestClientSpotApiSubAccount.cs +++ b/BitMart.Net/Interfaces/Clients/SpotApi/IBitMartRestClientSpotApiSubAccount.cs @@ -24,7 +24,7 @@ public interface IBitMartRestClientSpotApiSubAccount /// Quantity to transfer /// Sub account user name /// Cancellation token - Task TransferSubToMainForMainAsync(string clientOrderId, string asset, decimal quantity, string subAccount, CancellationToken ct = default); + Task TransferSubToMainForMainAsync(string clientOrderId, string asset, decimal quantity, string subAccount, CancellationToken ct = default); /// /// Transfer from sub account to main account, usable from sub account @@ -39,7 +39,7 @@ public interface IBitMartRestClientSpotApiSubAccount /// The asset, for example `ETH` /// Quantity to transfer /// Cancellation token - Task TransferSubToMainForSubAsync(string clientOrderId, string asset, decimal quantity, CancellationToken ct = default); + Task TransferSubToMainForSubAsync(string clientOrderId, string asset, decimal quantity, CancellationToken ct = default); /// /// Transfer from main account to a sub account @@ -55,7 +55,7 @@ public interface IBitMartRestClientSpotApiSubAccount /// Quantity to transfer /// Sub account name /// Cancellation token - Task TransferMainToSubAccountAsync(string clientOrderId, string asset, decimal quantity, string subAccount, CancellationToken ct = default); + Task TransferMainToSubAccountAsync(string clientOrderId, string asset, decimal quantity, string subAccount, CancellationToken ct = default); /// /// Transfer from sub account to another sub account @@ -72,7 +72,7 @@ public interface IBitMartRestClientSpotApiSubAccount /// Source sub account name /// Target sub account name /// Cancellation token - Task TransferSubAccountToSubAccountAsync(string clientOrderId, decimal quantity, string asset, string fromAccount, string toAccount, CancellationToken ct = default); + Task TransferSubAccountToSubAccountAsync(string clientOrderId, decimal quantity, string asset, string fromAccount, string toAccount, CancellationToken ct = default); /// /// Get sub account transfer history for main account @@ -86,7 +86,7 @@ public interface IBitMartRestClientSpotApiSubAccount /// Filter by account name /// Max number of results /// Cancellation token - Task> GetSubAccountTransferHistoryForMainAsync(int limit, string? account = null, CancellationToken ct = default); + Task> GetSubAccountTransferHistoryForMainAsync(int limit, string? account = null, CancellationToken ct = default); /// /// Get sub accont transfer history @@ -100,7 +100,7 @@ public interface IBitMartRestClientSpotApiSubAccount /// Max number of results /// Cancellation token /// - Task> GetSubAccountTransferHistoryAsync(int limit, CancellationToken ct = default); + Task> GetSubAccountTransferHistoryAsync(int limit, CancellationToken ct = default); /// /// Get the balance of a sub account @@ -114,7 +114,7 @@ public interface IBitMartRestClientSpotApiSubAccount /// Sub account name /// Filter by asset, for example `ETH` /// Cancellation token - Task> GetSubAcccountBalanceAsync(string subAccount, string? asset = null, CancellationToken ct = default); + Task> GetSubAccountBalanceAsync(string subAccount, string? asset = null, CancellationToken ct = default); /// /// Get list of sub accounts @@ -126,7 +126,7 @@ public interface IBitMartRestClientSpotApiSubAccount /// /// /// Cancellation token - Task> GetSubAccountListAsync(CancellationToken ct = default); + Task> GetSubAccountListAsync(CancellationToken ct = default); } } diff --git a/BitMart.Net/Interfaces/Clients/SpotApi/IBitMartRestClientSpotApiTrading.cs b/BitMart.Net/Interfaces/Clients/SpotApi/IBitMartRestClientSpotApiTrading.cs index abe16ae..b99ac80 100644 --- a/BitMart.Net/Interfaces/Clients/SpotApi/IBitMartRestClientSpotApiTrading.cs +++ b/BitMart.Net/Interfaces/Clients/SpotApi/IBitMartRestClientSpotApiTrading.cs @@ -31,7 +31,7 @@ public interface IBitMartRestClientSpotApiTrading /// ["client_order_id"] Client order id /// ["stpMode"] Self trade prevention mode /// Cancellation token - Task> PlaceOrderAsync(string symbol, OrderSide side, OrderType type, decimal? quantity = null, decimal? price = null, decimal? quoteQuantity = null, string? clientOrderId = null, SelfTradePreventionMode? stpMode = null, CancellationToken ct = default); + Task> PlaceOrderAsync(string symbol, OrderSide side, OrderType type, decimal? quantity = null, decimal? price = null, decimal? quoteQuantity = null, string? clientOrderId = null, SelfTradePreventionMode? stpMode = null, CancellationToken ct = default); /// /// Place multiple orders in one call @@ -46,7 +46,7 @@ public interface IBitMartRestClientSpotApiTrading /// ["orderParams"] Order parameters /// Cancellation token /// - Task> PlaceMultipleOrdersAsync(string symbol, IEnumerable orders, CancellationToken ct = default); + Task> PlaceMultipleOrdersAsync(string symbol, IEnumerable orders, CancellationToken ct = default); /// /// Cancel an open order @@ -61,7 +61,7 @@ public interface IBitMartRestClientSpotApiTrading /// ["order_id"] Cancel by order id. Either this or clientOrderId should be provided /// ["client_order_id"] Cancel by client order Id. Either this or orderId should be provided /// Cancellation token - Task CancelOrderAsync(string symbol, string? orderId = null, string? clientOrderId = null, CancellationToken ct = default); + Task CancelOrderAsync(string symbol, string? orderId = null, string? clientOrderId = null, CancellationToken ct = default); /// /// Cancel multiple orders @@ -76,7 +76,7 @@ public interface IBitMartRestClientSpotApiTrading /// ["orderIds"] Order ids to cancel. Either this or clientOrderIds should be provided /// ["clientOrderIds"] Client order ids to cancel. Either this or orderIds should be provided /// Cancellation token - Task> CancelOrdersAsync(string symbol, IEnumerable? orderIds = null, IEnumerable? clientOrderIds = null, CancellationToken ct = default); + Task> CancelOrdersAsync(string symbol, IEnumerable? orderIds = null, IEnumerable? clientOrderIds = null, CancellationToken ct = default); /// /// Cancel all orders matching the parameters @@ -91,7 +91,7 @@ public interface IBitMartRestClientSpotApiTrading /// ["side"] Filter by order side /// Cancellation token /// - Task CancelAllOrderAsync(string? symbol = null, OrderSide? side = null, CancellationToken ct = default); + Task CancelAllOrderAsync(string? symbol = null, OrderSide? side = null, CancellationToken ct = default); /// /// Place a new margin order @@ -110,7 +110,7 @@ public interface IBitMartRestClientSpotApiTrading /// ["notional"] Quantity in quote asset for market orders /// ["client_order_id"] Client order id /// Cancellation token - Task> PlaceMarginOrderAsync(string symbol, OrderSide side, OrderType type, decimal? quantity = null, decimal? price = null, decimal? quoteQuantity = null, string? clientOrderId = null, CancellationToken ct = default); + Task> PlaceMarginOrderAsync(string symbol, OrderSide side, OrderType type, decimal? quantity = null, decimal? price = null, decimal? quoteQuantity = null, string? clientOrderId = null, CancellationToken ct = default); /// /// Get order details @@ -124,7 +124,7 @@ public interface IBitMartRestClientSpotApiTrading /// ["orderId"] Id of the order /// ["queryState"] Order status. If known speeds up the request /// Cancellation token - Task> GetOrderAsync(string orderId, OrderQueryState? orderQueryState = null, CancellationToken ct = default); + Task> GetOrderAsync(string orderId, OrderQueryState? orderQueryState = null, CancellationToken ct = default); /// /// Get order details by client order id @@ -138,7 +138,7 @@ public interface IBitMartRestClientSpotApiTrading /// ["clientOrderId"] Client order id /// ["queryState"] Order status. If known speeds up the request /// Cancellation token - Task> GetOrderByClientOrderIdAsync(string clientOrderId, OrderQueryState? orderQueryState = null, CancellationToken ct = default); + Task> GetOrderByClientOrderIdAsync(string clientOrderId, OrderQueryState? orderQueryState = null, CancellationToken ct = default); /// /// Get current open orders @@ -155,7 +155,7 @@ public interface IBitMartRestClientSpotApiTrading /// ["endTime"] Filter by end time /// ["limit"] Max number of results /// Cancellation token - Task> GetOpenOrdersAsync(string? symbol = null, SpotMode? spotOrderMode = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default); + Task> GetOpenOrdersAsync(string? symbol = null, SpotMode? spotOrderMode = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default); /// /// Get closed orders @@ -172,7 +172,7 @@ public interface IBitMartRestClientSpotApiTrading /// ["endTime"] Filter by end time /// ["limit"] Max number of results /// Cancellation token - Task> GetClosedOrdersAsync(string? symbol = null, SpotMode? spotOrderMode = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default); + Task> GetClosedOrdersAsync(string? symbol = null, SpotMode? spotOrderMode = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default); /// /// Get list of user trades @@ -189,7 +189,7 @@ public interface IBitMartRestClientSpotApiTrading /// ["endTime"] Filter by end time /// ["limit"] Max number of results /// Cancellation token - Task> GetUserTradesAsync(string? symbol = null, SpotMode? spotOrderMode = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default); + Task> GetUserTradesAsync(string? symbol = null, SpotMode? spotOrderMode = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default); /// /// Get trades for a specific order @@ -202,7 +202,7 @@ public interface IBitMartRestClientSpotApiTrading /// /// ["orderId"] The order id /// Cancellation token - Task> GetOrderTradesAsync(string orderId, CancellationToken ct = default); + Task> GetOrderTradesAsync(string orderId, CancellationToken ct = default); } } diff --git a/BitMart.Net/Interfaces/Clients/SpotApi/IBitMartSocketClientSpotApi.cs b/BitMart.Net/Interfaces/Clients/SpotApi/IBitMartSocketClientSpotApi.cs index c255e03..54ebfe1 100644 --- a/BitMart.Net/Interfaces/Clients/SpotApi/IBitMartSocketClientSpotApi.cs +++ b/BitMart.Net/Interfaces/Clients/SpotApi/IBitMartSocketClientSpotApi.cs @@ -34,7 +34,7 @@ public interface IBitMartSocketClientSpotApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToTickerUpdatesAsync(string symbol, Action> onMessage, CancellationToken ct = default); + Task> SubscribeToTickerUpdatesAsync(string symbol, Action> onMessage, CancellationToken ct = default); /// /// Subscribe to price ticker updates for multiple symbols @@ -49,7 +49,7 @@ public interface IBitMartSocketClientSpotApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToTickerUpdatesAsync(IEnumerable symbols, Action> onMessage, CancellationToken ct = default); + Task> SubscribeToTickerUpdatesAsync(IEnumerable symbols, Action> onMessage, CancellationToken ct = default); /// /// Subscribe to kline/candlestick updates for a symbol @@ -65,7 +65,7 @@ public interface IBitMartSocketClientSpotApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToKlineUpdatesAsync(string symbol, KlineStreamInterval interval, Action> onMessage, CancellationToken ct = default); + Task> SubscribeToKlineUpdatesAsync(string symbol, KlineStreamInterval interval, Action> onMessage, CancellationToken ct = default); /// /// Subscribe to kline/candlestick updates for multiple symbols @@ -81,7 +81,7 @@ public interface IBitMartSocketClientSpotApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToKlineUpdatesAsync(IEnumerable symbols, KlineStreamInterval interval, Action> onMessage, CancellationToken ct = default); + Task> SubscribeToKlineUpdatesAsync(IEnumerable symbols, KlineStreamInterval interval, Action> onMessage, CancellationToken ct = default); /// /// Subscribe to full order book updates of the first x order book records @@ -97,7 +97,7 @@ public interface IBitMartSocketClientSpotApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToPartialOrderBookUpdatesAsync(string symbol, int depth, Action> onMessage, CancellationToken ct = default); + Task> SubscribeToPartialOrderBookUpdatesAsync(string symbol, int depth, Action> onMessage, CancellationToken ct = default); /// @@ -114,7 +114,7 @@ public interface IBitMartSocketClientSpotApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToPartialOrderBookUpdatesAsync(IEnumerable symbols, int depth, Action> onMessage, CancellationToken ct = default); + Task> SubscribeToPartialOrderBookUpdatesAsync(IEnumerable symbols, int depth, Action> onMessage, CancellationToken ct = default); /// /// Subscribe to order book updates. An initial snapshot will be pushed, followed by change updates @@ -129,7 +129,7 @@ public interface IBitMartSocketClientSpotApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToOrderBookUpdatesAsync(string symbol, Action> onMessage, CancellationToken ct = default); + Task> SubscribeToOrderBookUpdatesAsync(string symbol, Action> onMessage, CancellationToken ct = default); /// /// Subscribe to order book updates. An initial snapshot will be pushed, followed by change updates @@ -144,7 +144,7 @@ public interface IBitMartSocketClientSpotApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToOrderBookUpdatesAsync(IEnumerable symbols, Action> onMessage, CancellationToken ct = default); + Task> SubscribeToOrderBookUpdatesAsync(IEnumerable symbols, Action> onMessage, CancellationToken ct = default); /// /// Subscribe to trade updates for a symbol @@ -159,7 +159,7 @@ public interface IBitMartSocketClientSpotApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToTradeUpdatesAsync(string symbol, Action> onMessage, CancellationToken ct = default); + Task> SubscribeToTradeUpdatesAsync(string symbol, Action> onMessage, CancellationToken ct = default); /// /// Subscribe to trade updates for multiple symbols @@ -174,7 +174,7 @@ public interface IBitMartSocketClientSpotApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToTradeUpdatesAsync(IEnumerable symbols, Action> onMessage, CancellationToken ct = default); + Task> SubscribeToTradeUpdatesAsync(IEnumerable symbols, Action> onMessage, CancellationToken ct = default); /// /// Subscribe to user order updates @@ -188,7 +188,7 @@ public interface IBitMartSocketClientSpotApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToOrderUpdatesAsync(Action> onMessage, CancellationToken ct = default); + Task> SubscribeToOrderUpdatesAsync(Action> onMessage, CancellationToken ct = default); /// /// Subscribe to book ticker updates @@ -203,7 +203,7 @@ public interface IBitMartSocketClientSpotApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToBookTickerUpdatesAsync(string symbol, Action> onMessage, CancellationToken ct = default); + Task> SubscribeToBookTickerUpdatesAsync(string symbol, Action> onMessage, CancellationToken ct = default); /// /// Subscribe to book ticker updates @@ -218,7 +218,7 @@ public interface IBitMartSocketClientSpotApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToBookTickerUpdatesAsync(IEnumerable symbols, Action> onMessage, CancellationToken ct = default); + Task> SubscribeToBookTickerUpdatesAsync(IEnumerable symbols, Action> onMessage, CancellationToken ct = default); /// /// Subscribe to user balance updates @@ -232,6 +232,6 @@ public interface IBitMartSocketClientSpotApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToBalanceUpdatesAsync(Action> onMessage, CancellationToken ct = default); + Task> SubscribeToBalanceUpdatesAsync(Action> onMessage, CancellationToken ct = default); } } diff --git a/BitMart.Net/Interfaces/Clients/UsdFuturesApi/IBitMartRestClientUsdFuturesApiAccount.cs b/BitMart.Net/Interfaces/Clients/UsdFuturesApi/IBitMartRestClientUsdFuturesApiAccount.cs index 7fdff8c..9490790 100644 --- a/BitMart.Net/Interfaces/Clients/UsdFuturesApi/IBitMartRestClientUsdFuturesApiAccount.cs +++ b/BitMart.Net/Interfaces/Clients/UsdFuturesApi/IBitMartRestClientUsdFuturesApiAccount.cs @@ -22,7 +22,7 @@ public interface IBitMartRestClientUsdFuturesApiAccount /// /// /// Cancellation token - Task> GetBalancesAsync(CancellationToken ct = default); + Task> GetBalancesAsync(CancellationToken ct = default); /// /// Get account transfer history @@ -39,7 +39,7 @@ public interface IBitMartRestClientUsdFuturesApiAccount /// ["page"] Page number /// ["limit"] Max number of results /// Cancellation token - Task> GetTransferHistoryAsync(string? asset = null, DateTime? startTime = null, DateTime? endTime = null, int? page = null, int? limit = null, CancellationToken ct = default); + Task> GetTransferHistoryAsync(string? asset = null, DateTime? startTime = null, DateTime? endTime = null, int? page = null, int? limit = null, CancellationToken ct = default); /// /// Transfer between futures and spot account @@ -54,7 +54,7 @@ public interface IBitMartRestClientUsdFuturesApiAccount /// ["amount"] Quantity to transfer /// ["type"] Transfer direction /// Cancellation token - Task> TransferAsync(string asset, decimal quantity, FuturesTransferType type, CancellationToken ct = default); + Task> TransferAsync(string asset, decimal quantity, FuturesTransferType type, CancellationToken ct = default); /// /// Set leverage @@ -69,7 +69,7 @@ public interface IBitMartRestClientUsdFuturesApiAccount /// ["leverage"] Leverage /// ["open_type"] Open type, required at close position /// Cancellation token - Task> SetLeverageAsync(string symbol, decimal leverage, MarginType marginType, CancellationToken ct = default); + Task> SetLeverageAsync(string symbol, decimal leverage, MarginType marginType, CancellationToken ct = default); /// /// Get symbol trading fee @@ -83,7 +83,7 @@ public interface IBitMartRestClientUsdFuturesApiAccount /// ["symbol"] The symbol, for example `ETHUSDT` /// Cancellation token /// - Task> GetSymbolTradeFeeAsync(string symbol, CancellationToken ct = default); + Task> GetSymbolTradeFeeAsync(string symbol, CancellationToken ct = default); /// /// Get transaction history @@ -101,7 +101,7 @@ public interface IBitMartRestClientUsdFuturesApiAccount /// ["page_size"] Max number of results, max 1000 /// Cancellation token /// - Task> GetTransactionHistoryAsync(string? symbol = null, FlowType? flowType = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default); + Task> GetTransactionHistoryAsync(string? symbol = null, FlowType? flowType = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, CancellationToken ct = default); /// /// Set the position mode of the account @@ -115,7 +115,7 @@ public interface IBitMartRestClientUsdFuturesApiAccount /// ["position_mode"] Position mode /// Cancellation token /// - Task> SetPositionModeAsync(PositionMode positionMode, CancellationToken ct = default); + Task> SetPositionModeAsync(PositionMode positionMode, CancellationToken ct = default); /// /// Get the current position mode of the account @@ -128,6 +128,6 @@ public interface IBitMartRestClientUsdFuturesApiAccount /// /// Cancellation token /// - Task> GetPositionModeAsync(CancellationToken ct = default); + Task> GetPositionModeAsync(CancellationToken ct = default); } } diff --git a/BitMart.Net/Interfaces/Clients/UsdFuturesApi/IBitMartRestClientUsdFuturesApiExchangeData.cs b/BitMart.Net/Interfaces/Clients/UsdFuturesApi/IBitMartRestClientUsdFuturesApiExchangeData.cs index 214641e..db6b8d3 100644 --- a/BitMart.Net/Interfaces/Clients/UsdFuturesApi/IBitMartRestClientUsdFuturesApiExchangeData.cs +++ b/BitMart.Net/Interfaces/Clients/UsdFuturesApi/IBitMartRestClientUsdFuturesApiExchangeData.cs @@ -23,7 +23,7 @@ public interface IBitMartRestClientUsdFuturesApiExchangeData /// /// ["symbol"] Filter by symbol, for example `ETHUSDT` /// Cancellation token - Task> GetContractsAsync(string? symbol = null, CancellationToken ct = default); + Task> GetContractsAsync(string? symbol = null, CancellationToken ct = default); /// /// Get the current order book @@ -36,7 +36,7 @@ public interface IBitMartRestClientUsdFuturesApiExchangeData /// /// ["symbol"] The symbol, for example `ETHUSDT` /// Cancellation token - Task> GetOrderBookAsync(string symbol, CancellationToken ct = default); + Task> GetOrderBookAsync(string symbol, CancellationToken ct = default); /// /// Get open interest for a symbol @@ -49,7 +49,7 @@ public interface IBitMartRestClientUsdFuturesApiExchangeData /// /// ["symbol"] The symbol, for example `ETHUSDT` /// Cancellation token - Task> GetOpenInterestAsync(string symbol, CancellationToken ct = default); + Task> GetOpenInterestAsync(string symbol, CancellationToken ct = default); /// /// Get the current funding rate for a symbol @@ -62,7 +62,7 @@ public interface IBitMartRestClientUsdFuturesApiExchangeData /// /// ["symbol"] The symbol, for example `ETHUSDT` /// Cancellation token - Task> GetCurrentFundingRateAsync(string symbol, CancellationToken ct = default); + Task> GetCurrentFundingRateAsync(string symbol, CancellationToken ct = default); /// /// Get kline/candlestick data @@ -78,7 +78,7 @@ public interface IBitMartRestClientUsdFuturesApiExchangeData /// ["start_time"] Filter by start time /// ["end_time"] Filter by end time /// Cancellation token - Task> GetKlinesAsync(string symbol, FuturesKlineInterval klineInterval, DateTime startTime, DateTime endTime, CancellationToken ct = default); + Task> GetKlinesAsync(string symbol, FuturesKlineInterval klineInterval, DateTime startTime, DateTime endTime, CancellationToken ct = default); /// /// Get mark price klines @@ -94,7 +94,7 @@ public interface IBitMartRestClientUsdFuturesApiExchangeData /// ["start_time"] Filter by start time /// ["end_time"] Filter by end time /// Cancellation token - Task> GetMarkKlinesAsync(string symbol, FuturesKlineInterval klineInterval, DateTime startTime, DateTime endTime, CancellationToken ct = default); + Task> GetMarkKlinesAsync(string symbol, FuturesKlineInterval klineInterval, DateTime startTime, DateTime endTime, CancellationToken ct = default); /// /// Get funding rate history @@ -108,7 +108,7 @@ public interface IBitMartRestClientUsdFuturesApiExchangeData /// ["symbol"] The symbol, for example `ETHUSDT` /// ["limit"] Max number of results, max 100 /// Cancellation token - Task> GetFundingRateHistoryAsync(string symbol, int? limit = null, CancellationToken ct = default); + Task> GetFundingRateHistoryAsync(string symbol, int? limit = null, CancellationToken ct = default); /// /// Get leverage bracket info @@ -121,7 +121,7 @@ public interface IBitMartRestClientUsdFuturesApiExchangeData /// /// ["symbol"] The symbol, for example `ETHUSDT` /// Cancellation token - Task> GetLeverageBracketsAsync(string? symbol = null, CancellationToken ct = default); + Task> GetLeverageBracketsAsync(string? symbol = null, CancellationToken ct = default); /// /// Get recent trades @@ -135,7 +135,7 @@ public interface IBitMartRestClientUsdFuturesApiExchangeData /// ["symbol"] The symbol, for example `ETHUSDT` /// ["limit"] Max number of results /// Cancellation token - Task> GetRecentTradesAsync(string symbol, int? limit = null, CancellationToken ct = default); + Task> GetRecentTradesAsync(string symbol, int? limit = null, CancellationToken ct = default); } } diff --git a/BitMart.Net/Interfaces/Clients/UsdFuturesApi/IBitMartRestClientUsdFuturesApiSubAccount.cs b/BitMart.Net/Interfaces/Clients/UsdFuturesApi/IBitMartRestClientUsdFuturesApiSubAccount.cs index 9e0643d..4b86790 100644 --- a/BitMart.Net/Interfaces/Clients/UsdFuturesApi/IBitMartRestClientUsdFuturesApiSubAccount.cs +++ b/BitMart.Net/Interfaces/Clients/UsdFuturesApi/IBitMartRestClientUsdFuturesApiSubAccount.cs @@ -24,7 +24,7 @@ public interface IBitMartRestClientUsdFuturesApiSubAccount /// Sub account name /// Unique identifier /// Cancellation token - Task TransferSubToMainForMainAsync(string asset, decimal quantity, string subAccount, string clientOrderId, CancellationToken ct = default); + Task TransferSubToMainForMainAsync(string asset, decimal quantity, string subAccount, string clientOrderId, CancellationToken ct = default); /// /// Transfer from main account to sub futures acount @@ -40,7 +40,7 @@ public interface IBitMartRestClientUsdFuturesApiSubAccount /// Sub account name /// Unique identifier /// Cancellation token - Task TransferMainToSubForMainAsync(string asset, decimal quantity, string subAccount, string clientOrderId, CancellationToken ct = default); + Task TransferMainToSubForMainAsync(string asset, decimal quantity, string subAccount, string clientOrderId, CancellationToken ct = default); /// /// Transfer from sub futures account to main account, for sub account @@ -55,7 +55,7 @@ public interface IBitMartRestClientUsdFuturesApiSubAccount /// Quantity /// Unique identifier /// Cancellation token - Task TransferSubToMainForSubAsync(string asset, decimal quantity, string clientOrderId, CancellationToken ct = default); + Task TransferSubToMainForSubAsync(string asset, decimal quantity, string clientOrderId, CancellationToken ct = default); /// /// Get sub account futures balances @@ -69,7 +69,7 @@ public interface IBitMartRestClientUsdFuturesApiSubAccount /// Sub account name /// The asset, for example `USDT` /// Cancellation token - Task> GetSubAcccountBalanceAsync(string subAccount, string? asset = null, CancellationToken ct = default); + Task> GetSubAccountBalanceAsync(string subAccount, string? asset = null, CancellationToken ct = default); /// /// Get sub account transfer history, for main account @@ -83,7 +83,7 @@ public interface IBitMartRestClientUsdFuturesApiSubAccount /// Sub account name /// Max number of results /// Cancellation token - Task> GetSubAccountTransferHistoryForMainAsync(string subAccount, int limit, CancellationToken ct = default); + Task> GetSubAccountTransferHistoryForMainAsync(string subAccount, int limit, CancellationToken ct = default); /// /// Get sub account transfer history @@ -96,7 +96,7 @@ public interface IBitMartRestClientUsdFuturesApiSubAccount /// /// Max number of results /// Cancellation token - Task> GetSubAccountTransferHistoryAsync(int limit, CancellationToken ct = default); + Task> GetSubAccountTransferHistoryAsync(int limit, CancellationToken ct = default); } } diff --git a/BitMart.Net/Interfaces/Clients/UsdFuturesApi/IBitMartRestClientUsdFuturesApiTrading.cs b/BitMart.Net/Interfaces/Clients/UsdFuturesApi/IBitMartRestClientUsdFuturesApiTrading.cs index bd67f66..3de5778 100644 --- a/BitMart.Net/Interfaces/Clients/UsdFuturesApi/IBitMartRestClientUsdFuturesApiTrading.cs +++ b/BitMart.Net/Interfaces/Clients/UsdFuturesApi/IBitMartRestClientUsdFuturesApiTrading.cs @@ -24,7 +24,7 @@ public interface IBitMartRestClientUsdFuturesApiTrading /// ["symbol"] The symbol, for example `ETHUSDT` /// ["order_id"] Order id /// Cancellation token - Task> GetOrderAsync(string symbol, string orderId, CancellationToken ct = default); + Task> GetOrderAsync(string symbol, string orderId, CancellationToken ct = default); /// /// Get order history @@ -41,7 +41,7 @@ public interface IBitMartRestClientUsdFuturesApiTrading /// ["start_time"] Filter by start time /// ["end_time"] Filter by end time /// Cancellation token - Task> GetClosedOrdersAsync(string symbol, string? orderId = null, string? clientOrderId = null, DateTime? startTime = null, DateTime? endTime = null, CancellationToken ct = default); + Task> GetClosedOrdersAsync(string symbol, string? orderId = null, string? clientOrderId = null, DateTime? startTime = null, DateTime? endTime = null, CancellationToken ct = default); /// /// Get open orders @@ -57,7 +57,7 @@ public interface IBitMartRestClientUsdFuturesApiTrading /// ["order_state"] Filter by order status /// ["limit"] Max number of results /// Cancellation token - Task> GetOpenOrdersAsync(string? symbol = null, FuturesOrderType? orderType = null, OrderStatusQuery? status = null, int? limit = null, CancellationToken ct = default); + Task> GetOpenOrdersAsync(string? symbol = null, FuturesOrderType? orderType = null, OrderStatusQuery? status = null, int? limit = null, CancellationToken ct = default); /// /// Get open trigger orders @@ -73,7 +73,7 @@ public interface IBitMartRestClientUsdFuturesApiTrading /// ["limit"] Max number of results /// ["plan_type"] Filter by plan type /// Cancellation token - Task> GetTriggerOrdersAsync(string? symbol = null, OrderType? type = null, int? limit = null, TriggerPlanType? planType = null, CancellationToken ct = default); + Task> GetTriggerOrdersAsync(string? symbol = null, OrderType? type = null, int? limit = null, TriggerPlanType? planType = null, CancellationToken ct = default); /// /// Get current positions @@ -86,7 +86,7 @@ public interface IBitMartRestClientUsdFuturesApiTrading /// /// ["symbol"] Filter by symbol, for example `ETHUSDT` /// Cancellation token - Task> GetPositionsAsync(string? symbol = null, CancellationToken ct = default); + Task> GetPositionsAsync(string? symbol = null, CancellationToken ct = default); /// /// Get position risk @@ -99,7 +99,7 @@ public interface IBitMartRestClientUsdFuturesApiTrading /// /// ["symbol"] Filter by symbol, for example `ETHUSDT` /// Cancellation token - Task> GetPositionRiskAsync(string? symbol = null, CancellationToken ct = default); + Task> GetPositionRiskAsync(string? symbol = null, CancellationToken ct = default); /// /// Get user trades @@ -116,7 +116,7 @@ public interface IBitMartRestClientUsdFuturesApiTrading /// ["order_id"] Filter by order id /// ["client_order_id"] Filter by client order id /// Cancellation token - Task> GetUserTradesAsync( + Task> GetUserTradesAsync( string? symbol = null, DateTime? startTime = null, DateTime? endTime = null, @@ -148,7 +148,7 @@ Task> GetUserTradesAsync( /// ["preset_stop_loss_price"] Stop loss price /// ["stp_mode"] Self trade prevention mode /// Cancellation token - Task> PlaceOrderAsync(string symbol, FuturesSide side, FuturesOrderType type, int quantity, decimal? price = null, string? clientOrderId = null, decimal? leverage = null, MarginType? marginType = null, OrderMode? orderMode = null, TriggerPriceType? presetTakeProfitPriceType = null, TriggerPriceType? presetStopLossPriceType = null, decimal? presetTakeProfitPrice = null, decimal? presetStopLossPrice = null, StpMode? stpMode = null, CancellationToken ct = default); + Task> PlaceOrderAsync(string symbol, FuturesSide side, FuturesOrderType type, int quantity, decimal? price = null, string? clientOrderId = null, decimal? leverage = null, MarginType? marginType = null, OrderMode? orderMode = null, TriggerPriceType? presetTakeProfitPriceType = null, TriggerPriceType? presetStopLossPriceType = null, decimal? presetTakeProfitPrice = null, decimal? presetStopLossPrice = null, StpMode? stpMode = null, CancellationToken ct = default); /// /// Place a new trailing stop order @@ -169,7 +169,7 @@ Task> GetUserTradesAsync( /// ["activation_price_type"] Trigger price type /// Cancellation token /// - Task> PlaceTrailingOrderAsync( + Task> PlaceTrailingOrderAsync( string symbol, FuturesSide side, int quantity, @@ -193,7 +193,7 @@ Task> PlaceTrailingOrderAsync( /// ["order_id"] Order id /// Cancellation token /// - Task CancelTrailingOrderAsync(string symbol, string orderId, CancellationToken ct = default); + Task CancelTrailingOrderAsync(string symbol, string orderId, CancellationToken ct = default); /// /// Cancel an active order @@ -208,7 +208,7 @@ Task> PlaceTrailingOrderAsync( /// ["order_id"] The order id, either this or clientOrderId should be provided /// ["client_order_id"] The client order id, either this or orderId should be provided /// Cancellation token - Task CancelOrderAsync(string symbol, string? orderId = null, string? clientOrderId = null, CancellationToken ct = default); + Task CancelOrderAsync(string symbol, string? orderId = null, string? clientOrderId = null, CancellationToken ct = default); /// /// Cancel all orders on a symbol @@ -221,7 +221,7 @@ Task> PlaceTrailingOrderAsync( /// /// ["symbol"] The symbol, for example `ETHUSDT` /// Cancellation token - Task CancelOrdersAsync(string symbol, CancellationToken ct = default); + Task CancelOrdersAsync(string symbol, CancellationToken ct = default); /// /// Place a new trigger order @@ -249,7 +249,7 @@ Task> PlaceTrailingOrderAsync( /// ["preset_take_profit_price_type"] Take profit price type /// ["preset_stop_loss_price_type"] Stop loss price type /// Cancellation token - Task> PlaceTriggerOrderAsync(string symbol, OrderType orderType, FuturesSide side, int quantity, decimal leverage, MarginType marginType, decimal triggerPrice, PriceDirection priceDirection, TriggerPriceType triggerPriceType, OrderMode? orderMode = null, decimal? orderPrice = null, PlanCategory? planCategory = null, decimal? takeProfitPrice = null, decimal? stopLossPrice = null, TriggerPriceType? takeProfitPriceType = null, TriggerPriceType? stopLossPriceType = null, CancellationToken ct = default); + Task> PlaceTriggerOrderAsync(string symbol, OrderType orderType, FuturesSide side, int quantity, decimal leverage, MarginType marginType, decimal triggerPrice, PriceDirection priceDirection, TriggerPriceType triggerPriceType, OrderMode? orderMode = null, decimal? orderPrice = null, PlanCategory? planCategory = null, decimal? takeProfitPrice = null, decimal? stopLossPrice = null, TriggerPriceType? takeProfitPriceType = null, TriggerPriceType? stopLossPriceType = null, CancellationToken ct = default); /// /// Cancel a trigger order @@ -264,7 +264,7 @@ Task> PlaceTrailingOrderAsync( /// ["order_id"] The order id, either this or clientOrderId should be provided /// ["client_order_id"] The client order id, either this or orderId should be provided /// Cancellation token - Task CancelTriggerOrderAsync(string symbol, string orderId, string? clientOrderId = null, CancellationToken ct = default); + Task CancelTriggerOrderAsync(string symbol, string orderId, string? clientOrderId = null, CancellationToken ct = default); /// /// Place a new tp/sl order @@ -286,7 +286,7 @@ Task> PlaceTrailingOrderAsync( /// ["client_order_id"] Client order id /// ["category"] Type of order to place when triggered /// Cancellation token - Task> PlaceTpSlOrderAsync(string symbol, TplSlOrderType tpSlType, FuturesSide orderSide, decimal triggerPrice, TriggerPriceType priceType, PlanCategory planCategory, decimal? executionPrice = null, int? quantity = null, string? clientOrderId = null, OrderType? triggerOrderType = null, CancellationToken ct = default); + Task> PlaceTpSlOrderAsync(string symbol, TplSlOrderType tpSlType, FuturesSide orderSide, decimal triggerPrice, TriggerPriceType priceType, PlanCategory planCategory, decimal? executionPrice = null, int? quantity = null, string? clientOrderId = null, OrderType? triggerOrderType = null, CancellationToken ct = default); /// /// Edit an open limit order @@ -304,7 +304,7 @@ Task> PlaceTrailingOrderAsync( /// ["size"] New quantity /// Cancellation token /// - Task> EditOrderAsync(string symbol, long? orderId = null, string? clientOrderId = null, decimal? price = null, decimal? quantity = null, CancellationToken ct = default); + Task> EditOrderAsync(string symbol, long? orderId = null, string? clientOrderId = null, decimal? price = null, decimal? quantity = null, CancellationToken ct = default); /// /// Edit an existing tp/sl order @@ -323,7 +323,7 @@ Task> PlaceTrailingOrderAsync( /// ["plan_category"] Plan category /// ["category"] Order type /// Cancellation token - Task> EditTpSlOrderAsync(string symbol, decimal triggerPrice, TriggerPriceType priceType, PlanCategory planCategory, OrderType orderType, string? orderId = null, decimal? executionPrice = null, CancellationToken ct = default); + Task> EditTpSlOrderAsync(string symbol, decimal triggerPrice, TriggerPriceType priceType, PlanCategory planCategory, OrderType orderType, string? orderId = null, decimal? executionPrice = null, CancellationToken ct = default); /// /// Edit an existing plan order @@ -342,7 +342,7 @@ Task> PlaceTrailingOrderAsync( /// ["price_type"] Price type /// ["type"] Order type /// Cancellation token - Task> EditTriggerOrderAsync(string symbol, decimal triggerPrice, TriggerPriceType priceType, OrderType orderType, string? orderId = null, string? clientOrderId = null, decimal? executionPrice = null, CancellationToken ct = default); + Task> EditTriggerOrderAsync(string symbol, decimal triggerPrice, TriggerPriceType priceType, OrderType orderType, string? orderId = null, string? clientOrderId = null, decimal? executionPrice = null, CancellationToken ct = default); /// /// Edit an preset plan order @@ -360,7 +360,7 @@ Task> PlaceTrailingOrderAsync( /// ["preset_take_profit_price"] Take profit price /// ["preset_stop_loss_price"] Stop loss price /// Cancellation token - Task> EditPresetTriggerOrderAsync(string symbol, string orderId, TriggerPriceType takeProfitPriceType, TriggerPriceType stopLossPriceType, decimal takeProfitPrice, decimal stopLossPrice, CancellationToken ct = default); + Task> EditPresetTriggerOrderAsync(string symbol, string orderId, TriggerPriceType takeProfitPriceType, TriggerPriceType stopLossPriceType, decimal takeProfitPrice, decimal stopLossPrice, CancellationToken ct = default); /// /// Cancel all orders for a symbol after a certain timeout @@ -368,6 +368,6 @@ Task> PlaceTrailingOrderAsync( /// ["symbol"] The symbol, for example `ETHUSDT` /// ["timeout"] TimeSpan after which to cancel. TimeSpan.Zero to cancel the countdown /// Cancellation token - Task> CancelAllAfterAsync(string symbol, TimeSpan timespan, CancellationToken ct = default); + Task> CancelAllAfterAsync(string symbol, TimeSpan timespan, CancellationToken ct = default); } } diff --git a/BitMart.Net/Interfaces/Clients/UsdFuturesApi/IBitMartSocketClientUsdFuturesApi.cs b/BitMart.Net/Interfaces/Clients/UsdFuturesApi/IBitMartSocketClientUsdFuturesApi.cs index 346cee9..f9a2f4a 100644 --- a/BitMart.Net/Interfaces/Clients/UsdFuturesApi/IBitMartSocketClientUsdFuturesApi.cs +++ b/BitMart.Net/Interfaces/Clients/UsdFuturesApi/IBitMartSocketClientUsdFuturesApi.cs @@ -34,7 +34,7 @@ public interface IBitMartSocketClientUsdFuturesApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToTickerUpdatesAsync(string symbol, Action> onMessage, CancellationToken ct = default); + Task> SubscribeToTickerUpdatesAsync(string symbol, Action> onMessage, CancellationToken ct = default); /// /// Subscribe to ticker updates @@ -49,7 +49,7 @@ public interface IBitMartSocketClientUsdFuturesApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToTickerUpdatesAsync(IEnumerable symbols, Action> onMessage, CancellationToken ct = default); + Task> SubscribeToTickerUpdatesAsync(IEnumerable symbols, Action> onMessage, CancellationToken ct = default); /// /// Subscribe to ticker updates @@ -63,7 +63,7 @@ public interface IBitMartSocketClientUsdFuturesApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToTickerUpdatesAsync(Action> onMessage, CancellationToken ct = default); + Task> SubscribeToTickerUpdatesAsync(Action> onMessage, CancellationToken ct = default); /// /// Subscribe to trade updates for a symbol @@ -78,7 +78,7 @@ public interface IBitMartSocketClientUsdFuturesApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToTradeUpdatesAsync(string symbol, Action> onMessage, CancellationToken ct = default); + Task> SubscribeToTradeUpdatesAsync(string symbol, Action> onMessage, CancellationToken ct = default); /// /// Subscribe to trade updates for multiple symbols @@ -93,7 +93,7 @@ public interface IBitMartSocketClientUsdFuturesApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToTradeUpdatesAsync(IEnumerable symbols, Action> onMessage, CancellationToken ct = default); + Task> SubscribeToTradeUpdatesAsync(IEnumerable symbols, Action> onMessage, CancellationToken ct = default); /// /// Subscribe to funding rate updates for a symbol @@ -108,7 +108,7 @@ public interface IBitMartSocketClientUsdFuturesApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToFundingRateUpdatesAsync(string symbol, Action> onMessage, CancellationToken ct = default); + Task> SubscribeToFundingRateUpdatesAsync(string symbol, Action> onMessage, CancellationToken ct = default); /// /// Subscribe to funding rate updates for multiple symbols @@ -123,7 +123,7 @@ public interface IBitMartSocketClientUsdFuturesApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToFundingRateUpdatesAsync(IEnumerable symbols, Action> onMessage, CancellationToken ct = default); + Task> SubscribeToFundingRateUpdatesAsync(IEnumerable symbols, Action> onMessage, CancellationToken ct = default); /// /// Subscribe to order book updates for a symbol @@ -139,7 +139,7 @@ public interface IBitMartSocketClientUsdFuturesApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToOrderBookUpdatesAsync(string symbol, int depth, Action> onMessage, CancellationToken ct = default); + Task> SubscribeToOrderBookUpdatesAsync(string symbol, int depth, Action> onMessage, CancellationToken ct = default); /// /// Subscribe to order book updates for multiple symbols @@ -155,7 +155,7 @@ public interface IBitMartSocketClientUsdFuturesApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToOrderBookUpdatesAsync(IEnumerable symbols, int depth, Action> onMessage, CancellationToken ct = default); + Task> SubscribeToOrderBookUpdatesAsync(IEnumerable symbols, int depth, Action> onMessage, CancellationToken ct = default); /// /// Subscribe to order book updates for a symbol. Pushes the full order book depth with each update @@ -171,7 +171,7 @@ public interface IBitMartSocketClientUsdFuturesApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToOrderBookSnapshotUpdatesAsync(string symbol, int depth, Action> onMessage, CancellationToken ct = default); + Task> SubscribeToOrderBookSnapshotUpdatesAsync(string symbol, int depth, Action> onMessage, CancellationToken ct = default); /// /// Subscribe to order book updates for multiple symbols. Pushes the full order book depth with each update @@ -187,7 +187,7 @@ public interface IBitMartSocketClientUsdFuturesApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToOrderBookSnapshotUpdatesAsync(IEnumerable symbols, int depth, Action> onMessage, CancellationToken ct = default); + Task> SubscribeToOrderBookSnapshotUpdatesAsync(IEnumerable symbols, int depth, Action> onMessage, CancellationToken ct = default); /// /// Subscribe to order book updates for a symbol. First update is the snapshot, after that updates to the snapshot will be pushed @@ -203,7 +203,7 @@ public interface IBitMartSocketClientUsdFuturesApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToOrderBookIncrementalUpdatesAsync(string symbol, int depth, Action> onMessage, CancellationToken ct = default); + Task> SubscribeToOrderBookIncrementalUpdatesAsync(string symbol, int depth, Action> onMessage, CancellationToken ct = default); /// /// Subscribe to order book updates for multiple symbols. First update is the snapshot, after that updates to the snapshot will be pushed @@ -219,7 +219,7 @@ public interface IBitMartSocketClientUsdFuturesApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToOrderBookIncrementalUpdatesAsync(IEnumerable symbols, int depth, Action> onMessage, CancellationToken ct = default); + Task> SubscribeToOrderBookIncrementalUpdatesAsync(IEnumerable symbols, int depth, Action> onMessage, CancellationToken ct = default); /// /// Subscribe to updates for the best ask/bid price for a symbol @@ -228,7 +228,7 @@ public interface IBitMartSocketClientUsdFuturesApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToBookTickerUpdatesAsync(string symbol, Action> onMessage, CancellationToken ct = default); + Task> SubscribeToBookTickerUpdatesAsync(string symbol, Action> onMessage, CancellationToken ct = default); /// /// Subscribe to updates for the best ask/bid price for a symbol @@ -237,7 +237,7 @@ public interface IBitMartSocketClientUsdFuturesApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToBookTickerUpdatesAsync(IEnumerable symbols, Action> onMessage, CancellationToken ct = default); + Task> SubscribeToBookTickerUpdatesAsync(IEnumerable symbols, Action> onMessage, CancellationToken ct = default); /// /// Subscribe to kline/candlestick updates for a symbol @@ -253,7 +253,7 @@ public interface IBitMartSocketClientUsdFuturesApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToKlineUpdatesAsync(string symbol, FuturesStreamKlineInterval interval, Action> onMessage, CancellationToken ct = default); + Task> SubscribeToKlineUpdatesAsync(string symbol, FuturesStreamKlineInterval interval, Action> onMessage, CancellationToken ct = default); /// /// Subscribe to kline/candlestick updates for multiple symbols @@ -269,7 +269,7 @@ public interface IBitMartSocketClientUsdFuturesApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToKlineUpdatesAsync(IEnumerable symbols, FuturesStreamKlineInterval interval, Action> onMessage, CancellationToken ct = default); + Task> SubscribeToKlineUpdatesAsync(IEnumerable symbols, FuturesStreamKlineInterval interval, Action> onMessage, CancellationToken ct = default); /// /// Subscribe mark price kline/candlestick updates for multiple symbols @@ -285,7 +285,7 @@ public interface IBitMartSocketClientUsdFuturesApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToMarkKlineUpdatesAsync(string symbol, FuturesStreamKlineInterval interval, Action> onMessage, CancellationToken ct = default); + Task> SubscribeToMarkKlineUpdatesAsync(string symbol, FuturesStreamKlineInterval interval, Action> onMessage, CancellationToken ct = default); /// /// Subscribe mark price kline/candlestick updates for multiple symbols @@ -301,7 +301,7 @@ public interface IBitMartSocketClientUsdFuturesApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToMarkKlineUpdatesAsync(IEnumerable symbols, FuturesStreamKlineInterval interval, Action> onMessage, CancellationToken ct = default); + Task> SubscribeToMarkKlineUpdatesAsync(IEnumerable symbols, FuturesStreamKlineInterval interval, Action> onMessage, CancellationToken ct = default); /// /// Subscribe to balance updates @@ -315,7 +315,7 @@ public interface IBitMartSocketClientUsdFuturesApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToBalanceUpdatesAsync(Action> onMessage, CancellationToken ct = default); + Task> SubscribeToBalanceUpdatesAsync(Action> onMessage, CancellationToken ct = default); /// /// Subscribe to position updates @@ -329,7 +329,7 @@ public interface IBitMartSocketClientUsdFuturesApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToPositionUpdatesAsync(Action> onMessage, CancellationToken ct = default); + Task> SubscribeToPositionUpdatesAsync(Action> onMessage, CancellationToken ct = default); /// /// Subscribe to order updates @@ -343,6 +343,6 @@ public interface IBitMartSocketClientUsdFuturesApi : ISocketApiClientThe event handler for the received data /// Cancellation token for closing this subscription /// A stream subscription. This stream subscription can be used to be notified when the socket is disconnected/reconnected - Task> SubscribeToOrderUpdatesAsync(Action> onMessage, CancellationToken ct = default); + Task> SubscribeToOrderUpdatesAsync(Action> onMessage, CancellationToken ct = default); } } diff --git a/BitMart.Net/Objects/Models/BorrowInfo.cs b/BitMart.Net/Objects/Models/BitMartBorrowInfo.cs similarity index 95% rename from BitMart.Net/Objects/Models/BorrowInfo.cs rename to BitMart.Net/Objects/Models/BitMartBorrowInfo.cs index 628d4e0..8f58aaa 100644 --- a/BitMart.Net/Objects/Models/BorrowInfo.cs +++ b/BitMart.Net/Objects/Models/BitMartBorrowInfo.cs @@ -11,14 +11,14 @@ internal record BorrowInfoWrapper /// ["symbols"] Symbols /// [JsonPropertyName("symbols")] - public BorrowInfo[] Symbols { get; set; } = Array.Empty(); + public BitMartBorrowInfo[] Symbols { get; set; } = Array.Empty(); } /// /// Borrow rate and quantity info /// [SerializationModel] - public record BorrowInfo + public record BitMartBorrowInfo { /// /// ["symbol"] Symbol diff --git a/BitMart.Net/Objects/Models/BorrowRecord.cs b/BitMart.Net/Objects/Models/BitMartBorrowRecord.cs similarity index 93% rename from BitMart.Net/Objects/Models/BorrowRecord.cs rename to BitMart.Net/Objects/Models/BitMartBorrowRecord.cs index 8b2d248..b0d019a 100644 --- a/BitMart.Net/Objects/Models/BorrowRecord.cs +++ b/BitMart.Net/Objects/Models/BitMartBorrowRecord.cs @@ -11,14 +11,14 @@ internal record BorrowRecordWrapper /// ["records"] Records /// [JsonPropertyName("records")] - public BorrowRecord[] Records { get; set; } = Array.Empty(); + public BitMartBorrowRecord[] Records { get; set; } = Array.Empty(); } /// /// Borrow details /// [SerializationModel] - public record BorrowRecord + public record BitMartBorrowRecord { /// /// ["borrow_id"] Borrow id diff --git a/BitMart.Net/Objects/Models/RepayRecord.cs b/BitMart.Net/Objects/Models/BitMartRepayRecord.cs similarity index 92% rename from BitMart.Net/Objects/Models/RepayRecord.cs rename to BitMart.Net/Objects/Models/BitMartRepayRecord.cs index 0a3e5c5..2d61141 100644 --- a/BitMart.Net/Objects/Models/RepayRecord.cs +++ b/BitMart.Net/Objects/Models/BitMartRepayRecord.cs @@ -11,14 +11,14 @@ internal record RepayRecordWrapper /// ["records"] Records /// [JsonPropertyName("records")] - public RepayRecord[] Records { get; set; } = Array.Empty(); + public BitMartRepayRecord[] Records { get; set; } = Array.Empty(); } /// /// /// [SerializationModel] - public record RepayRecord + public record BitMartRepayRecord { /// /// ["repay_id"] Repay id diff --git a/BitMart.Net/Objects/Sockets/BitMartFuturesLoginQuery.cs b/BitMart.Net/Objects/Sockets/BitMartFuturesLoginQuery.cs index 7b8ec70..17fed15 100644 --- a/BitMart.Net/Objects/Sockets/BitMartFuturesLoginQuery.cs +++ b/BitMart.Net/Objects/Sockets/BitMartFuturesLoginQuery.cs @@ -16,15 +16,15 @@ public BitMartFuturesLoginQuery(string key, string timestamp, string sign) : bas Parameters = new[] { key, timestamp, sign, "web" }, }, false, 1) { - MessageRouter = MessageRouter.CreateWithoutTopicFilter("access", HandleMessage); + MessageRouter = MessageRouter.CreateForQuery("access", HandleMessage); } public CallResult HandleMessage(SocketConnection connection, DateTime receiveTime, string? originalData, BitMartFuturesLoginResponse message) { if (message.Success != true) - return new CallResult(new ServerError(ErrorInfo.Unknown with { Message = message.ErrorMessage! })); + return CallResult.Fail(new ServerError(ErrorInfo.Unknown with { Message = message.ErrorMessage! }), originalData); - return new CallResult(message, originalData, null); + return CallResult.Ok(message, originalData); } } } diff --git a/BitMart.Net/Objects/Sockets/BitMartFuturesQuery.cs b/BitMart.Net/Objects/Sockets/BitMartFuturesQuery.cs index 2fa8661..7f24088 100644 --- a/BitMart.Net/Objects/Sockets/BitMartFuturesQuery.cs +++ b/BitMart.Net/Objects/Sockets/BitMartFuturesQuery.cs @@ -11,7 +11,7 @@ namespace BitMart.Net.Objects.Sockets { - internal class BitMartFuturesQuery : Query + internal class BitMartFuturesQuery : Query { private readonly SocketApiClient _client; @@ -22,7 +22,7 @@ public BitMartFuturesQuery(SocketApiClient client, string operation, IEnumerable }, authenticated, weight) { _client = client; - MessageRouter = MessageRouter.CreateWithoutTopicFilter(parameters.Select(p => operation + "-" + p), HandleMessage); + MessageRouter = MessageRouter.CreateForQuery(parameters.Select(p => operation + "-" + p), HandleMessage); } public CallResult HandleMessage(SocketConnection connection, DateTime receiveTime, string? originalData, BitMartFuturesSocketResponse message) @@ -30,11 +30,11 @@ public CallResult HandleMessage(SocketConnection c if (message.ErrorMessage != null) { if (message.ErrorMessage.Contains("Invalid channel")) - return new CallResult(new ServerError(new ErrorInfo(ErrorType.UnknownSymbol, message.ErrorMessage))); + return CallResult.Fail(new ServerError(new ErrorInfo(ErrorType.UnknownSymbol, message.ErrorMessage))); - return new CallResult(new ServerError(new ErrorInfo(ErrorType.Unknown, message.ErrorMessage))); + return CallResult.Fail(new ServerError(new ErrorInfo(ErrorType.Unknown, message.ErrorMessage))); } - return new CallResult(message, originalData, null); + return CallResult.Ok(message, originalData); } } } diff --git a/BitMart.Net/Objects/Sockets/BitMartLoginQuery.cs b/BitMart.Net/Objects/Sockets/BitMartLoginQuery.cs index cf0a1ed..78e77c4 100644 --- a/BitMart.Net/Objects/Sockets/BitMartLoginQuery.cs +++ b/BitMart.Net/Objects/Sockets/BitMartLoginQuery.cs @@ -19,15 +19,15 @@ public BitMartLoginQuery(SocketApiClient client, string key, string timestamp, s }, false, 1) { _client = client; - MessageRouter = MessageRouter.CreateWithoutTopicFilter("login", HandleMessage); + MessageRouter = MessageRouter.CreateForQuery("login", HandleMessage); } public CallResult HandleMessage(SocketConnection connection, DateTime receiveTime, string? originalData, BitMartSocketResponse message) { if (message.ErrorCode != null) - return new CallResult(new ServerError(message.ErrorCode.Value, _client.GetErrorInfo(message.ErrorCode.Value, message.ErrorMessage!))); + return CallResult.Fail(new ServerError(message.ErrorCode.Value, _client.GetErrorInfo(message.ErrorCode.Value, message.ErrorMessage!)), originalData); - return new CallResult(message, originalData, null); + return CallResult.Ok(message, originalData); } } } diff --git a/BitMart.Net/Objects/Sockets/BitMartQuery.cs b/BitMart.Net/Objects/Sockets/BitMartQuery.cs index c6e89f4..9e7778b 100644 --- a/BitMart.Net/Objects/Sockets/BitMartQuery.cs +++ b/BitMart.Net/Objects/Sockets/BitMartQuery.cs @@ -21,15 +21,15 @@ public BitMartQuery(SocketApiClient client, string operation, IEnumerable(parameters.Select(p => operation + ":" + p), HandleMessage); + MessageRouter = MessageRouter.CreateForQuery(parameters.Select(p => operation + ":" + p), HandleMessage); } public CallResult HandleMessage(SocketConnection connection, DateTime receiveTime, string? originalData, BitMartSocketResponse message) { if (message.ErrorCode != null && message.ErrorCode != 90008) // 90008 = duplicate subscription, which is fine - return new CallResult(new ServerError(message.ErrorCode.Value, _client.GetErrorInfo(message.ErrorCode.Value, message.ErrorMessage!))); + return CallResult.Fail(new ServerError(message.ErrorCode.Value, _client.GetErrorInfo(message.ErrorCode.Value, message.ErrorMessage!)), originalData); - return new CallResult(message, originalData, null); + return CallResult.Ok(message, originalData); } } } diff --git a/BitMart.Net/Objects/Sockets/FuturesPingQuery.cs b/BitMart.Net/Objects/Sockets/FuturesPingQuery.cs index 2ada9cb..df5bd29 100644 --- a/BitMart.Net/Objects/Sockets/FuturesPingQuery.cs +++ b/BitMart.Net/Objects/Sockets/FuturesPingQuery.cs @@ -9,7 +9,7 @@ internal class FuturesPingQuery : Query> { public FuturesPingQuery() : base("{\"action\":\"ping\"}", false) { RequestTimeout = TimeSpan.FromSeconds(5); - MessageRouter = MessageRouter.CreateWithoutHandler>("pong"); + MessageRouter = MessageRouter.CreateVoid>("pong"); } } } diff --git a/BitMart.Net/Objects/Sockets/PingQuery.cs b/BitMart.Net/Objects/Sockets/PingQuery.cs index cb6fa46..6ced30a 100644 --- a/BitMart.Net/Objects/Sockets/PingQuery.cs +++ b/BitMart.Net/Objects/Sockets/PingQuery.cs @@ -8,7 +8,7 @@ internal class PingQuery : Query { public PingQuery() : base("ping", false) { RequestTimeout = TimeSpan.FromSeconds(5); - MessageRouter = MessageRouter.CreateWithoutHandler("pong"); + MessageRouter = MessageRouter.CreateVoid("pong"); } } } diff --git a/BitMart.Net/Objects/Sockets/Subscriptions/BitMartFuturesSubscription.cs b/BitMart.Net/Objects/Sockets/Subscriptions/BitMartFuturesSubscription.cs index 22713c4..b1c67c1 100644 --- a/BitMart.Net/Objects/Sockets/Subscriptions/BitMartFuturesSubscription.cs +++ b/BitMart.Net/Objects/Sockets/Subscriptions/BitMartFuturesSubscription.cs @@ -29,7 +29,7 @@ public BitMartFuturesSubscription(ILogger logger, SocketApiClient client, string IndividualSubscriptionCount = topics.Length; - MessageRouter = MessageRouter.CreateWithoutTopicFilter>(topics, DoHandleMessage); + MessageRouter = MessageRouter.CreateForEvent>(topics, DoHandleMessage); } /// @@ -42,7 +42,7 @@ public BitMartFuturesSubscription(ILogger logger, SocketApiClient client, string public CallResult DoHandleMessage(SocketConnection connection, DateTime receiveTime, string? originalData, BitMartFuturesUpdate message) { _handler.Invoke(receiveTime, originalData, message); - return CallResult.SuccessResult; + return CallResult.Ok(); } } } diff --git a/BitMart.Net/Objects/Sockets/Subscriptions/BitMartSubscription.cs b/BitMart.Net/Objects/Sockets/Subscriptions/BitMartSubscription.cs index d1a2d73..8baca01 100644 --- a/BitMart.Net/Objects/Sockets/Subscriptions/BitMartSubscription.cs +++ b/BitMart.Net/Objects/Sockets/Subscriptions/BitMartSubscription.cs @@ -34,7 +34,10 @@ public BitMartSubscription(ILogger logger, SocketApiClient client, string topic, else _subTopics = symbols!.Select(x => $"{topic}:{x}").ToArray(); - MessageRouter = MessageRouter.CreateWithOptionalTopicFilters>(topic, symbols, DoHandleMessage); + if (symbols == null || symbols.Length == 0) + MessageRouter = MessageRouter.CreateForEvent>(topic, DoHandleMessage); + else + MessageRouter = MessageRouter.CreateForEvent>(topic, symbols, DoHandleMessage); } /// @@ -47,7 +50,7 @@ public BitMartSubscription(ILogger logger, SocketApiClient client, string topic, public CallResult DoHandleMessage(SocketConnection connection, DateTime receiveTime, string? originalData, BitMartUpdate message) { _handler.Invoke(receiveTime, originalData, message); - return CallResult.SuccessResult; + return CallResult.Ok(); } } } diff --git a/BitMart.Net/SymbolOrderBooks/BitMartOrderBookFactory.cs b/BitMart.Net/SymbolOrderBooks/BitMartOrderBookFactory.cs index 76bbccd..e869941 100644 --- a/BitMart.Net/SymbolOrderBooks/BitMartOrderBookFactory.cs +++ b/BitMart.Net/SymbolOrderBooks/BitMartOrderBookFactory.cs @@ -52,14 +52,12 @@ public ISymbolOrderBook Create(SharedSymbol symbol, Action? options = null) => new BitMartUsdFuturesSymbolOrderBook(symbol, options, _serviceProvider.GetRequiredService(), - _serviceProvider.GetRequiredService(), _serviceProvider.GetRequiredService()); /// public ISymbolOrderBook CreateSpot(string symbol, Action? options = null) => new BitMartSpotSymbolOrderBook(symbol, options, _serviceProvider.GetRequiredService(), - _serviceProvider.GetRequiredService(), _serviceProvider.GetRequiredService()); diff --git a/BitMart.Net/SymbolOrderBooks/BitMartSpotSymbolOrderBook.cs b/BitMart.Net/SymbolOrderBooks/BitMartSpotSymbolOrderBook.cs index 72af760..1e8e026 100644 --- a/BitMart.Net/SymbolOrderBooks/BitMartSpotSymbolOrderBook.cs +++ b/BitMart.Net/SymbolOrderBooks/BitMartSpotSymbolOrderBook.cs @@ -20,7 +20,6 @@ namespace BitMart.Net.SymbolOrderBooks public class BitMartSpotSymbolOrderBook : SymbolOrderBook { private readonly bool _clientOwner; - private readonly IBitMartRestClient _restClient; private readonly IBitMartSocketClient _socketClient; private readonly TimeSpan _initialDataTimeout; @@ -30,7 +29,7 @@ public class BitMartSpotSymbolOrderBook : SymbolOrderBook /// The symbol the order book is for /// Option configuration delegate public BitMartSpotSymbolOrderBook(string symbol, Action? optionsDelegate = null) - : this(symbol, optionsDelegate, null, null, null) + : this(symbol, optionsDelegate, null, null) { _clientOwner = true; } @@ -41,13 +40,11 @@ public BitMartSpotSymbolOrderBook(string symbol, Action /// The symbol the order book is for /// Option configuration delegate /// Logger - /// Rest client instance /// Socket client instance public BitMartSpotSymbolOrderBook( string symbol, Action? optionsDelegate, ILoggerFactory? logger, - IBitMartRestClient? restClient, IBitMartSocketClient? socketClient) : base(logger, "BitMart", "Spot", symbol) { var options = BitMartOrderBookOptions.Default.Copy(); @@ -62,33 +59,32 @@ public BitMartSpotSymbolOrderBook( _initialDataTimeout = options?.InitialDataTimeout ?? TimeSpan.FromSeconds(30); _clientOwner = socketClient == null; _socketClient = socketClient ?? new BitMartSocketClient(); - _restClient = restClient ?? new BitMartRestClient(); } /// protected override async Task> DoStartAsync(CancellationToken ct) { - CallResult subResult; + WebSocketResult subResult; if (Levels == null) subResult = await _socketClient.SpotApi.SubscribeToOrderBookUpdatesAsync(Symbol, HandleUpdate).ConfigureAwait(false); else subResult = await _socketClient.SpotApi.SubscribeToPartialOrderBookUpdatesAsync(Symbol, Levels.Value, HandleUpdate).ConfigureAwait(false); - if (!subResult) - return new CallResult(subResult.Error!); + if (!subResult.Success) + return CallResult.Fail(subResult.Error!); if (ct.IsCancellationRequested) { await subResult.Data.CloseAsync().ConfigureAwait(false); - return subResult.AsError(new CancellationRequestedError()); + return CallResult.Fail(new CancellationRequestedError()); } Status = OrderBookStatus.Syncing; var setResult = await WaitForSetOrderBookAsync(_initialDataTimeout, ct).ConfigureAwait(false); - if (!setResult) + if (!setResult.Success) await subResult.Data.CloseAsync().ConfigureAwait(false); - return setResult ? subResult : new CallResult(setResult.Error!); + return setResult.Success ? CallResult.Ok(subResult.Data) : CallResult.Fail(setResult.Error!); } private void HandleUpdate(DataEvent data) @@ -110,7 +106,7 @@ protected override void DoReset() } /// - protected override async Task> DoResyncAsync(CancellationToken ct) + protected override async Task DoResyncAsync(CancellationToken ct) { return await WaitForSetOrderBookAsync(_initialDataTimeout, ct).ConfigureAwait(false); } @@ -119,10 +115,7 @@ protected override async Task> DoResyncAsync(CancellationToken protected override void Dispose(bool disposing) { if (_clientOwner) - { - _restClient?.Dispose(); _socketClient?.Dispose(); - } base.Dispose(disposing); } diff --git a/BitMart.Net/SymbolOrderBooks/BitMartUsdFuturesSymbolOrderBook.cs b/BitMart.Net/SymbolOrderBooks/BitMartUsdFuturesSymbolOrderBook.cs index bef283f..d569a69 100644 --- a/BitMart.Net/SymbolOrderBooks/BitMartUsdFuturesSymbolOrderBook.cs +++ b/BitMart.Net/SymbolOrderBooks/BitMartUsdFuturesSymbolOrderBook.cs @@ -19,7 +19,6 @@ namespace BitMart.Net.SymbolOrderBooks public class BitMartUsdFuturesSymbolOrderBook : SymbolOrderBook { private readonly bool _clientOwner; - private readonly IBitMartRestClient _restClient; private readonly IBitMartSocketClient _socketClient; private readonly TimeSpan _initialDataTimeout; @@ -29,7 +28,7 @@ public class BitMartUsdFuturesSymbolOrderBook : SymbolOrderBook /// The symbol the order book is for /// Option configuration delegate public BitMartUsdFuturesSymbolOrderBook(string symbol, Action? optionsDelegate = null) - : this(symbol, optionsDelegate, null, null, null) + : this(symbol, optionsDelegate, null, null) { _clientOwner = true; } @@ -40,13 +39,11 @@ public BitMartUsdFuturesSymbolOrderBook(string symbol, ActionThe symbol the order book is for /// Option configuration delegate /// Logger - /// Rest client instance /// Socket client instance public BitMartUsdFuturesSymbolOrderBook( string symbol, Action? optionsDelegate, ILoggerFactory? logger, - IBitMartRestClient? restClient, IBitMartSocketClient? socketClient) : base(logger, "BitMart", "UsdFutures", symbol) { var options = BitMartOrderBookOptions.Default.Copy(); @@ -61,28 +58,27 @@ public BitMartUsdFuturesSymbolOrderBook( _initialDataTimeout = options?.InitialDataTimeout ?? TimeSpan.FromSeconds(30); _clientOwner = socketClient == null; _socketClient = socketClient ?? new BitMartSocketClient(); - _restClient = restClient ?? new BitMartRestClient(); } /// protected override async Task> DoStartAsync(CancellationToken ct) { var subResult = await _socketClient.UsdFuturesApi.SubscribeToOrderBookIncrementalUpdatesAsync(Symbol, Levels ?? 20, HandleUpdate).ConfigureAwait(false); - if (!subResult) - return new CallResult(subResult.Error!); + if (!subResult.Success) + return CallResult.Fail(subResult.Error!); if (ct.IsCancellationRequested) { await subResult.Data.CloseAsync().ConfigureAwait(false); - return subResult.AsError(new CancellationRequestedError()); + return CallResult.Fail(new CancellationRequestedError()); } Status = OrderBookStatus.Syncing; var setResult = await WaitForSetOrderBookAsync(_initialDataTimeout, ct).ConfigureAwait(false); - if (!setResult) + if (!setResult.Success) await subResult.Data.CloseAsync().ConfigureAwait(false); - return setResult ? subResult : new CallResult(setResult.Error!); + return setResult.Success ? CallResult.Ok(subResult.Data) : CallResult.Fail(setResult.Error!); } private void HandleUpdate(DataEvent data) @@ -100,7 +96,7 @@ protected override void DoReset() } /// - protected override async Task> DoResyncAsync(CancellationToken ct) + protected override async Task DoResyncAsync(CancellationToken ct) { return await WaitForSetOrderBookAsync(_initialDataTimeout, ct).ConfigureAwait(false); } @@ -109,10 +105,7 @@ protected override async Task> DoResyncAsync(CancellationToken protected override void Dispose(bool disposing) { if (_clientOwner) - { - _restClient?.Dispose(); _socketClient?.Dispose(); - } base.Dispose(disposing); } diff --git a/Examples/ai-friendly/03-websocket.cs b/Examples/ai-friendly/03-websocket.cs index 51594d0..b652c5b 100644 --- a/Examples/ai-friendly/03-websocket.cs +++ b/Examples/ai-friendly/03-websocket.cs @@ -9,6 +9,7 @@ var socketClient = new BitMartSocketClient(); +// Subscription methods return WebSocketResult. var spotTickerSubscription = await socketClient.SpotApi.SubscribeToTickerUpdatesAsync( "BTC_USDT", update => diff --git a/Examples/ai-friendly/04-multi-exchange.cs b/Examples/ai-friendly/04-multi-exchange.cs index fe79a81..42c86a4 100644 --- a/Examples/ai-friendly/04-multi-exchange.cs +++ b/Examples/ai-friendly/04-multi-exchange.cs @@ -11,7 +11,14 @@ using CryptoExchange.Net.SharedApis; // BitMart exposes SharedClient on both SpotApi and UsdFuturesApi. -ISpotTickerRestClient bitMartSpotShared = new BitMartRestClient().SpotApi.SharedClient; +var bitMartRest = new BitMartRestClient(); +ISpotTickerRestClient bitMartSpotShared = bitMartRest.SpotApi.SharedClient; + +var sharedInfo = bitMartRest.SpotApi.SharedClient.Discover(); +var supportedFeatures = sharedInfo.Features + .Where(x => x.Supported) + .Select(x => x.EndpointName); +Console.WriteLine($"{sharedInfo.Exchange} {sharedInfo.TypeName}: {string.Join(", ", supportedFeatures)}"); var btcusdt = new SharedSymbol(TradingMode.Spot, "BTC", "USDT"); @@ -33,6 +40,7 @@ async Task PrintTicker(ISpotTickerRestClient client, SharedSymbol symbol) // ISpotTickerRestClient, ISpotSymbolRestClient, ISpotOrderRestClient // IFuturesTickerRestClient, IFuturesOrderRestClient, IFuturesSymbolRestClient // IBalanceRestClient, IFeeRestClient, IOrderBookRestClient +// Call SharedClient.Discover() before routing optional shared features. // ---- WEBSOCKET EXAMPLE - SHARED SUBSCRIPTION ---- var bitMartSocket = new BitMartSocketClient(); diff --git a/Examples/ai-friendly/05-error-handling.cs b/Examples/ai-friendly/05-error-handling.cs index 99c375a..9a31963 100644 --- a/Examples/ai-friendly/05-error-handling.cs +++ b/Examples/ai-friendly/05-error-handling.cs @@ -1,6 +1,7 @@ // 05-error-handling.cs // -// Demonstrates: WebCallResult patterns, retry logic, common error scenarios. +// Demonstrates: HttpResult, WebSocketResult, ExchangeCallResult, retry logic, +// and common error scenarios. // // Setup: dotnet add package BitMart.Net @@ -15,7 +16,9 @@ }); // ---- 1. THE BASIC PATTERN ---- -// Every REST method returns WebCallResult or WebCallResult. +// Every REST method returns HttpResult or HttpResult. +// WebSocket subscriptions return WebSocketResult. +// Shared non-I/O symbol/cache helpers return ExchangeCallResult. // .Success is true/false. .Data is valid only when .Success is true. // .Error contains structured error info when .Success is false. @@ -37,11 +40,11 @@ // Retry only on transient errors such as rate limits, network issues, or server overload. // Do not retry validation errors or insufficient balance errors. -async Task> WithRetry( - Func>> call, +async Task> WithRetry( + Func>> call, int maxAttempts = 3) { - WebCallResult last = default!; + HttpResult last = default!; for (var attempt = 1; attempt <= maxAttempts; attempt++) { last = await call(); @@ -79,7 +82,7 @@ async Task> WithRetry( } // ---- 4. EXCEPTIONS VS ERROR RESULTS ---- -// BitMart.Net returns API/network/rate-limit errors via WebCallResult.Error. +// BitMart.Net returns API/network/rate-limit errors via HttpResult.Error. // Exceptions are for misconfiguration, disposal, cancellation, or programmer errors. // Common variations: diff --git a/Examples/ai-friendly/README.md b/Examples/ai-friendly/README.md index cffaf53..b54c2b2 100644 --- a/Examples/ai-friendly/README.md +++ b/Examples/ai-friendly/README.md @@ -30,7 +30,7 @@ Do not use `BTC-USDT`, `BTC/USDT`, or Bitfinex-style `tBTCUSD`. ## Result pattern -Most REST calls return `WebCallResult`. Always check `.Success` before using `.Data`; use `.Error` for exchange, validation, network and rate-limit failures. +Most REST calls return `HttpResult` or `HttpResult`. Shared non-I/O symbol/cache helpers return `ExchangeCallResult`. Always check `.Success` before using `.Data`; use `.Error` for exchange, validation, network and rate-limit failures. ```csharp var result = await client.SpotApi.ExchangeData.GetTickerAsync("BTC_USDT"); @@ -43,7 +43,7 @@ if (!result.Success) Console.WriteLine(result.Data.LastPrice); ``` -Socket subscription calls return `CallResult`. Keep the concrete socket client so you can unsubscribe: +Socket subscription calls return `WebSocketResult`. Keep the concrete socket client so you can unsubscribe: ```csharp var sub = await socketClient.SpotApi.SubscribeToTickerUpdatesAsync("BTC_USDT", update => { }); @@ -56,8 +56,8 @@ if (sub.Success) - `01-spot-quickstart.cs` - public market data, balances, open orders and spot order placement. - `02-usd-futures.cs` - USD futures funding, balances, positions and order flow. - `03-websocket.cs` - spot and USD futures public WebSocket subscriptions and unsubscribe pattern. -- `04-multi-exchange.cs` - CryptoExchange.Net shared API usage for exchange-agnostic code. -- `05-error-handling.cs` - `WebCallResult` handling, transient retry shape and order error categorization. +- `04-multi-exchange.cs` - CryptoExchange.Net shared API usage, capability discovery and shared subscriptions. +- `05-error-handling.cs` - `HttpResult`, `WebSocketResult` and `ExchangeCallResult` handling, transient retry shape and order error categorization. ## Common routing @@ -70,6 +70,6 @@ if (sub.Success) - USD futures account: `client.UsdFuturesApi.Account` - USD futures positions and orders: `client.UsdFuturesApi.Trading` - USD futures subaccounts: `client.UsdFuturesApi.SubAccount` -- Shared APIs: `client.SpotApi.SharedClient`, `client.UsdFuturesApi.SharedClient` +- Shared APIs: `client.SpotApi.SharedClient`, `client.UsdFuturesApi.SharedClient`; call `.Discover()` before routing optional shared features For detailed endpoint routing, see `docs/ai-api-map.md`. For fuller assistant context, see `llms-full.txt`. diff --git a/docs/ai-api-map.md b/docs/ai-api-map.md index 625095f..7a8d83f 100644 --- a/docs/ai-api-map.md +++ b/docs/ai-api-map.md @@ -19,6 +19,7 @@ Use this file to route common user intents to the correct BitMart.Net client mem | Shared USD futures REST | `client.UsdFuturesApi.SharedClient` | | Shared spot socket | `socketClient.SpotApi.SharedClient` | | Shared USD futures socket | `socketClient.UsdFuturesApi.SharedClient` | +| Discover shared capabilities | `client.SpotApi.SharedClient.Discover()` / `client.UsdFuturesApi.SharedClient.Discover()` | ## Symbols @@ -202,13 +203,25 @@ Use this file to route common user intents to the correct BitMart.Net client mem | Shared futures REST client | `new BitMartRestClient().UsdFuturesApi.SharedClient` | | Shared spot socket client | `new BitMartSocketClient().SpotApi.SharedClient` | | Shared futures socket client | `new BitMartSocketClient().UsdFuturesApi.SharedClient` | +| Discover shared capabilities | `client.SpotApi.SharedClient.Discover()` / `client.UsdFuturesApi.SharedClient.Discover()` | | Shared spot ticker REST | `ISpotTickerRestClient.GetSpotTickerAsync(new GetTickerRequest(symbol))` | | Shared futures ticker REST | `IFuturesTickerRestClient.GetFuturesTickerAsync(new GetTickerRequest(symbol))` | | Shared ticker socket | `ITickerSocketClient.SubscribeToTickerUpdatesAsync(...)` | | Shared order book socket | `IOrderBookSocketClient.SubscribeToOrderBookUpdatesAsync(...)` | +Shared REST calls return `HttpResult` / `HttpResult`. Shared socket subscriptions return `WebSocketResult`. Shared non-I/O symbol/cache helpers such as symbol support checks return `ExchangeCallResult`. + For shared socket subscriptions, keep the concrete socket client and unsubscribe with `await socketClient.UnsubscribeAsync(subscription.Data)`. +## Result Handling + +| Situation | Pattern | +|---|---| +| REST success check | `if (!result.Success) { Console.WriteLine(result.Error); return; }` | +| Socket subscription success check | `WebSocketResult sub = await ...; if (!sub.Success) { Console.WriteLine(sub.Error); return; }` | +| Read REST data | Read `result.Data` only after `result.Success` | +| Shared helper data | Read `ExchangeCallResult.Data` only after `result.Success` | + ## Common Routing Pitfalls | Do not use | Use instead | diff --git a/llms-full.txt b/llms-full.txt index 58b2402..9770ef5 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -25,8 +25,9 @@ Primary documentation: - Include `using BitMart.Net;` when using `BitMartCredentials` or `BitMartEnvironment`. - Include `using BitMart.Net.Enums;` for order sides, order types, futures sides, margin types, position modes and kline intervals. - Always check `.Success` before reading `.Data`. -- REST methods return `WebCallResult` or `WebCallResult`. -- WebSocket subscriptions return `CallResult`. +- REST methods return `HttpResult` or `HttpResult`. +- WebSocket subscriptions return `WebSocketResult`. +- Shared non-I/O symbol/cache helpers return `ExchangeCallResult`. - Reuse clients. Do not instantiate a REST or socket client per request in production code. - Prefer dependency injection for long-running services. - Store WebSocket subscriptions and unsubscribe during shutdown. @@ -35,7 +36,7 @@ Primary documentation: - Use `SpotApi` for spot and margin endpoints. - Use `UsdFuturesApi` for USD futures endpoints. - Spot symbols use underscores (`BTC_USDT`); USD futures symbols do not (`BTCUSDT`). -- For multi-exchange code, use `CryptoExchange.Net.SharedApis` interfaces from each exchange's `.SharedClient`. +- For multi-exchange code, use `CryptoExchange.Net.SharedApis` interfaces from each exchange's `.SharedClient` and call `.Discover()` to inspect supported shared features. ## Installation @@ -435,6 +436,10 @@ Spot: ```csharp ISpotTickerRestClient tickerClient = new BitMartRestClient().SpotApi.SharedClient; +var info = tickerClient.Discover(); +var supported = info.Features.Where(x => x.Supported).Select(x => x.EndpointName); +Console.WriteLine($"{info.Exchange} {info.TypeName}: {string.Join(", ", supported)}"); + var symbol = new SharedSymbol(TradingMode.Spot, "BTC", "USDT"); var ticker = await tickerClient.GetSpotTickerAsync(new GetTickerRequest(symbol)); @@ -444,6 +449,10 @@ USD futures: ```csharp IFuturesTickerRestClient futuresTickerClient = new BitMartRestClient().UsdFuturesApi.SharedClient; +var futuresInfo = futuresTickerClient.Discover(); +var futuresSupported = futuresInfo.Features.Where(x => x.Supported).Select(x => x.EndpointName); +Console.WriteLine($"{futuresInfo.Exchange} {futuresInfo.TypeName}: {string.Join(", ", futuresSupported)}"); + var futuresSymbol = new SharedSymbol(TradingMode.PerpetualLinear, "BTC", "USDT"); var ticker = await futuresTickerClient.GetFuturesTickerAsync(new GetTickerRequest(futuresSymbol)); @@ -482,9 +491,9 @@ Console.WriteLine(result.Data.LastPrice); Retry only transient failures: ```csharp -async Task> WithRetry(Func>> call) +async Task> WithRetry(Func>> call) { - WebCallResult last = default!; + HttpResult last = default!; for (var attempt = 1; attempt <= 3; attempt++) { last = await call(); diff --git a/llms.txt b/llms.txt index a1a60fa..4c6c973 100644 --- a/llms.txt +++ b/llms.txt @@ -1,6 +1,6 @@ # BitMart.Net -BitMart.Net is a .NET client library for BitMart REST and WebSocket APIs, built on CryptoExchange.Net. +BitMart.Net is a .NET client library for BitMart REST and WebSocket APIs, built on CryptoExchange.Net. REST methods return `HttpResult` / `HttpResult`, WebSocket subscriptions return `WebSocketResult`, and shared symbol/cache helpers return `ExchangeCallResult`. ## Install @@ -28,6 +28,7 @@ var socketClient = new BitMartSocketClient(); - USD futures REST: `restClient.UsdFuturesApi` - Spot socket: `socketClient.SpotApi` - USD futures socket: `socketClient.UsdFuturesApi` +- Shared capability discovery: `client.SpotApi.SharedClient.Discover()` / `client.UsdFuturesApi.SharedClient.Discover()` ## Common calls