From 7d4ba156b2123bb4fb8bc0da3cd6f95bc208412c Mon Sep 17 00:00:00 2001 From: Jan Korf Date: Tue, 19 Nov 2024 13:19:46 +0100 Subject: [PATCH] Client Configuration (#59) Updated CryptoExchange.Net to version 8.3.0 Added support for loading client settings from IConfiguration Added DI registration method for configuring Rest and Socket options at the same time Added DisplayName and ImageUrl properties to OKXExchange class Updated client constructors to accept IOptions from DI Removed redundant OKXSocketClient constructor --- OKX.Net.UnitTests/OKXRestIntegrationTests.cs | 10 +- OKX.Net.UnitTests/OXKRestClientTests.cs | 106 ++++++++++++++++ OKX.Net/Clients/OKXRestClient.cs | 19 ++- OKX.Net/Clients/OKXSocketClient.cs | 25 ++-- .../UnifiedApi/OKXRestClientUnifiedApi.cs | 2 +- .../UnifiedApi/OKXSocketClientUnifiedApi.cs | 2 +- .../ServiceCollectionExtensions.cs | 118 ++++++++++++++---- OKX.Net/OKX.Net.csproj | 4 +- OKX.Net/OKX.Net.xml | 101 ++++++++++++--- OKX.Net/OKXEnvironment.cs | 21 ++++ OKX.Net/OKXExchange.cs | 10 ++ OKX.Net/Objects/OKXApiCredentials.cs | 12 +- OKX.Net/Objects/Options/OKXOptions.cs | 36 ++++++ OKX.Net/Objects/Options/OKXRestOptions.cs | 22 ++-- OKX.Net/Objects/Options/OKXSocketOptions.cs | 20 ++- docs/index.html | 14 ++- 16 files changed, 419 insertions(+), 103 deletions(-) create mode 100644 OKX.Net/Objects/Options/OKXOptions.cs diff --git a/OKX.Net.UnitTests/OKXRestIntegrationTests.cs b/OKX.Net.UnitTests/OKXRestIntegrationTests.cs index 86e3373..8da16d0 100644 --- a/OKX.Net.UnitTests/OKXRestIntegrationTests.cs +++ b/OKX.Net.UnitTests/OKXRestIntegrationTests.cs @@ -9,6 +9,8 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using Microsoft.Extensions.Options; +using OKX.Net.Objects.Options; namespace OKX.Net.UnitTests { @@ -28,11 +30,11 @@ public override OKXRestClient GetClient(ILoggerFactory loggerFactory) var pass = Environment.GetEnvironmentVariable("APIPASS"); Authenticated = key != null && sec != null; - return new OKXRestClient(null, loggerFactory, opts => + return new OKXRestClient(null, loggerFactory, Options.Create(new OKXRestOptions { - opts.OutputOriginalData = true; - opts.ApiCredentials = Authenticated ? new OKXApiCredentials(key, sec, pass) : null; - }); + OutputOriginalData = true, + ApiCredentials = Authenticated ? new OKXApiCredentials(key, sec, pass) : null + })); } [Test] diff --git a/OKX.Net.UnitTests/OXKRestClientTests.cs b/OKX.Net.UnitTests/OXKRestClientTests.cs index ab68930..79ed4a1 100644 --- a/OKX.Net.UnitTests/OXKRestClientTests.cs +++ b/OKX.Net.UnitTests/OXKRestClientTests.cs @@ -5,6 +5,10 @@ using CryptoExchange.Net.Clients; using OKX.Net.Objects; using System.Text.Json; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using CryptoExchange.Net.Objects; +using OKX.Net.Interfaces.Clients; namespace OKX.Net.UnitTests { @@ -101,5 +105,107 @@ public void CheckInterfaces() CryptoExchange.Net.Testing.TestHelpers.CheckForMissingRestInterfaces(); CryptoExchange.Net.Testing.TestHelpers.CheckForMissingSocketInterfaces(); } + + + [Test] + [TestCase(TradeEnvironmentNames.Live, "https://www.okx.com")] + [TestCase(TradeEnvironmentNames.Testnet, "https://www.okx.com")] + [TestCase("", "https://www.okx.com")] + public void TestConstructorEnvironments(string environmentName, string expected) + { + var configuration = new ConfigurationBuilder() + .AddInMemoryCollection(new Dictionary + { + { "OKX:Environment:Name", environmentName }, + }).Build(); + + var collection = new ServiceCollection(); + collection.AddOKX(configuration.GetSection("OKX")); + var provider = collection.BuildServiceProvider(); + + var client = provider.GetRequiredService(); + + var address = client.UnifiedApi.BaseAddress; + + Assert.That(address, Is.EqualTo(expected)); + } + + [Test] + public void TestConstructorNullEnvironment() + { + var configuration = new ConfigurationBuilder() + .AddInMemoryCollection(new Dictionary + { + { "OKX", null }, + }).Build(); + + var collection = new ServiceCollection(); + collection.AddOKX(configuration.GetSection("OKX")); + var provider = collection.BuildServiceProvider(); + + var client = provider.GetRequiredService(); + + var address = client.UnifiedApi.BaseAddress; + + Assert.That(address, Is.EqualTo("https://www.okx.com")); + } + + [Test] + public void TestConstructorApiOverwriteEnvironment() + { + var configuration = new ConfigurationBuilder() + .AddInMemoryCollection(new Dictionary + { + { "OKX:Environment:Name", "test" }, + { "OKX:Rest:Environment:Name", "live" }, + }).Build(); + + var collection = new ServiceCollection(); + collection.AddOKX(configuration.GetSection("OKX")); + var provider = collection.BuildServiceProvider(); + + var client = provider.GetRequiredService(); + + var address = client.UnifiedApi.BaseAddress; + + Assert.That(address, Is.EqualTo("https://www.okx.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.AddOKX(configuration); + var provider = collection.BuildServiceProvider(); + + var restClient = provider.GetRequiredService(); + var socketClient = provider.GetRequiredService(); + + Assert.That(((BaseApiClient)restClient.UnifiedApi).OutputOriginalData, Is.True); + Assert.That(((BaseApiClient)socketClient.UnifiedApi).OutputOriginalData, Is.False); + Assert.That(((BaseApiClient)restClient.UnifiedApi).AuthenticationProvider.ApiKey, Is.EqualTo("123")); + Assert.That(((BaseApiClient)socketClient.UnifiedApi).AuthenticationProvider.ApiKey, Is.EqualTo("456")); + Assert.That(((BaseApiClient)restClient.UnifiedApi).ClientOptions.Proxy.Host, Is.EqualTo("host")); + Assert.That(((BaseApiClient)restClient.UnifiedApi).ClientOptions.Proxy.Port, Is.EqualTo(80)); + Assert.That(((BaseApiClient)socketClient.UnifiedApi).ClientOptions.Proxy.Host, Is.EqualTo("host2")); + Assert.That(((BaseApiClient)socketClient.UnifiedApi).ClientOptions.Proxy.Port, Is.EqualTo(81)); + } } } diff --git a/OKX.Net/Clients/OKXRestClient.cs b/OKX.Net/Clients/OKXRestClient.cs index b7bcb70..85c16d6 100644 --- a/OKX.Net/Clients/OKXRestClient.cs +++ b/OKX.Net/Clients/OKXRestClient.cs @@ -1,4 +1,5 @@ using CryptoExchange.Net.Clients; +using Microsoft.Extensions.Options; using OKX.Net.Clients.UnifiedApi; using OKX.Net.Interfaces.Clients; using OKX.Net.Interfaces.Clients.UnifiedApi; @@ -22,25 +23,23 @@ public class OKXRestClient : BaseRestClient, IOKXRestClient /// Create a new instance of the OKXRestClient using provided options /// /// Option configuration delegate - public OKXRestClient(Action? optionsDelegate = null) : this(null, null, optionsDelegate) + public OKXRestClient(Action? optionsDelegate = null) + : this(null, null, Options.Create(ApplyOptionsDelegate(optionsDelegate))) { } /// /// Create a new instance of the OKXRestClient /// - /// Option configuration delegate + /// Option configuration /// The logger factory /// Http client for this client - public OKXRestClient(HttpClient? httpClient, ILoggerFactory? loggerFactory, Action? optionsDelegate = null) + public OKXRestClient(HttpClient? httpClient, ILoggerFactory? loggerFactory, IOptions options) : base(loggerFactory, "OKX") { - var options = OKXRestOptions.Default.Copy(); - if (optionsDelegate != null) - optionsDelegate(options); - Initialize(options); + Initialize(options.Value); - UnifiedApi = AddApiClient(new OKXRestClientUnifiedApi(_logger, httpClient, options)); + UnifiedApi = AddApiClient(new OKXRestClientUnifiedApi(_logger, httpClient, options.Value)); } #endregion @@ -51,9 +50,7 @@ public OKXRestClient(HttpClient? httpClient, ILoggerFactory? loggerFactory, Acti /// Callback for setting the options public static void SetDefaultOptions(Action optionsDelegate) { - var options = OKXRestOptions.Default.Copy(); - optionsDelegate(options); - OKXRestOptions.Default = options; + OKXRestOptions.Default = ApplyOptionsDelegate(optionsDelegate); } /// diff --git a/OKX.Net/Clients/OKXSocketClient.cs b/OKX.Net/Clients/OKXSocketClient.cs index b7366ea..c1b37cf 100644 --- a/OKX.Net/Clients/OKXSocketClient.cs +++ b/OKX.Net/Clients/OKXSocketClient.cs @@ -1,4 +1,5 @@ using CryptoExchange.Net.Clients; +using Microsoft.Extensions.Options; using OKX.Net.Clients.UnifiedApi; using OKX.Net.Interfaces.Clients; using OKX.Net.Interfaces.Clients.UnifiedApi; @@ -16,19 +17,13 @@ public class OKXSocketClient : BaseSocketClient, IOKXSocketClient public IOKXSocketClientUnifiedApi UnifiedApi { get; } #region ctor - /// - /// Create a new instance of the OKXSocketClient - /// - /// The logger - public OKXSocketClient(ILoggerFactory? loggerFactory = null) : this((x) => { }, loggerFactory) - { - } /// /// Create a new instance of the OKXSocketClient /// /// Option configuration delegate - public OKXSocketClient(Action optionsDelegate) : this(optionsDelegate, null) + public OKXSocketClient(Action? optionsDelegate = null) + : this(Options.Create(ApplyOptionsDelegate(optionsDelegate)), null) { } @@ -36,14 +31,12 @@ public OKXSocketClient(Action optionsDelegate) : this(optionsD /// Create a new instance of the OKXSocketClient /// /// The logger - /// Option configuration delegate - public OKXSocketClient(Action optionsDelegate, ILoggerFactory? loggerFactory = null) : base(loggerFactory, "OKX") + /// Option configuration delegate + public OKXSocketClient(IOptions options, ILoggerFactory? loggerFactory = null) : base(loggerFactory, "OKX") { - var options = OKXSocketOptions.Default.Copy(); - optionsDelegate(options); - Initialize(options); + Initialize(options.Value); - UnifiedApi = AddApiClient(new OKXSocketClientUnifiedApi(_logger, options)); + UnifiedApi = AddApiClient(new OKXSocketClientUnifiedApi(_logger, options.Value)); } #endregion @@ -54,9 +47,7 @@ public OKXSocketClient(Action optionsDelegate, ILoggerFactory? /// public static void SetDefaultOptions(Action optionsDelegate) { - var options = OKXSocketOptions.Default.Copy(); - optionsDelegate(options); - OKXSocketOptions.Default = options; + OKXSocketOptions.Default = ApplyOptionsDelegate(optionsDelegate); } /// diff --git a/OKX.Net/Clients/UnifiedApi/OKXRestClientUnifiedApi.cs b/OKX.Net/Clients/UnifiedApi/OKXRestClientUnifiedApi.cs index 25312fd..e453459 100644 --- a/OKX.Net/Clients/UnifiedApi/OKXRestClientUnifiedApi.cs +++ b/OKX.Net/Clients/UnifiedApi/OKXRestClientUnifiedApi.cs @@ -40,7 +40,7 @@ internal OKXRestClientUnifiedApi(ILogger logger, HttpClient? httpClient, OKXRest _ref = !string.IsNullOrEmpty(options.BrokerId) ? options.BrokerId! : "1425d83a94fbBCDE"; - if (options.Environment.EnvironmentName == TradeEnvironmentNames.Testnet) + if (options.Environment.Name == TradeEnvironmentNames.Testnet) { StandardRequestHeaders = new Dictionary { diff --git a/OKX.Net/Clients/UnifiedApi/OKXSocketClientUnifiedApi.cs b/OKX.Net/Clients/UnifiedApi/OKXSocketClientUnifiedApi.cs index b8bf8da..12b7f58 100644 --- a/OKX.Net/Clients/UnifiedApi/OKXSocketClientUnifiedApi.cs +++ b/OKX.Net/Clients/UnifiedApi/OKXSocketClientUnifiedApi.cs @@ -45,7 +45,7 @@ internal OKXSocketClientUnifiedApi(ILogger logger, OKXSocketOptions options) : _ref = !string.IsNullOrEmpty(options.BrokerId) ? options.BrokerId! : "078ee129065aBCDE"; - _demoTrading = options.Environment.EnvironmentName == TradeEnvironmentNames.Testnet; + _demoTrading = options.Environment.Name == TradeEnvironmentNames.Testnet; RegisterPeriodicQuery("Ping", TimeSpan.FromSeconds(20), x => new OKXPingQuery(), null); diff --git a/OKX.Net/ExtensionMethods/ServiceCollectionExtensions.cs b/OKX.Net/ExtensionMethods/ServiceCollectionExtensions.cs index 6925669..7872f5e 100644 --- a/OKX.Net/ExtensionMethods/ServiceCollectionExtensions.cs +++ b/OKX.Net/ExtensionMethods/ServiceCollectionExtensions.cs @@ -1,4 +1,6 @@ using CryptoExchange.Net.Clients; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Options; using OKX.Net; using OKX.Net.Clients; using OKX.Net.Interfaces; @@ -14,47 +16,115 @@ namespace Microsoft.Extensions.DependencyInjection /// public static class ServiceCollectionExtensions { + /// - /// Add the IOKXRestClient and IOKXSocketClient to the sevice collection so they can be injected + /// Add services such as the IOKXRestClient and IOKXSocketClient. 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 IOKXSocketClient for the service collection. Defaults to Singleton. + /// The configuration(section) containing the options /// public static IServiceCollection AddOKX( this IServiceCollection services, - Action? defaultRestOptionsDelegate = null, - Action? defaultSocketOptionsDelegate = null, - ServiceLifetime? socketClientLifeTime = null) + IConfiguration configuration) { - var restOptions = OKXRestOptions.Default.Copy(); + var options = new OKXOptions(); + // Reset environment so we know if theyre overriden + options.Rest.Environment = null!; + options.Socket.Environment = null!; + configuration.Bind(options); - if (defaultRestOptionsDelegate != null) - { - defaultRestOptionsDelegate(restOptions); - OKXRestClient.SetDefaultOptions(defaultRestOptionsDelegate); - } + if (options.Rest == null || options.Socket == null) + throw new ArgumentException("Options null"); - if (defaultSocketOptionsDelegate != null) - OKXSocketClient.SetDefaultOptions(defaultSocketOptionsDelegate); + var restEnvName = options.Rest.Environment?.Name ?? options.Environment?.Name ?? OKXEnvironment.Live.Name; + var socketEnvName = options.Socket.Environment?.Name ?? options.Environment?.Name ?? OKXEnvironment.Live.Name; + options.Rest.Environment = OKXEnvironment.GetEnvironmentByName(restEnvName) ?? options.Rest.Environment!; + options.Rest.ApiCredentials = options.Rest.ApiCredentials ?? options.ApiCredentials; + options.Socket.Environment = OKXEnvironment.GetEnvironmentByName(socketEnvName) ?? options.Socket.Environment!; + options.Socket.ApiCredentials = options.Socket.ApiCredentials ?? options.ApiCredentials; - services.AddHttpClient(options => - { - options.Timeout = restOptions.RequestTimeout; - }).ConfigurePrimaryHttpMessageHandler(() => + + services.AddSingleton(x => Options.Options.Create(options.Rest)); + services.AddSingleton(x => Options.Options.Create(options.Socket)); + + return AddOKXCore(services, options.SocketClientLifeTime); + } + + /// + /// Add services such as the IOKXRestClient and IOKXSocketClient. Services will be configured based on the provided options. + /// + /// The service collection + /// Set options for the OKX services + /// + public static IServiceCollection AddOKX( + this IServiceCollection services, + Action? optionsDelegate = null) + { + var options = new OKXOptions(); + // 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 ?? OKXEnvironment.Live; + options.Rest.ApiCredentials = options.Rest.ApiCredentials ?? options.ApiCredentials; + options.Socket.Environment = options.Socket.Environment ?? options.Environment ?? OKXEnvironment.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 AddOKXCore(services, options.SocketClientLifeTime); + } + + /// + /// DEPRECATED; use instead + /// + public static IServiceCollection AddOKX( + this IServiceCollection services, + Action restDelegate, + Action? socketDelegate = null, + ServiceLifetime? socketClientLifeTime = null) + { + services.Configure((x) => { restDelegate?.Invoke(x); }); + services.Configure((x) => { socketDelegate?.Invoke(x); }); + + return AddOKXCore(services, socketClientLifeTime); + } + + private static IServiceCollection AddOKXCore( + this IServiceCollection services, + ServiceLifetime? socketClientLifeTime = null) + { + services.AddHttpClient((client, serviceProvider) => { + var options = serviceProvider.GetRequiredService>().Value; + client.Timeout = options.RequestTimeout; + return new OKXRestClient(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(IOKXSocketClient), x => { return new OKXSocketClient(x.GetRequiredService>(), x.GetRequiredService()); }, socketClientLifeTime ?? ServiceLifetime.Singleton)); + services.AddTransient(); services.AddTransient(); @@ -65,10 +135,6 @@ public static IServiceCollection AddOKX( services.RegisterSharedRestInterfaces(x => x.GetRequiredService().UnifiedApi.SharedClient); services.RegisterSharedSocketInterfaces(x => x.GetRequiredService().UnifiedApi.SharedClient); - if (socketClientLifeTime == null) - services.AddSingleton(); - else - services.Add(new ServiceDescriptor(typeof(IOKXSocketClient), typeof(OKXSocketClient), socketClientLifeTime.Value)); return services; } } diff --git a/OKX.Net/OKX.Net.csproj b/OKX.Net/OKX.Net.csproj index 61268ca..1b6c7c9 100644 --- a/OKX.Net/OKX.Net.csproj +++ b/OKX.Net/OKX.Net.csproj @@ -1,4 +1,4 @@ - + netstandard2.0;netstandard2.1 latest @@ -49,7 +49,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/OKX.Net/OKX.Net.xml b/OKX.Net/OKX.Net.xml index 8600e07..48207b3 100644 --- a/OKX.Net/OKX.Net.xml +++ b/OKX.Net/OKX.Net.xml @@ -18,11 +18,11 @@ Option configuration delegate - + Create a new instance of the OKXRestClient - Option configuration delegate + Option configuration The logger factory Http client for this client @@ -46,24 +46,18 @@ Unified API endpoints - - - Create a new instance of the OKXSocketClient - - The logger - Create a new instance of the OKXSocketClient Option configuration delegate - + Create a new instance of the OKXSocketClient The logger - Option configuration delegate + Option configuration delegate @@ -6218,9 +6212,9 @@ ctor - - - + The API key + The API secret + The API passphrase @@ -6228,6 +6222,36 @@ + + + OKX options + + + + + Rest client options + + + + + Socket client options + + + + + Trade environment. Contains info about URL's to use to connect to the API. Use `OKXEnvironment` to swap environment, for example `Environment = OKXEnvironment.Live` + + + + + The api credentials used for signing requests. + + + + + The DI service lifetime for the IOKXSocketClient + + Order book options @@ -6258,6 +6282,11 @@ Default options for new OKXRestClients + + + ctor + + Whether or not to sign public requests @@ -6283,6 +6312,11 @@ Default options for new OKXRestClients + + + ctor + + Broker ID for earning rebates @@ -9125,6 +9159,16 @@ Socket API base address + + + ctor for DI, use for creating a custom environment + + + + + Get the OKX environment by name + + Live environment @@ -9154,6 +9198,16 @@ Exchange name + + + Exchange name + + + + + Url to exchange image + + Url to the main website @@ -9286,15 +9340,26 @@ Extensions for DI - + + + Add services such as the IOKXRestClient and IOKXSocketClient. Configures the services based on the provided configuration. + + The service collection + The configuration(section) containing the options + + + - Add the IOKXRestClient and IOKXSocketClient to the sevice collection so they can be injected + Add services such as the IOKXRestClient and IOKXSocketClient. Services will be configured based on the provided options. The service collection - Set default options for the rest client - Set default options for the socket client - The lifetime of the IOKXSocketClient for the service collection. Defaults to Singleton. + Set options for the OKX services + + + DEPRECATED; use instead + + diff --git a/OKX.Net/OKXEnvironment.cs b/OKX.Net/OKXEnvironment.cs index 48e48fc..59eedb0 100644 --- a/OKX.Net/OKXEnvironment.cs +++ b/OKX.Net/OKXEnvironment.cs @@ -23,6 +23,27 @@ internal OKXEnvironment(string name, SocketAddress = socketAddress; } + /// + /// 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 OKXEnvironment() : 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 OKX environment by name + /// + public static OKXEnvironment? GetEnvironmentByName(string? name) + => name switch + { + TradeEnvironmentNames.Live => Live, + TradeEnvironmentNames.Testnet => Demo, + "" => Live, + null => Live, + _ => default + }; + /// /// Live environment /// diff --git a/OKX.Net/OKXExchange.cs b/OKX.Net/OKXExchange.cs index b95ce8e..350c40c 100644 --- a/OKX.Net/OKXExchange.cs +++ b/OKX.Net/OKXExchange.cs @@ -14,6 +14,16 @@ public static class OKXExchange /// public static string ExchangeName => "OKX"; + /// + /// Exchange name + /// + public static string DisplayName => "OKX"; + + /// + /// Url to exchange image + /// + public static string ImageUrl { get; } = "https://raw.githubusercontent.com/JKorf/OKX.Net/master/OKX.Net/Icon/icon.png"; + /// /// Url to the main website /// diff --git a/OKX.Net/Objects/OKXApiCredentials.cs b/OKX.Net/Objects/OKXApiCredentials.cs index c65c79c..d342771 100644 --- a/OKX.Net/Objects/OKXApiCredentials.cs +++ b/OKX.Net/Objects/OKXApiCredentials.cs @@ -6,17 +6,17 @@ public class OKXApiCredentials : ApiCredentials /// /// Passphrase /// - public string PassPhrase { get; } + public string PassPhrase { get; set; } /// /// ctor /// - /// - /// - /// - public OKXApiCredentials(string apiKey, string apiSecret, string apiPassPhrase) : base(apiKey, apiSecret) + /// The API key + /// The API secret + /// The API passphrase + public OKXApiCredentials(string key, string secret, string passPhrase) : base(key, secret) { - PassPhrase = apiPassPhrase; + PassPhrase = passPhrase; } /// diff --git a/OKX.Net/Objects/Options/OKXOptions.cs b/OKX.Net/Objects/Options/OKXOptions.cs new file mode 100644 index 0000000..5cb6ea9 --- /dev/null +++ b/OKX.Net/Objects/Options/OKXOptions.cs @@ -0,0 +1,36 @@ +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Text; + +namespace OKX.Net.Objects.Options; +/// +/// OKX options +/// +public class OKXOptions +{ + /// + /// Rest client options + /// + public OKXRestOptions Rest { get; set; } = new OKXRestOptions(); + + /// + /// Socket client options + /// + public OKXSocketOptions Socket { get; set; } = new OKXSocketOptions(); + + /// + /// Trade environment. Contains info about URL's to use to connect to the API. Use `OKXEnvironment` to swap environment, for example `Environment = OKXEnvironment.Live` + /// + public OKXEnvironment? Environment { get; set; } + + /// + /// The api credentials used for signing requests. + /// + public OKXApiCredentials? ApiCredentials { get; set; } + + /// + /// The DI service lifetime for the IOKXSocketClient + /// + public ServiceLifetime? SocketClientLifeTime { get; set; } +} diff --git a/OKX.Net/Objects/Options/OKXRestOptions.cs b/OKX.Net/Objects/Options/OKXRestOptions.cs index b962159..01e56a4 100644 --- a/OKX.Net/Objects/Options/OKXRestOptions.cs +++ b/OKX.Net/Objects/Options/OKXRestOptions.cs @@ -10,11 +10,19 @@ public class OKXRestOptions : RestExchangeOptions /// Default options for new OKXRestClients /// - public static OKXRestOptions Default { get; set; } = new OKXRestOptions() + internal static OKXRestOptions Default { get; set; } = new OKXRestOptions() { Environment = OKXEnvironment.Live }; + /// + /// ctor + /// + public OKXRestOptions() + { + Default?.Set(this); + } + /// /// Whether or not to sign public requests /// @@ -30,12 +38,12 @@ public class OKXRestOptions : RestExchangeOptions public RestApiOptions UnifiedOptions { get; private set; } = new RestApiOptions(); - internal OKXRestOptions Copy() + internal OKXRestOptions Set(OKXRestOptions targetOptions) { - var options = Copy(); - options.SignPublicRequests = SignPublicRequests; - options.BrokerId = BrokerId; - options.UnifiedOptions = UnifiedOptions.Copy(); - return options; + targetOptions = base.Set(targetOptions); + targetOptions.SignPublicRequests = SignPublicRequests; + targetOptions.BrokerId = BrokerId; + targetOptions.UnifiedOptions = UnifiedOptions.Set(targetOptions.UnifiedOptions); + return targetOptions; } } diff --git a/OKX.Net/Objects/Options/OKXSocketOptions.cs b/OKX.Net/Objects/Options/OKXSocketOptions.cs index 8687ee9..c709c56 100644 --- a/OKX.Net/Objects/Options/OKXSocketOptions.cs +++ b/OKX.Net/Objects/Options/OKXSocketOptions.cs @@ -10,12 +10,20 @@ public class OKXSocketOptions : SocketExchangeOptions /// Default options for new OKXRestClients /// - public static OKXSocketOptions Default { get; set; } = new OKXSocketOptions() + internal static OKXSocketOptions Default { get; set; } = new OKXSocketOptions() { SocketSubscriptionsCombineTarget = 10, Environment = OKXEnvironment.Live }; + /// + /// ctor + /// + public OKXSocketOptions() + { + Default?.Set(this); + } + /// /// Broker ID for earning rebates /// @@ -26,11 +34,11 @@ public class OKXSocketOptions : SocketExchangeOptions public SocketApiOptions UnifiedOptions { get; private set; } = new SocketApiOptions(); - internal OKXSocketOptions Copy() + internal OKXSocketOptions Set(OKXSocketOptions targetOptions) { - var options = Copy(); - options.BrokerId = BrokerId; - options.UnifiedOptions = UnifiedOptions.Copy(); - return options; + targetOptions = base.Set(targetOptions); + targetOptions.BrokerId = BrokerId; + targetOptions.UnifiedOptions = UnifiedOptions.Set(targetOptions.UnifiedOptions); + return targetOptions; } } diff --git a/docs/index.html b/docs/index.html index f3e0652..0d0aa91 100644 --- a/docs/index.html +++ b/docs/index.html @@ -190,16 +190,22 @@

API Access

OKX.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.AddOKX(options => {
-  // Options can be configured here, for example:
-  options.ApiCredentials = new ApiCredentials("APIKEY", "APISECRET");
+		  
// Configure options from config file
+// see https://github.com/JKorf/CryptoExchange.Net/tree/master/Examples/example-config.json for an example
+builder.Services.AddOKX(builder.Configuration.GetSection("OKX"));
+		  
+// OR
+		  
+ builder.Services.AddOKX(options => {
+  // Configure options in code
+  options.ApiCredentials = new OKXApiCredentials("APIKEY", "APISECRET", "APIPASS");
 });

The IOKXRestClient and IOKXSocketClient can then be injected.

Alternatively the rest and socket client can be constructed directly

var restClient = new OKXRestClient(options => {
   // Options can be configured here, for example:
-  options.ApiCredentials = new ApiCredentials("APIKEY", "APISECRET");
+  options.ApiCredentials = new OKXApiCredentials("APIKEY", "APISECRET", "APIPASS");
 });
 var socketClient = new OKXSocketClient();