From e65c3357c7bc45de0c95053c361b119084e4d02c Mon Sep 17 00:00:00 2001 From: Jkorf Date: Mon, 18 Nov 2024 14:40:12 +0100 Subject: [PATCH 1/2] wip --- Kucoin.Net.UnitTests/KucoinClientTests.cs | 105 ++++++++++++++++ .../KucoinRestIntegrationTests.cs | 10 +- .../KucoinSocketClientFuturesApi.cs | 2 +- Kucoin.Net/Clients/KucoinRestClient.cs | 21 ++-- Kucoin.Net/Clients/KucoinSocketClient.cs | 28 ++--- .../SpotApi/KucoinSocketClientSpotApi.cs | 2 +- .../ServiceCollectionExtensions.cs | 116 ++++++++++++++---- Kucoin.Net/Kucoin.Net.csproj | 4 +- Kucoin.Net/Kucoin.Net.xml | 93 +++++++++++--- Kucoin.Net/KucoinEnvironment.cs | 21 ++++ Kucoin.Net/Objects/KucoinApiCredentials.cs | 23 ++-- Kucoin.Net/Objects/Options/KucoinOptions.cs | 39 ++++++ .../Objects/Options/KucoinRestApiOptions.cs | 10 +- .../Objects/Options/KucoinRestOptions.cs | 20 ++- .../Objects/Options/KucoinSocketOptions.cs | 20 ++- 15 files changed, 406 insertions(+), 108 deletions(-) create mode 100644 Kucoin.Net/Objects/Options/KucoinOptions.cs diff --git a/Kucoin.Net.UnitTests/KucoinClientTests.cs b/Kucoin.Net.UnitTests/KucoinClientTests.cs index 52bc00b6..47885e56 100644 --- a/Kucoin.Net.UnitTests/KucoinClientTests.cs +++ b/Kucoin.Net.UnitTests/KucoinClientTests.cs @@ -10,6 +10,10 @@ using System.Net.Http; using CryptoExchange.Net.Clients; using CryptoExchange.Net.Converters.JsonNet; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Kucoin.Net.Interfaces.Clients; +using CryptoExchange.Net.Objects; namespace Kucoin.Net.UnitTests { @@ -110,5 +114,106 @@ public void CheckInterfaces() CryptoExchange.Net.Testing.TestHelpers.CheckForMissingRestInterfaces(); CryptoExchange.Net.Testing.TestHelpers.CheckForMissingSocketInterfaces(); } + + [Test] + [TestCase(TradeEnvironmentNames.Live, "https://api.kucoin.com/")] + [TestCase(TradeEnvironmentNames.Testnet, "https://openapi-sandbox.kucoin.com/")] + [TestCase("", "https://api.kucoin.com/")] + public void TestConstructorEnvironments(string environmentName, string expected) + { + var configuration = new ConfigurationBuilder() + .AddInMemoryCollection(new Dictionary + { + { "Kucoin:Environment:Name", environmentName }, + }).Build(); + + var collection = new ServiceCollection(); + collection.AddKucoin(configuration.GetSection("Kucoin")); + var provider = collection.BuildServiceProvider(); + + var client = provider.GetRequiredService(); + + var address = client.SpotApi.BaseAddress; + + Assert.That(address, Is.EqualTo(expected)); + } + + [Test] + public void TestConstructorNullEnvironment() + { + var configuration = new ConfigurationBuilder() + .AddInMemoryCollection(new Dictionary + { + { "Kucoin", null }, + }).Build(); + + var collection = new ServiceCollection(); + collection.AddKucoin(configuration.GetSection("Kucoin")); + var provider = collection.BuildServiceProvider(); + + var client = provider.GetRequiredService(); + + var address = client.SpotApi.BaseAddress; + + Assert.That(address, Is.EqualTo("https://api.kucoin.com/")); + } + + [Test] + public void TestConstructorApiOverwriteEnvironment() + { + var configuration = new ConfigurationBuilder() + .AddInMemoryCollection(new Dictionary + { + { "Kucoin:Environment:Name", "test" }, + { "Kucoin:Rest:Environment:Name", "live" }, + }).Build(); + + var collection = new ServiceCollection(); + collection.AddKucoin(configuration.GetSection("Kucoin")); + var provider = collection.BuildServiceProvider(); + + var client = provider.GetRequiredService(); + + var address = client.SpotApi.BaseAddress; + + Assert.That(address, Is.EqualTo("https://api.kucoin.com/")); + } + + [Test] + public void TestConstructorConfiguration() + { + var configuration = new ConfigurationBuilder() + .AddInMemoryCollection(new Dictionary + { + { "ApiCredentials:Key", "123" }, + { "ApiCredentials:Secret", "456" }, + { "ApiCredentials:PassPhrase", "222" }, + { "Socket:ApiCredentials:Key", "456" }, + { "Socket:ApiCredentials:Secret", "789" }, + { "Socket:ApiCredentials:PassPhrase", "111" }, + { "Rest:OutputOriginalData", "true" }, + { "Socket:OutputOriginalData", "false" }, + { "Rest:Proxy:Host", "host" }, + { "Rest:Proxy:Port", "80" }, + { "Socket:Proxy:Host", "host2" }, + { "Socket:Proxy:Port", "81" }, + }).Build(); + + var collection = new ServiceCollection(); + collection.AddKucoin(configuration); + var provider = collection.BuildServiceProvider(); + + var restClient = provider.GetRequiredService(); + var socketClient = provider.GetRequiredService(); + + Assert.That(((BaseApiClient)restClient.SpotApi).OutputOriginalData, Is.True); + Assert.That(((BaseApiClient)socketClient.SpotApi).OutputOriginalData, Is.False); + Assert.That(((BaseApiClient)restClient.SpotApi).AuthenticationProvider.ApiKey, Is.EqualTo("123")); + Assert.That(((BaseApiClient)socketClient.SpotApi).AuthenticationProvider.ApiKey, Is.EqualTo("456")); + Assert.That(((BaseApiClient)restClient.SpotApi).ClientOptions.Proxy.Host, Is.EqualTo("host")); + Assert.That(((BaseApiClient)restClient.SpotApi).ClientOptions.Proxy.Port, Is.EqualTo(80)); + Assert.That(((BaseApiClient)socketClient.SpotApi).ClientOptions.Proxy.Host, Is.EqualTo("host2")); + Assert.That(((BaseApiClient)socketClient.SpotApi).ClientOptions.Proxy.Port, Is.EqualTo(81)); + } } } diff --git a/Kucoin.Net.UnitTests/KucoinRestIntegrationTests.cs b/Kucoin.Net.UnitTests/KucoinRestIntegrationTests.cs index d9d1b145..ed54106c 100644 --- a/Kucoin.Net.UnitTests/KucoinRestIntegrationTests.cs +++ b/Kucoin.Net.UnitTests/KucoinRestIntegrationTests.cs @@ -9,6 +9,8 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using Kucoin.Net.Objects.Options; namespace Kucoin.Net.UnitTests { @@ -28,11 +30,11 @@ public override KucoinRestClient GetClient(ILoggerFactory loggerFactory) var pass = Environment.GetEnvironmentVariable("APIPASS"); Authenticated = key != null && sec != null; - return new KucoinRestClient(null, loggerFactory, opts => + return new KucoinRestClient(null, loggerFactory, Options.Create(new KucoinRestOptions { - opts.OutputOriginalData = true; - opts.ApiCredentials = Authenticated ? new KucoinApiCredentials(key, sec, pass) : null; - }); + OutputOriginalData = true, + ApiCredentials = Authenticated ? new KucoinApiCredentials(key, sec, pass) : null + })); } [Test] diff --git a/Kucoin.Net/Clients/FuturesApi/KucoinSocketClientFuturesApi.cs b/Kucoin.Net/Clients/FuturesApi/KucoinSocketClientFuturesApi.cs index caaba474..695e6c09 100644 --- a/Kucoin.Net/Clients/FuturesApi/KucoinSocketClientFuturesApi.cs +++ b/Kucoin.Net/Clients/FuturesApi/KucoinSocketClientFuturesApi.cs @@ -241,7 +241,7 @@ public async Task> SubscribeToCrossMarginLeverage /// protected override async Task> GetConnectionUrlAsync(string address, bool authenticated) { - if (ClientOptions.Environment.EnvironmentName == "UnitTesting") + if (ClientOptions.Environment.Name == "UnitTesting") return new CallResult("wss://ws-api-spot.kucoin.com"); var apiCredentials = (KucoinApiCredentials?)(ApiOptions.ApiCredentials ?? _baseClient.ClientOptions.ApiCredentials ?? KucoinSocketOptions.Default.ApiCredentials ?? KucoinRestOptions.Default.ApiCredentials); diff --git a/Kucoin.Net/Clients/KucoinRestClient.cs b/Kucoin.Net/Clients/KucoinRestClient.cs index 95653e7b..06be630a 100644 --- a/Kucoin.Net/Clients/KucoinRestClient.cs +++ b/Kucoin.Net/Clients/KucoinRestClient.cs @@ -8,6 +8,7 @@ using Kucoin.Net.Objects.Options; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using System; using System.Net.Http; @@ -26,25 +27,23 @@ public class KucoinRestClient : BaseRestClient, IKucoinRestClient /// Create a new instance of KucoinClient /// /// Option configuration delegate - public KucoinRestClient(Action? optionsDelegate = null) : this(null, null, optionsDelegate) + public KucoinRestClient(Action? optionsDelegate = null) + : this(null, null, Options.Create(ApplyOptionsDelegate(optionsDelegate))) { } /// /// Create a new instance of KucoinClient /// - /// Option configuration delegate + /// Option configuration /// The logger factory /// Http client for this client - public KucoinRestClient(HttpClient? httpClient, ILoggerFactory? loggerFactory, Action? optionsDelegate = null) : base(loggerFactory, "Kucoin") + public KucoinRestClient(HttpClient? httpClient, ILoggerFactory? loggerFactory, IOptions options) : base(loggerFactory, "Kucoin") { - var options = KucoinRestOptions.Default.Copy(); - if (optionsDelegate != null) - optionsDelegate(options); - Initialize(options); + Initialize(options.Value); - SpotApi = AddApiClient(new KucoinRestClientSpotApi(_logger, httpClient, this, options)); - FuturesApi = AddApiClient(new KucoinRestClientFuturesApi(_logger, httpClient, this, options)); + SpotApi = AddApiClient(new KucoinRestClientSpotApi(_logger, httpClient, this, options.Value)); + FuturesApi = AddApiClient(new KucoinRestClientFuturesApi(_logger, httpClient, this, options.Value)); } /// @@ -60,9 +59,7 @@ public void SetApiCredentials(KucoinApiCredentials credentials) /// Option configuration delegate public static void SetDefaultOptions(Action optionsFunc) { - var options = KucoinRestOptions.Default.Copy(); - optionsFunc(options); - KucoinRestOptions.Default = options; + KucoinRestOptions.Default = ApplyOptionsDelegate(optionsFunc); } } } diff --git a/Kucoin.Net/Clients/KucoinSocketClient.cs b/Kucoin.Net/Clients/KucoinSocketClient.cs index 39d8c0d7..7e66894a 100644 --- a/Kucoin.Net/Clients/KucoinSocketClient.cs +++ b/Kucoin.Net/Clients/KucoinSocketClient.cs @@ -9,6 +9,7 @@ using Kucoin.Net.Objects.Options; using Microsoft.Extensions.DependencyInjection; using CryptoExchange.Net.Clients; +using Microsoft.Extensions.Options; namespace Kucoin.Net.Clients { @@ -23,37 +24,28 @@ public class KucoinSocketClient : BaseSocketClient, IKucoinSocketClient public IKucoinSocketClientFuturesApi FuturesApi { get; } #endregion - /// - /// Create a new instance of the OKXSocketClient - /// - /// The logger - public KucoinSocketClient(ILoggerFactory? loggerFactory = null) : this((x) => { }, loggerFactory) - { - } /// /// Create a new instance of KucoinSocketClient /// /// Option configuration delegate - public KucoinSocketClient(Action optionsDelegate) : this(optionsDelegate, null) + public KucoinSocketClient(Action? optionsDelegate = null) + : this(Options.Create(ApplyOptionsDelegate(optionsDelegate)), null) { } /// /// Create a new instance of KucoinSocketClient /// - /// Option configuration delegate + /// Option configuration /// The logger factory [ActivatorUtilitiesConstructor] - public KucoinSocketClient(Action? optionsDelegate, ILoggerFactory? loggerFactory = null) : base(loggerFactory, "Kucoin") + public KucoinSocketClient(IOptions options, ILoggerFactory? loggerFactory = null) : base(loggerFactory, "Kucoin") { - var options = KucoinSocketOptions.Default.Copy(); - if (optionsDelegate != null) - optionsDelegate(options); - Initialize(options); + Initialize(options.Value); - SpotApi = AddApiClient(new KucoinSocketClientSpotApi(_logger, this, options)); - FuturesApi = AddApiClient(new KucoinSocketClientFuturesApi(_logger, this, options)); + SpotApi = AddApiClient(new KucoinSocketClientSpotApi(_logger, this, options.Value)); + FuturesApi = AddApiClient(new KucoinSocketClientFuturesApi(_logger, this, options.Value)); } /// @@ -62,9 +54,7 @@ public KucoinSocketClient(Action? optionsDelegate, ILoggerF /// Option configuration delegate public static void SetDefaultOptions(Action optionsDelegate) { - var options = KucoinSocketOptions.Default.Copy(); - optionsDelegate(options); - KucoinSocketOptions.Default = options; + KucoinSocketOptions.Default = ApplyOptionsDelegate(optionsDelegate); } /// diff --git a/Kucoin.Net/Clients/SpotApi/KucoinSocketClientSpotApi.cs b/Kucoin.Net/Clients/SpotApi/KucoinSocketClientSpotApi.cs index cd0203f5..29576285 100644 --- a/Kucoin.Net/Clients/SpotApi/KucoinSocketClientSpotApi.cs +++ b/Kucoin.Net/Clients/SpotApi/KucoinSocketClientSpotApi.cs @@ -258,7 +258,7 @@ public async Task> SubscribeToMarginOrderUpdatesA /// protected override async Task> GetConnectionUrlAsync(string address, bool authenticated) { - if (ClientOptions.Environment.EnvironmentName == "UnitTesting") + if (ClientOptions.Environment.Name == "UnitTesting") return new CallResult("wss://ws-api-spot.kucoin.com"); var apiCredentials = (KucoinApiCredentials?)(ApiOptions.ApiCredentials ?? _baseClient.ClientOptions.ApiCredentials); diff --git a/Kucoin.Net/ExtensionMethods/ServiceCollectionExtensions.cs b/Kucoin.Net/ExtensionMethods/ServiceCollectionExtensions.cs index 158fa64e..b63aaed0 100644 --- a/Kucoin.Net/ExtensionMethods/ServiceCollectionExtensions.cs +++ b/Kucoin.Net/ExtensionMethods/ServiceCollectionExtensions.cs @@ -7,6 +7,9 @@ using Kucoin.Net.Interfaces.Clients; using Kucoin.Net.Objects.Options; using Kucoin.Net.SymbolOrderBooks; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using System; using System.Net; using System.Net.Http; @@ -19,45 +22,112 @@ namespace Microsoft.Extensions.DependencyInjection public static class ServiceCollectionExtensions { /// - /// Add the IKucoinClient and IKucoinSocketClient to the sevice collection so they can be injected + /// Add services such as the IKucoinRestClient and IKucoinSocketClient. Configures the services based on the provided configuration. /// /// The service collection - /// Set default options for the rest client - /// Set default options for the socket client - /// The lifetime of the IKucoinSocketClient for the service collection. Defaults to Singleton. + /// The configuration(section) containing the options /// public static IServiceCollection AddKucoin( this IServiceCollection services, - Action? defaultRestOptionsDelegate = null, - Action? defaultSocketOptionsDelegate = null, - ServiceLifetime? socketClientLifeTime = null) + IConfiguration configuration) { - var restOptions = KucoinRestOptions.Default.Copy(); + var options = new KucoinOptions(); + // Reset environment so we know if theyre overriden + options.Rest.Environment = null!; + options.Socket.Environment = null!; + configuration.Bind(options); - if (defaultRestOptionsDelegate != null) - { - defaultRestOptionsDelegate(restOptions); - KucoinRestClient.SetDefaultOptions(defaultRestOptionsDelegate); - } + if (options.Rest == null || options.Socket == null) + throw new ArgumentException("Options null"); + + var restEnvName = options.Rest.Environment?.Name ?? options.Environment?.Name ?? KucoinEnvironment.Live.Name; + var socketEnvName = options.Socket.Environment?.Name ?? options.Environment?.Name ?? KucoinEnvironment.Live.Name; + options.Rest.Environment = KucoinEnvironment.GetEnvironmentByName(restEnvName) ?? options.Rest.Environment!; + options.Rest.ApiCredentials = options.Rest.ApiCredentials ?? options.ApiCredentials; + options.Socket.Environment = KucoinEnvironment.GetEnvironmentByName(socketEnvName) ?? options.Socket.Environment!; + options.Socket.ApiCredentials = options.Socket.ApiCredentials ?? options.ApiCredentials; - if (defaultSocketOptionsDelegate != null) - KucoinSocketClient.SetDefaultOptions(defaultSocketOptionsDelegate); - services.AddHttpClient(options => + services.AddSingleton(x => Options.Options.Create(options.Rest)); + services.AddSingleton(x => Options.Options.Create(options.Socket)); + + return AddKucoinCore(services, options.SocketClientLifeTime); + } + + /// + /// Add services such as the IKucoinRestClient and IKucoinSocketClient. Services will be configured based on the provided options. + /// + /// The service collection + /// Set options for the Kucoin services + /// + public static IServiceCollection AddKucoin( + this IServiceCollection services, + Action? optionsDelegate = null) + { + var options = new KucoinOptions(); + // Reset environment so we know if theyre overriden + options.Rest.Environment = null!; + options.Socket.Environment = null!; + optionsDelegate?.Invoke(options); + if (options.Rest == null || options.Socket == null) + throw new ArgumentException("Options null"); + + options.Rest.Environment = options.Rest.Environment ?? options.Environment ?? KucoinEnvironment.Live; + options.Rest.ApiCredentials = options.Rest.ApiCredentials ?? options.ApiCredentials; + options.Socket.Environment = options.Socket.Environment ?? options.Environment ?? KucoinEnvironment.Live; + options.Socket.ApiCredentials = options.Socket.ApiCredentials ?? options.ApiCredentials; + + services.AddSingleton(x => Options.Options.Create(options.Rest)); + services.AddSingleton(x => Options.Options.Create(options.Socket)); + + return AddKucoinCore(services, options.SocketClientLifeTime); + } + + /// + /// DEPRECATED; use instead + /// + public static IServiceCollection AddKucoin( + this IServiceCollection services, + Action restDelegate, + Action? socketDelegate = null, + ServiceLifetime? socketClientLifeTime = null) + { + services.Configure((x) => { restDelegate?.Invoke(x); }); + services.Configure((x) => { socketDelegate?.Invoke(x); }); + + return AddKucoinCore(services, socketClientLifeTime); + } + + private static IServiceCollection AddKucoinCore( + this IServiceCollection services, + ServiceLifetime? socketClientLifeTime = null) + { + services.AddHttpClient((client, serviceProvider) => { - options.Timeout = restOptions.RequestTimeout; - }).ConfigurePrimaryHttpMessageHandler(() => { + var options = serviceProvider.GetRequiredService>().Value; + client.Timeout = options.RequestTimeout; + return new KucoinRestClient(client, serviceProvider.GetRequiredService(), serviceProvider.GetRequiredService>()); + }).ConfigurePrimaryHttpMessageHandler((serviceProvider) => { var handler = new HttpClientHandler(); - if (restOptions.Proxy != null) + try + { + handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; + } + catch (PlatformNotSupportedException) + { } + + var options = serviceProvider.GetRequiredService>().Value; + if (options.Proxy != null) { handler.Proxy = new WebProxy { - Address = new Uri($"{restOptions.Proxy.Host}:{restOptions.Proxy.Port}"), - Credentials = restOptions.Proxy.Password == null ? null : new NetworkCredential(restOptions.Proxy.Login, restOptions.Proxy.Password) + Address = new Uri($"{options.Proxy.Host}:{options.Proxy.Port}"), + Credentials = options.Proxy.Password == null ? null : new NetworkCredential(options.Proxy.Login, options.Proxy.Password) }; } return handler; }); + services.Add(new ServiceDescriptor(typeof(IKucoinSocketClient), x => { return new KucoinSocketClient(x.GetRequiredService>(), x.GetRequiredService()); }, socketClientLifeTime ?? ServiceLifetime.Singleton)); services.AddTransient(); services.AddTransient(); @@ -71,10 +141,6 @@ public static IServiceCollection AddKucoin( services.RegisterSharedRestInterfaces(x => x.GetRequiredService().FuturesApi.SharedClient); services.RegisterSharedSocketInterfaces(x => x.GetRequiredService().FuturesApi.SharedClient); - if (socketClientLifeTime == null) - services.AddSingleton(); - else - services.Add(new ServiceDescriptor(typeof(IKucoinSocketClient), typeof(KucoinSocketClient), socketClientLifeTime.Value)); return services; } } diff --git a/Kucoin.Net/Kucoin.Net.csproj b/Kucoin.Net/Kucoin.Net.csproj index a1068f74..80a26fa7 100644 --- a/Kucoin.Net/Kucoin.Net.csproj +++ b/Kucoin.Net/Kucoin.Net.csproj @@ -49,10 +49,12 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - all runtime; build; native; contentfiles; analyzers; buildtransitive + + + \ No newline at end of file diff --git a/Kucoin.Net/Kucoin.Net.xml b/Kucoin.Net/Kucoin.Net.xml index 99d452e8..91922561 100644 --- a/Kucoin.Net/Kucoin.Net.xml +++ b/Kucoin.Net/Kucoin.Net.xml @@ -337,11 +337,11 @@ Option configuration delegate - + Create a new instance of KucoinClient - Option configuration delegate + Option configuration The logger factory Http client for this client @@ -363,23 +363,17 @@ - - - Create a new instance of the OKXSocketClient - - The logger - Create a new instance of KucoinSocketClient Option configuration delegate - + Create a new instance of KucoinSocketClient - Option configuration delegate + Option configuration The logger factory @@ -5339,6 +5333,16 @@ Futures API address + + + ctor for DI, use for creating a custom environment + + + + + Get the Kucoin environment by name + + Live environment @@ -5473,11 +5477,11 @@ Creates new api credentials. Keep this information safe. - The API key - The API secret - The API passPhrase + The API key + The API secret + The API passPhrase - + Create Api credentials providing a stream containing json data. The json data should include three values: apiKey, apiSecret and apiPassPhrase @@ -12486,6 +12490,36 @@ The symbol + + + Kucoin options + + + + + Rest client options + + + + + Socket client options + + + + + Trade environment. Contains info about URL's to use to connect to the API. Use `KucoinEnvironment` to swap environment, for example `Environment = KucoinEnvironment.Live` + + + + + The api credentials used for signing requests. + + + + + The DI service lifetime for the IKucoinSocketClient + + Options for the Kucoin SymbolOrderBook @@ -12534,6 +12568,11 @@ Default options for new clients + + + ctor + + Spot API options @@ -12554,6 +12593,11 @@ Default options for new clients + + + ctor + + Spot API options @@ -12690,15 +12734,26 @@ Extensions for DI - + - Add the IKucoinClient and IKucoinSocketClient to the sevice collection so they can be injected + Add services such as the IKucoinRestClient and IKucoinSocketClient. Configures the services based on the provided configuration. The service collection - Set default options for the rest client - Set default options for the socket client - The lifetime of the IKucoinSocketClient for the service collection. Defaults to Singleton. + The configuration(section) containing the options + + + Add services such as the IKucoinRestClient and IKucoinSocketClient. Services will be configured based on the provided options. + + The service collection + Set options for the Kucoin services + + + + + DEPRECATED; use instead + + diff --git a/Kucoin.Net/KucoinEnvironment.cs b/Kucoin.Net/KucoinEnvironment.cs index 48a44862..c00a533b 100644 --- a/Kucoin.Net/KucoinEnvironment.cs +++ b/Kucoin.Net/KucoinEnvironment.cs @@ -25,6 +25,27 @@ internal KucoinEnvironment(string name, string spotAddress, string futuresAddres FuturesAddress = futuresAddress; } + /// + /// ctor for DI, use for creating a custom environment + /// +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable. + public KucoinEnvironment() : base(TradeEnvironmentNames.Live) +#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable. + { } + + /// + /// Get the Kucoin environment by name + /// + public static KucoinEnvironment? GetEnvironmentByName(string? name) + => name switch + { + TradeEnvironmentNames.Live => Live, + TradeEnvironmentNames.Testnet => Testnet, + "" => Live, + null => Live, + _ => default + }; + /// /// Live environment /// diff --git a/Kucoin.Net/Objects/KucoinApiCredentials.cs b/Kucoin.Net/Objects/KucoinApiCredentials.cs index 18c689f4..c34e4b13 100644 --- a/Kucoin.Net/Objects/KucoinApiCredentials.cs +++ b/Kucoin.Net/Objects/KucoinApiCredentials.cs @@ -15,17 +15,17 @@ public class KucoinApiCredentials : ApiCredentials /// /// The pass phrase /// - public string PassPhrase { get; } + public string PassPhrase { get; set; } /// /// Creates new api credentials. Keep this information safe. /// - /// The API key - /// The API secret - /// The API passPhrase - public KucoinApiCredentials(string apiKey, string apiSecret, string apiPassPhrase): base(apiKey, apiSecret) + /// The API key + /// The API secret + /// The API passPhrase + public KucoinApiCredentials(string key, string secret, string passPhrase): base(key, secret) { - PassPhrase = apiPassPhrase; + PassPhrase = passPhrase; } /// @@ -35,14 +35,19 @@ public KucoinApiCredentials(string apiKey, string apiSecret, string apiPassPhras /// A key to identify the credentials for the API. For example, when set to `binanceKey` the json data should contain a value for the property `binanceKey`. Defaults to 'apiKey'. /// A key to identify the credentials for the API. For example, when set to `binanceSecret` the json data should contain a value for the property `binanceSecret`. Defaults to 'apiSecret'. /// A key to identify the credentials for the API. For example, when set to `kucoinPass` the json data should contain a value for the property `kucoinPass`. Defaults to 'apiPassPhrase'. - public KucoinApiCredentials(Stream inputStream, string? identifierKey = null, string? identifierSecret = null, string? identifierPassPhrase = null) : base(inputStream, identifierKey, identifierSecret) + public static KucoinApiCredentials FromStream(Stream inputStream, string? identifierKey = null, string? identifierSecret = null, string? identifierPassPhrase = null) { var accessor = new JsonNetStreamMessageAccessor(); if (!accessor.Read(inputStream, false).Result) throw new ArgumentException("Input stream not valid json data"); - var pass = accessor.GetValue(MessagePath.Get().Property(identifierPassPhrase ?? "apiPassPhrase")) ?? throw new ArgumentException("apiKey or apiSecret value not found in Json credential file"); - PassPhrase = pass; + var key = accessor.GetValue(MessagePath.Get().Property(identifierKey ?? "apiKey")); + var secret = accessor.GetValue(MessagePath.Get().Property(identifierSecret ?? "apiSecret")); + var pass = accessor.GetValue(MessagePath.Get().Property(identifierPassPhrase ?? "apiPassPhrase")); + if (key == null || secret == null || pass == null) + throw new ArgumentException("apiKey or apiSecret value not found in Json credential file"); + + return new KucoinApiCredentials(key, secret, pass); } /// diff --git a/Kucoin.Net/Objects/Options/KucoinOptions.cs b/Kucoin.Net/Objects/Options/KucoinOptions.cs new file mode 100644 index 00000000..d3ca1a21 --- /dev/null +++ b/Kucoin.Net/Objects/Options/KucoinOptions.cs @@ -0,0 +1,39 @@ +using CryptoExchange.Net.Authentication; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Kucoin.Net.Objects.Options +{ + /// + /// Kucoin options + /// + public class KucoinOptions + { + /// + /// Rest client options + /// + public KucoinRestOptions Rest { get; set; } = new KucoinRestOptions(); + + /// + /// Socket client options + /// + public KucoinSocketOptions Socket { get; set; } = new KucoinSocketOptions(); + + /// + /// Trade environment. Contains info about URL's to use to connect to the API. Use `KucoinEnvironment` to swap environment, for example `Environment = KucoinEnvironment.Live` + /// + public KucoinEnvironment? Environment { get; set; } + + /// + /// The api credentials used for signing requests. + /// + public KucoinApiCredentials? ApiCredentials { get; set; } + + /// + /// The DI service lifetime for the IKucoinSocketClient + /// + public ServiceLifetime? SocketClientLifeTime { get; set; } + } +} diff --git a/Kucoin.Net/Objects/Options/KucoinRestApiOptions.cs b/Kucoin.Net/Objects/Options/KucoinRestApiOptions.cs index 4def01da..4614d6d8 100644 --- a/Kucoin.Net/Objects/Options/KucoinRestApiOptions.cs +++ b/Kucoin.Net/Objects/Options/KucoinRestApiOptions.cs @@ -15,12 +15,12 @@ public class KucoinRestApiOptions : RestApiOptions /// public string? BrokerKey { get; set; } - internal KucoinRestApiOptions Copy() + internal KucoinRestApiOptions Set(KucoinRestApiOptions targetOptions) { - var result = base.Copy(); - result.BrokerKey = BrokerKey; - result.BrokerName = BrokerName; - return result; + targetOptions = base.Set(targetOptions); + targetOptions.BrokerName = BrokerName; + targetOptions.BrokerKey = BrokerKey; + return targetOptions; } } } diff --git a/Kucoin.Net/Objects/Options/KucoinRestOptions.cs b/Kucoin.Net/Objects/Options/KucoinRestOptions.cs index 0caeef29..28b87703 100644 --- a/Kucoin.Net/Objects/Options/KucoinRestOptions.cs +++ b/Kucoin.Net/Objects/Options/KucoinRestOptions.cs @@ -14,11 +14,19 @@ public class KucoinRestOptions : RestExchangeOptions /// Default options for new clients /// - public static KucoinRestOptions Default { get; set; } = new KucoinRestOptions() + internal static KucoinRestOptions Default { get; set; } = new KucoinRestOptions() { Environment = KucoinEnvironment.Live }; + /// + /// ctor + /// + public KucoinRestOptions() + { + Default?.Set(this); + } + /// /// Spot API options /// @@ -29,12 +37,12 @@ public class KucoinRestOptions : RestExchangeOptions public KucoinRestApiOptions FuturesOptions { get; private set; } = new KucoinRestApiOptions(); - internal KucoinRestOptions Copy() + internal KucoinRestOptions Set(KucoinRestOptions targetOptions) { - var options = Copy(); - options.SpotOptions = SpotOptions.Copy(); - options.FuturesOptions = FuturesOptions.Copy(); - return options; + targetOptions = base.Set(targetOptions); + targetOptions.SpotOptions = SpotOptions.Set(targetOptions.SpotOptions); + targetOptions.FuturesOptions = FuturesOptions.Set(targetOptions.FuturesOptions); + return targetOptions; } } } diff --git a/Kucoin.Net/Objects/Options/KucoinSocketOptions.cs b/Kucoin.Net/Objects/Options/KucoinSocketOptions.cs index 88fee234..65b8644c 100644 --- a/Kucoin.Net/Objects/Options/KucoinSocketOptions.cs +++ b/Kucoin.Net/Objects/Options/KucoinSocketOptions.cs @@ -10,12 +10,20 @@ public class KucoinSocketOptions : SocketExchangeOptions /// Default options for new clients /// - public static KucoinSocketOptions Default { get; set; } = new KucoinSocketOptions() + internal static KucoinSocketOptions Default { get; set; } = new KucoinSocketOptions() { Environment = KucoinEnvironment.Live, SocketSubscriptionsCombineTarget = 10 }; + /// + /// ctor + /// + public KucoinSocketOptions() + { + Default?.Set(this); + } + /// /// Spot API options /// @@ -32,12 +40,12 @@ public class KucoinSocketOptions : SocketExchangeOptions(); - options.SpotOptions = SpotOptions.Copy>(); - options.FuturesOptions = FuturesOptions.Copy>(); - return options; + targetOptions = base.Set(targetOptions); + targetOptions.SpotOptions = SpotOptions.Set(targetOptions.SpotOptions); + targetOptions.FuturesOptions = FuturesOptions.Set(targetOptions.FuturesOptions); + return targetOptions; } } } From 6a45b0f46ee12cc3048afd82e7af35abef444d46 Mon Sep 17 00:00:00 2001 From: Jkorf Date: Tue, 19 Nov 2024 13:00:03 +0100 Subject: [PATCH 2/2] updated CryptoExchange ref --- Kucoin.Net/Kucoin.Net.csproj | 6 ++---- Kucoin.Net/Kucoin.Net.xml | 10 ++++++++++ Kucoin.Net/KucoinExchange.cs | 10 ++++++++++ docs/index.html | 10 ++++++++-- 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/Kucoin.Net/Kucoin.Net.csproj b/Kucoin.Net/Kucoin.Net.csproj index 80a26fa7..b5d5404b 100644 --- a/Kucoin.Net/Kucoin.Net.csproj +++ b/Kucoin.Net/Kucoin.Net.csproj @@ -1,4 +1,4 @@ - + netstandard2.0;netstandard2.1 10.0 @@ -49,12 +49,10 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - \ No newline at end of file diff --git a/Kucoin.Net/Kucoin.Net.xml b/Kucoin.Net/Kucoin.Net.xml index 91922561..35bf6496 100644 --- a/Kucoin.Net/Kucoin.Net.xml +++ b/Kucoin.Net/Kucoin.Net.xml @@ -5372,6 +5372,16 @@ Exchange name + + + Exchange name + + + + + Url to exchange image + + Url to the main website diff --git a/Kucoin.Net/KucoinExchange.cs b/Kucoin.Net/KucoinExchange.cs index 3e239957..19675f2d 100644 --- a/Kucoin.Net/KucoinExchange.cs +++ b/Kucoin.Net/KucoinExchange.cs @@ -22,6 +22,16 @@ public static class KucoinExchange /// public static string ExchangeName => "Kucoin"; + /// + /// Exchange name + /// + public static string DisplayName => "Kucoin"; + + /// + /// Url to exchange image + /// + public static string ImageUrl { get; } = "https://raw.githubusercontent.com/JKorf/Kucoin.Net/master/Kucoin.Net/Icon/icon.png"; + /// /// Url to the main website /// diff --git a/docs/index.html b/docs/index.html index 8d01ba25..249db536 100644 --- a/docs/index.html +++ b/docs/index.html @@ -190,8 +190,14 @@

API Access

Kucoin.Net can be configured using Dotnet dependency injection, after which the clients can be injected into your services. It also correctly configures logging and HttpClient usage.

-
builder.Services.AddKucoin(options => {
-  // Options can be configured here, for example:
+		  
// Configure options from config file
+// see https://github.com/JKorf/CryptoExchange.Net/tree/master/Examples/example-config.json for an example
+builder.Services.AddKucoin(builder.Configuration.GetSection("Kucoin"));
+		  
+// OR
+		  
+ builder.Services.AddKucoin(options => {
+  // Configure options in code
   options.ApiCredentials = new KucoinApiCredentials("APIKEY", "APISECRET", "PASS");
 });