diff --git a/CoinEx.Net/Clients/CoinExUserClientProvider.cs b/CoinEx.Net/Clients/CoinExUserClientProvider.cs
index 1554c0f..7f2bed5 100644
--- a/CoinEx.Net/Clients/CoinExUserClientProvider.cs
+++ b/CoinEx.Net/Clients/CoinExUserClientProvider.cs
@@ -66,7 +66,7 @@ public void ClearUserClients(string userIdentifier)
///
public ICoinExRestClient GetRestClient(string userIdentifier, ApiCredentials? credentials = null, CoinExEnvironment? environment = null)
{
- if (!_restClients.TryGetValue(userIdentifier, out var client))
+ if (!_restClients.TryGetValue(userIdentifier, out var client) || client.Disposed)
client = CreateRestClient(userIdentifier, credentials, environment);
return client;
@@ -75,7 +75,7 @@ public ICoinExRestClient GetRestClient(string userIdentifier, ApiCredentials? cr
///
public ICoinExSocketClient GetSocketClient(string userIdentifier, ApiCredentials? credentials = null, CoinExEnvironment? environment = null)
{
- if (!_socketClients.TryGetValue(userIdentifier, out var client))
+ if (!_socketClients.TryGetValue(userIdentifier, out var client) || client.Disposed)
client = CreateSocketClient(userIdentifier, credentials, environment);
return client;
diff --git a/CoinEx.Net/Clients/FuturesApi/CoinExRestClientFuturesApiShared.cs b/CoinEx.Net/Clients/FuturesApi/CoinExRestClientFuturesApiShared.cs
index ff0f63c..832dd2c 100644
--- a/CoinEx.Net/Clients/FuturesApi/CoinExRestClientFuturesApiShared.cs
+++ b/CoinEx.Net/Clients/FuturesApi/CoinExRestClientFuturesApiShared.cs
@@ -162,7 +162,44 @@ async Task> IFuturesSymbolRestClient.Ge
ExchangeSymbolCache.UpdateSymbolInfo(_topicId, response.Data);
return response;
}
+ async Task> IFuturesSymbolRestClient.GetFuturesSymbolsForBaseAssetAsync(string baseAsset)
+ {
+ if (!ExchangeSymbolCache.HasCached(_topicId))
+ {
+ var symbols = await ((IFuturesSymbolRestClient)this).GetFuturesSymbolsAsync(new GetSymbolsRequest()).ConfigureAwait(false);
+ if (!symbols)
+ return new ExchangeResult(Exchange, symbols.Error!);
+ }
+
+ return new ExchangeResult(Exchange, ExchangeSymbolCache.GetSymbolsForBaseAsset(_topicId, baseAsset));
+ }
+ async Task> IFuturesSymbolRestClient.SupportsFuturesSymbolAsync(SharedSymbol symbol)
+ {
+ if (symbol.TradingMode == TradingMode.Spot)
+ throw new ArgumentException(nameof(symbol), "Spot symbols not allowed");
+
+ if (!ExchangeSymbolCache.HasCached(_topicId))
+ {
+ var symbols = await ((IFuturesSymbolRestClient)this).GetFuturesSymbolsAsync(new GetSymbolsRequest()).ConfigureAwait(false);
+ if (!symbols)
+ return new ExchangeResult(Exchange, symbols.Error!);
+ }
+
+ return new ExchangeResult(Exchange, ExchangeSymbolCache.SupportsSymbol(_topicId, symbol));
+ }
+
+ async Task> IFuturesSymbolRestClient.SupportsFuturesSymbolAsync(string symbolName)
+ {
+ if (!ExchangeSymbolCache.HasCached(_topicId))
+ {
+ var symbols = await ((IFuturesSymbolRestClient)this).GetFuturesSymbolsAsync(new GetSymbolsRequest()).ConfigureAwait(false);
+ if (!symbols)
+ return new ExchangeResult(Exchange, symbols.Error!);
+ }
+
+ return new ExchangeResult(Exchange, ExchangeSymbolCache.SupportsSymbol(_topicId, symbolName));
+ }
#endregion
#region Futures Order Client
@@ -440,6 +477,7 @@ async Task> IFuturesOrderRestClient.GetPosit
Leverage = x.Leverage,
StopLossPrice = x.StopLossPrice == 0 ? null : x.StopLossPrice,
TakeProfitPrice = x.TakeProfitPrice == 0 ? null : x.TakeProfitPrice,
+ PositionMode = SharedPositionMode.OneWay,
PositionSide = x.Side == PositionSide.Short ? SharedPositionSide.Short : SharedPositionSide.Long
}).ToArray());
}
diff --git a/CoinEx.Net/Clients/FuturesApi/CoinExSocketClientFuturesApiShared.cs b/CoinEx.Net/Clients/FuturesApi/CoinExSocketClientFuturesApiShared.cs
index e4614ad..0603d67 100644
--- a/CoinEx.Net/Clients/FuturesApi/CoinExSocketClientFuturesApiShared.cs
+++ b/CoinEx.Net/Clients/FuturesApi/CoinExSocketClientFuturesApiShared.cs
@@ -221,6 +221,7 @@ async Task> IPositionSocketClient.SubscribeTo
update => handler(update.ToType(new[] { new SharedPosition(ExchangeSymbolCache.ParseSymbol(_topicId, update.Data.Position.Symbol), update.Data.Position.Symbol, update.Data.Position.OpenInterest, update.Data.Position.UpdateTime)
{
AverageOpenPrice = update.Data.Position.AverageEntryPrice,
+ PositionMode = SharedPositionMode.OneWay,
PositionSide = update.Data.Position.Side == Enums.PositionSide.Short ? SharedPositionSide.Short : SharedPositionSide.Long,
LiquidationPrice = update.Data.Position.LiquidationPrice,
Leverage = update.Data.Position.Leverage,
diff --git a/CoinEx.Net/Clients/SpotApiV2/CoinExRestClientSpotApiShared.cs b/CoinEx.Net/Clients/SpotApiV2/CoinExRestClientSpotApiShared.cs
index a7c8441..1466c44 100644
--- a/CoinEx.Net/Clients/SpotApiV2/CoinExRestClientSpotApiShared.cs
+++ b/CoinEx.Net/Clients/SpotApiV2/CoinExRestClientSpotApiShared.cs
@@ -116,7 +116,44 @@ async Task> ISpotSymbolRestClient.GetSpotS
ExchangeSymbolCache.UpdateSymbolInfo(_topicId, response.Data);
return response;
}
+ async Task> ISpotSymbolRestClient.GetSpotSymbolsForBaseAssetAsync(string baseAsset)
+ {
+ if (!ExchangeSymbolCache.HasCached(_topicId))
+ {
+ var symbols = await ((ISpotSymbolRestClient)this).GetSpotSymbolsAsync(new GetSymbolsRequest()).ConfigureAwait(false);
+ if (!symbols)
+ return new ExchangeResult(Exchange, symbols.Error!);
+ }
+
+ return new ExchangeResult(Exchange, ExchangeSymbolCache.GetSymbolsForBaseAsset(_topicId, baseAsset));
+ }
+ async Task> ISpotSymbolRestClient.SupportsSpotSymbolAsync(SharedSymbol symbol)
+ {
+ if (symbol.TradingMode != TradingMode.Spot)
+ throw new ArgumentException(nameof(symbol), "Only Spot symbols allowed");
+
+ if (!ExchangeSymbolCache.HasCached(_topicId))
+ {
+ var symbols = await ((ISpotSymbolRestClient)this).GetSpotSymbolsAsync(new GetSymbolsRequest()).ConfigureAwait(false);
+ if (!symbols)
+ return new ExchangeResult(Exchange, symbols.Error!);
+ }
+
+ return new ExchangeResult(Exchange, ExchangeSymbolCache.SupportsSymbol(_topicId, symbol));
+ }
+
+ async Task> ISpotSymbolRestClient.SupportsSpotSymbolAsync(string symbolName)
+ {
+ if (!ExchangeSymbolCache.HasCached(_topicId))
+ {
+ var symbols = await ((ISpotSymbolRestClient)this).GetSpotSymbolsAsync(new GetSymbolsRequest()).ConfigureAwait(false);
+ if (!symbols)
+ return new ExchangeResult(Exchange, symbols.Error!);
+ }
+
+ return new ExchangeResult(Exchange, ExchangeSymbolCache.SupportsSymbol(_topicId, symbolName));
+ }
#endregion
#region Ticker client
@@ -728,7 +765,15 @@ async Task> IDepositRestClient.GetDepositsAsy
if (deposits.Data.HasNext == true)
nextToken = new PageToken(page + 1, pageSize);
- return deposits.AsExchangeResult(Exchange, TradingMode.Spot, deposits.Data.Items.Select(x => new SharedDeposit(x.Asset, x.Quantity, x.Status == DepositStatus.Finished, x.CreateTime)
+ return deposits.AsExchangeResult(Exchange, TradingMode.Spot, deposits.Data.Items.Select(x =>
+ new SharedDeposit(
+ x.Asset,
+ x.Quantity,
+ x.Status == DepositStatus.Finished,
+ x.CreateTime,
+ x.Status == DepositStatus.Finished ? SharedTransferStatus.Completed
+ : x.Status == DepositStatus.Processing || x.Status == DepositStatus.Confirming ? SharedTransferStatus.InProgress
+ : SharedTransferStatus.Failed)
{
Id = x.Id.ToString(),
Confirmations = x.Confirmations,
diff --git a/CoinEx.Net/CoinEx.Net.csproj b/CoinEx.Net/CoinEx.Net.csproj
index c384a38..6ccc382 100644
--- a/CoinEx.Net/CoinEx.Net.csproj
+++ b/CoinEx.Net/CoinEx.Net.csproj
@@ -54,7 +54,7 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/CoinEx.Net/CoinEx.Net.xml b/CoinEx.Net/CoinEx.Net.xml
index 1d18d24..ef96646 100644
--- a/CoinEx.Net/CoinEx.Net.xml
+++ b/CoinEx.Net/CoinEx.Net.xml
@@ -796,6 +796,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ctor
+
+
+
+
+
+
+
+
+
+
+ ctor
+
+
Defines the source generated JSON serialization contract metadata for a given type.
@@ -4559,6 +4590,36 @@
Tracker factory
+
+
+ Create a new Spot user data tracker
+
+ User identifier
+ Configuration
+ Credentials
+ Environment
+
+
+
+ Create a new spot user data tracker
+
+ Configuration
+
+
+
+ Create a new futures user data tracker
+
+ User identifier
+ Configuration
+ Credentials
+ Environment
+
+
+
+ Create a new futures user data tracker
+
+ Configuration
+
Api addresses usable for the CoinEx clients
diff --git a/CoinEx.Net/CoinExTrackerFactory.cs b/CoinEx.Net/CoinExTrackerFactory.cs
index 241a5c6..efd40ed 100644
--- a/CoinEx.Net/CoinExTrackerFactory.cs
+++ b/CoinEx.Net/CoinExTrackerFactory.cs
@@ -1,11 +1,15 @@
using CoinEx.Net.Clients;
using CoinEx.Net.Interfaces;
using CoinEx.Net.Interfaces.Clients;
+using CryptoExchange.Net.Authentication;
using CryptoExchange.Net.SharedApis;
using CryptoExchange.Net.Trackers.Klines;
using CryptoExchange.Net.Trackers.Trades;
+using CryptoExchange.Net.Trackers.UserData.Interfaces;
+using CryptoExchange.Net.Trackers.UserData.Objects;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
using System;
namespace CoinEx.Net
@@ -70,5 +74,63 @@ public ITradeTracker CreateTradeTracker(SharedSymbol symbol, int? limit = null,
period
);
}
+
+ ///
+ public IUserSpotDataTracker CreateUserSpotDataTracker(SpotUserDataTrackerConfig? config = null)
+ {
+ var restClient = _serviceProvider?.GetRequiredService() ?? new CoinExRestClient();
+ var socketClient = _serviceProvider?.GetRequiredService() ?? new CoinExSocketClient();
+ return new CoinExUserSpotDataTracker(
+ _serviceProvider?.GetRequiredService>() ?? new NullLogger(),
+ restClient,
+ socketClient,
+ null,
+ config
+ );
+ }
+
+ ///
+ public IUserSpotDataTracker CreateUserSpotDataTracker(string userIdentifier, ApiCredentials credentials, SpotUserDataTrackerConfig? config = null, CoinExEnvironment? environment = null)
+ {
+ var clientProvider = _serviceProvider?.GetRequiredService() ?? new CoinExUserClientProvider();
+ var restClient = clientProvider.GetRestClient(userIdentifier, credentials, environment);
+ var socketClient = clientProvider.GetSocketClient(userIdentifier, credentials, environment);
+ return new CoinExUserSpotDataTracker(
+ _serviceProvider?.GetRequiredService>() ?? new NullLogger(),
+ restClient,
+ socketClient,
+ userIdentifier,
+ config
+ );
+ }
+
+ ///
+ public IUserFuturesDataTracker CreateUserFuturesDataTracker(FuturesUserDataTrackerConfig? config = null)
+ {
+ var restClient = _serviceProvider?.GetRequiredService() ?? new CoinExRestClient();
+ var socketClient = _serviceProvider?.GetRequiredService() ?? new CoinExSocketClient();
+ return new CoinExUserFuturesDataTracker(
+ _serviceProvider?.GetRequiredService>() ?? new NullLogger(),
+ restClient,
+ socketClient,
+ null,
+ config
+ );
+ }
+
+ ///
+ public IUserFuturesDataTracker CreateUserFuturesDataTracker(string userIdentifier, ApiCredentials credentials, FuturesUserDataTrackerConfig? config = null, CoinExEnvironment? environment = null)
+ {
+ var clientProvider = _serviceProvider?.GetRequiredService() ?? new CoinExUserClientProvider();
+ var restClient = clientProvider.GetRestClient(userIdentifier, credentials, environment);
+ var socketClient = clientProvider.GetSocketClient(userIdentifier, credentials, environment);
+ return new CoinExUserFuturesDataTracker(
+ _serviceProvider?.GetRequiredService>() ?? new NullLogger(),
+ restClient,
+ socketClient,
+ userIdentifier,
+ config
+ );
+ }
}
}
diff --git a/CoinEx.Net/CoinExUserDataTracker.cs b/CoinEx.Net/CoinExUserDataTracker.cs
new file mode 100644
index 0000000..b9f4d92
--- /dev/null
+++ b/CoinEx.Net/CoinExUserDataTracker.cs
@@ -0,0 +1,63 @@
+using CoinEx.Net.Interfaces.Clients;
+using CryptoExchange.Net.SharedApis;
+using CryptoExchange.Net.Trackers.UserData;
+using CryptoExchange.Net.Trackers.UserData.Objects;
+using Microsoft.Extensions.Logging;
+
+namespace CoinEx.Net
+{
+ ///
+ public class CoinExUserSpotDataTracker : UserSpotDataTracker
+ {
+ ///
+ /// ctor
+ ///
+ public CoinExUserSpotDataTracker(
+ ILogger logger,
+ ICoinExRestClient restClient,
+ ICoinExSocketClient socketClient,
+ string? userIdentifier,
+ SpotUserDataTrackerConfig? config) : base(
+ logger,
+ restClient.SpotApiV2.SharedClient,
+ null,
+ restClient.SpotApiV2.SharedClient,
+ socketClient.SpotApiV2.SharedClient,
+ restClient.SpotApiV2.SharedClient,
+ socketClient.SpotApiV2.SharedClient,
+ socketClient.SpotApiV2.SharedClient,
+ userIdentifier,
+ config ?? new SpotUserDataTrackerConfig())
+ {
+ }
+ }
+
+ ///
+ public class CoinExUserFuturesDataTracker : UserFuturesDataTracker
+ {
+ ///
+ protected override bool WebsocketPositionUpdatesAreFullSnapshots => false;
+
+ ///
+ /// ctor
+ ///
+ public CoinExUserFuturesDataTracker(
+ ILogger logger,
+ ICoinExRestClient restClient,
+ ICoinExSocketClient socketClient,
+ string? userIdentifier,
+ FuturesUserDataTrackerConfig? config) : base(logger,
+ restClient.FuturesApi.SharedClient,
+ null,
+ restClient.FuturesApi.SharedClient,
+ socketClient.FuturesApi.SharedClient,
+ restClient.FuturesApi.SharedClient,
+ socketClient.FuturesApi.SharedClient,
+ socketClient.FuturesApi.SharedClient,
+ socketClient.FuturesApi.SharedClient,
+ userIdentifier,
+ config ?? new FuturesUserDataTrackerConfig())
+ {
+ }
+ }
+}
diff --git a/CoinEx.Net/Interfaces/ICoinExTrackerFactory.cs b/CoinEx.Net/Interfaces/ICoinExTrackerFactory.cs
index 8bc14f2..88516c3 100644
--- a/CoinEx.Net/Interfaces/ICoinExTrackerFactory.cs
+++ b/CoinEx.Net/Interfaces/ICoinExTrackerFactory.cs
@@ -1,7 +1,10 @@
-using CryptoExchange.Net.Interfaces;
+using CryptoExchange.Net.Authentication;
+using CryptoExchange.Net.Interfaces;
using CryptoExchange.Net.SharedApis;
using CryptoExchange.Net.Trackers.Klines;
using CryptoExchange.Net.Trackers.Trades;
+using CryptoExchange.Net.Trackers.UserData.Interfaces;
+using CryptoExchange.Net.Trackers.UserData.Objects;
using System;
using System.Collections.Generic;
using System.Text;
@@ -13,5 +16,32 @@ namespace CoinEx.Net.Interfaces
///
public interface ICoinExTrackerFactory : ITrackerFactory
{
+ ///
+ /// Create a new Spot user data tracker
+ ///
+ /// User identifier
+ /// Configuration
+ /// Credentials
+ /// Environment
+ IUserSpotDataTracker CreateUserSpotDataTracker(string userIdentifier, ApiCredentials credentials, SpotUserDataTrackerConfig? config = null, CoinExEnvironment? environment = null);
+ ///
+ /// Create a new spot user data tracker
+ ///
+ /// Configuration
+ IUserSpotDataTracker CreateUserSpotDataTracker(SpotUserDataTrackerConfig? config = null);
+
+ ///
+ /// Create a new futures user data tracker
+ ///
+ /// User identifier
+ /// Configuration
+ /// Credentials
+ /// Environment
+ IUserFuturesDataTracker CreateUserFuturesDataTracker(string userIdentifier, ApiCredentials credentials, FuturesUserDataTrackerConfig? config = null, CoinExEnvironment? environment = null);
+ ///
+ /// Create a new futures user data tracker
+ ///
+ /// Configuration
+ IUserFuturesDataTracker CreateUserFuturesDataTracker(FuturesUserDataTrackerConfig? config = null);
}
}