diff --git a/DeepCoin.Net/Clients/DeepCoinUserClientProvider.cs b/DeepCoin.Net/Clients/DeepCoinUserClientProvider.cs
index a4b6bd5..4073120 100644
--- a/DeepCoin.Net/Clients/DeepCoinUserClientProvider.cs
+++ b/DeepCoin.Net/Clients/DeepCoinUserClientProvider.cs
@@ -64,7 +64,7 @@ public void ClearUserClients(string userIdentifier)
///
public IDeepCoinRestClient GetRestClient(string userIdentifier, ApiCredentials? credentials = null, DeepCoinEnvironment? 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;
@@ -73,7 +73,7 @@ public IDeepCoinRestClient GetRestClient(string userIdentifier, ApiCredentials?
///
public IDeepCoinSocketClient GetSocketClient(string userIdentifier, ApiCredentials? credentials = null, DeepCoinEnvironment? 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/DeepCoin.Net/Clients/ExchangeApi/DeepCoinRestClientExchangeApiShared.cs b/DeepCoin.Net/Clients/ExchangeApi/DeepCoinRestClientExchangeApiShared.cs
index dd31b8d..fb55251 100644
--- a/DeepCoin.Net/Clients/ExchangeApi/DeepCoinRestClientExchangeApiShared.cs
+++ b/DeepCoin.Net/Clients/ExchangeApi/DeepCoinRestClientExchangeApiShared.cs
@@ -86,7 +86,15 @@ async Task> IDepositRestClient.GetDepositsAsy
if (result.Data.Total > (result.Data.Page * result.Data.PageSize))
nextToken = new PageToken(page++, pageSize);
- return result.AsExchangeResult(Exchange, TradingMode.Spot, result.Data.Data.Select(x => new SharedDeposit(x.Asset, x.Quantity, x.DepositStatus == Enums.DepositStatus.Success, x.CreateTime)
+ return result.AsExchangeResult(Exchange, TradingMode.Spot, result.Data.Data.Select(x =>
+ new SharedDeposit(
+ x.Asset,
+ x.Quantity,
+ x.DepositStatus == Enums.DepositStatus.Success,
+ x.CreateTime,
+ x.DepositStatus == DepositStatus.Success ? SharedTransferStatus.Completed
+ : x.DepositStatus == DepositStatus.Confirming ? SharedTransferStatus.InProgress
+ : SharedTransferStatus.Failed)
{
TransactionId = x.TransactionHash,
Network = x.NetworkName,
@@ -350,6 +358,44 @@ async Task> ISpotSymbolRestClient.GetSpotS
return response;
}
+ async Task> ISpotSymbolRestClient.GetSpotSymbolsForBaseAssetAsync(string baseAsset)
+ {
+ if (!ExchangeSymbolCache.HasCached(_topicSpotId))
+ {
+ var symbols = await ((ISpotSymbolRestClient)this).GetSpotSymbolsAsync(new GetSymbolsRequest()).ConfigureAwait(false);
+ if (!symbols)
+ return new ExchangeResult(Exchange, symbols.Error!);
+ }
+
+ return new ExchangeResult(Exchange, ExchangeSymbolCache.GetSymbolsForBaseAsset(_topicSpotId, baseAsset));
+ }
+
+ async Task> ISpotSymbolRestClient.SupportsSpotSymbolAsync(SharedSymbol symbol)
+ {
+ if (symbol.TradingMode != TradingMode.Spot)
+ throw new ArgumentException(nameof(symbol), "Only Spot symbols allowed");
+
+ if (!ExchangeSymbolCache.HasCached(_topicSpotId))
+ {
+ var symbols = await ((ISpotSymbolRestClient)this).GetSpotSymbolsAsync(new GetSymbolsRequest()).ConfigureAwait(false);
+ if (!symbols)
+ return new ExchangeResult(Exchange, symbols.Error!);
+ }
+
+ return new ExchangeResult(Exchange, ExchangeSymbolCache.SupportsSymbol(_topicSpotId, symbol));
+ }
+
+ async Task> ISpotSymbolRestClient.SupportsSpotSymbolAsync(string symbolName)
+ {
+ if (!ExchangeSymbolCache.HasCached(_topicSpotId))
+ {
+ var symbols = await ((ISpotSymbolRestClient)this).GetSpotSymbolsAsync(new GetSymbolsRequest()).ConfigureAwait(false);
+ if (!symbols)
+ return new ExchangeResult(Exchange, symbols.Error!);
+ }
+
+ return new ExchangeResult(Exchange, ExchangeSymbolCache.SupportsSymbol(_topicSpotId, symbolName));
+ }
#endregion
#region Spot Order Client
@@ -746,10 +792,51 @@ async Task> IFuturesSymbolRestClient.Ge
MaxShortLeverage = s.MaxLeverage
}).ToArray());
- ExchangeSymbolCache.UpdateSymbolInfo(_topicFuturesId, response.Data);
+ // Also register [BaseAsset][QuoteAsset] as they might be returned for websocket updates
+ var symbolRegistrations = response.Data
+ .Concat(response.Data.Select(x => new SharedSpotSymbol(x.BaseAsset, x.QuoteAsset, x.BaseAsset + x.QuoteAsset, x.Trading, x.TradingMode))).ToArray();
+
+ ExchangeSymbolCache.UpdateSymbolInfo(_topicFuturesId, symbolRegistrations);
return response;
}
+ async Task> IFuturesSymbolRestClient.GetFuturesSymbolsForBaseAssetAsync(string baseAsset)
+ {
+ if (!ExchangeSymbolCache.HasCached(_topicFuturesId))
+ {
+ var symbols = await ((IFuturesSymbolRestClient)this).GetFuturesSymbolsAsync(new GetSymbolsRequest()).ConfigureAwait(false);
+ if (!symbols)
+ return new ExchangeResult(Exchange, symbols.Error!);
+ }
+
+ return new ExchangeResult(Exchange, ExchangeSymbolCache.GetSymbolsForBaseAsset(_topicFuturesId, baseAsset));
+ }
+
+ async Task> IFuturesSymbolRestClient.SupportsFuturesSymbolAsync(SharedSymbol symbol)
+ {
+ if (symbol.TradingMode == TradingMode.Spot)
+ throw new ArgumentException(nameof(symbol), "Spot symbols not allowed");
+
+ if (!ExchangeSymbolCache.HasCached(_topicFuturesId))
+ {
+ var symbols = await ((IFuturesSymbolRestClient)this).GetFuturesSymbolsAsync(new GetSymbolsRequest()).ConfigureAwait(false);
+ if (!symbols)
+ return new ExchangeResult(Exchange, symbols.Error!);
+ }
+
+ return new ExchangeResult(Exchange, ExchangeSymbolCache.SupportsSymbol(_topicFuturesId, symbol));
+ }
+ async Task> IFuturesSymbolRestClient.SupportsFuturesSymbolAsync(string symbolName)
+ {
+ if (!ExchangeSymbolCache.HasCached(_topicFuturesId))
+ {
+ var symbols = await ((IFuturesSymbolRestClient)this).GetFuturesSymbolsAsync(new GetSymbolsRequest()).ConfigureAwait(false);
+ if (!symbols)
+ return new ExchangeResult(Exchange, symbols.Error!);
+ }
+
+ return new ExchangeResult(Exchange, ExchangeSymbolCache.SupportsSymbol(_topicFuturesId, symbolName));
+ }
#endregion
#region Futures Order Client
@@ -1064,7 +1151,8 @@ async Task> IFuturesOrderRestClient.GetPosit
{
LiquidationPrice = x.LiquidationPrice == 0 ? null : x.LiquidationPrice,
Leverage = x.Leverage,
- AverageOpenPrice = x.AveragePrice,
+ AverageOpenPrice = x.AveragePrice,
+ PositionMode = SharedPositionMode.HedgeMode,
PositionSide = x.PositionSide == PositionSide.Long ? SharedPositionSide.Long : SharedPositionSide.Short
}).ToArray());
}
diff --git a/DeepCoin.Net/Clients/ExchangeApi/DeepCoinSocketClientExchangeApiShared.cs b/DeepCoin.Net/Clients/ExchangeApi/DeepCoinSocketClientExchangeApiShared.cs
index cb0b3f5..3fc2384 100644
--- a/DeepCoin.Net/Clients/ExchangeApi/DeepCoinSocketClientExchangeApiShared.cs
+++ b/DeepCoin.Net/Clients/ExchangeApi/DeepCoinSocketClientExchangeApiShared.cs
@@ -219,9 +219,10 @@ async Task> IPositionSocketClient.SubscribeTo
return new ExchangeResult(Exchange, validationError);
var result = await SubscribeToUserDataUpdatesAsync(request.ListenKey!,
- onPositionMessage: update => handler(update.ToType(update.Data.Select(x => new SharedPosition(ExchangeSymbolCache.ParseSymbol(_topicSpotId, x.Symbol), x.Symbol, x.PositionSize, x.UpdateTime)
+ onPositionMessage: update => handler(update.ToType(update.Data.Select(x => new SharedPosition(ExchangeSymbolCache.ParseSymbol(_topicFuturesId, x.Symbol), x.Symbol, x.PositionSize, x.UpdateTime)
{
AverageOpenPrice = x.OpenPrice,
+ PositionMode = SharedPositionMode.HedgeMode,
PositionSide = x.PositionSide == Enums.PositionSide.Short ? SharedPositionSide.Short : SharedPositionSide.Long,
Leverage = x.Leverage
}).ToArray())),
@@ -251,7 +252,7 @@ async Task> IUserTradeSocketClient.SubscribeT
request.ListenKey!,
onUserTradeMessage: update => handler(update.ToType(update.Data.Select(x =>
new SharedUserTrade(
- ExchangeSymbolCache.ParseSymbol(_topicFuturesId, x.Symbol) ?? ExchangeSymbolCache.ParseSymbol(_topicSpotId, x.Symbol),
+ ExchangeSymbolCache.ParseSymbol(_topicFuturesId, x.Symbol) ?? ExchangeSymbolCache.ParseSymbol(_topicFuturesId, x.Symbol),
x.Symbol,
x.OrderId.ToString(),
x.TradeId.ToString(),
diff --git a/DeepCoin.Net/DeepCoin.Net.csproj b/DeepCoin.Net/DeepCoin.Net.csproj
index cdc02b7..f57786e 100644
--- a/DeepCoin.Net/DeepCoin.Net.csproj
+++ b/DeepCoin.Net/DeepCoin.Net.csproj
@@ -52,7 +52,7 @@
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/DeepCoin.Net/DeepCoin.Net.xml b/DeepCoin.Net/DeepCoin.Net.xml
index 9307076..2afd10b 100644
--- a/DeepCoin.Net/DeepCoin.Net.xml
+++ b/DeepCoin.Net/DeepCoin.Net.xml
@@ -1209,6 +1209,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ctor
+
+
+
+
+
+
+
+
+
+
+ ctor
+
+
Account type
@@ -2104,6 +2135,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
diff --git a/DeepCoin.Net/DeepCoinTrackerFactory.cs b/DeepCoin.Net/DeepCoinTrackerFactory.cs
index 5a3a623..7e14a10 100644
--- a/DeepCoin.Net/DeepCoinTrackerFactory.cs
+++ b/DeepCoin.Net/DeepCoinTrackerFactory.cs
@@ -1,12 +1,16 @@
+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 DeepCoin.Net.Clients;
using DeepCoin.Net.Interfaces;
using DeepCoin.Net.Interfaces.Clients;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Logging.Abstractions;
using System;
-using DeepCoin.Net.Clients;
namespace DeepCoin.Net
{
@@ -73,5 +77,63 @@ public ITradeTracker CreateTradeTracker(SharedSymbol symbol, int? limit = null,
period
);
}
+
+ ///
+ public IUserSpotDataTracker CreateUserSpotDataTracker(SpotUserDataTrackerConfig? config = null)
+ {
+ var restClient = _serviceProvider?.GetRequiredService() ?? new DeepCoinRestClient();
+ var socketClient = _serviceProvider?.GetRequiredService() ?? new DeepCoinSocketClient();
+ return new DeepCoinUserSpotDataTracker(
+ _serviceProvider?.GetRequiredService>() ?? new NullLogger(),
+ restClient,
+ socketClient,
+ null,
+ config
+ );
+ }
+
+ ///
+ public IUserSpotDataTracker CreateUserSpotDataTracker(string userIdentifier, ApiCredentials credentials, SpotUserDataTrackerConfig? config = null, DeepCoinEnvironment? environment = null)
+ {
+ var clientProvider = _serviceProvider?.GetRequiredService() ?? new DeepCoinUserClientProvider();
+ var restClient = clientProvider.GetRestClient(userIdentifier, credentials, environment);
+ var socketClient = clientProvider.GetSocketClient(userIdentifier, credentials, environment);
+ return new DeepCoinUserSpotDataTracker(
+ _serviceProvider?.GetRequiredService>() ?? new NullLogger(),
+ restClient,
+ socketClient,
+ userIdentifier,
+ config
+ );
+ }
+
+ ///
+ public IUserFuturesDataTracker CreateUserFuturesDataTracker(FuturesUserDataTrackerConfig? config = null)
+ {
+ var restClient = _serviceProvider?.GetRequiredService() ?? new DeepCoinRestClient();
+ var socketClient = _serviceProvider?.GetRequiredService() ?? new DeepCoinSocketClient();
+ return new DeepCoinUserFuturesDataTracker(
+ _serviceProvider?.GetRequiredService>() ?? new NullLogger(),
+ restClient,
+ socketClient,
+ null,
+ config
+ );
+ }
+
+ ///
+ public IUserFuturesDataTracker CreateUserFuturesDataTracker(string userIdentifier, ApiCredentials credentials, FuturesUserDataTrackerConfig? config = null, DeepCoinEnvironment? environment = null)
+ {
+ var clientProvider = _serviceProvider?.GetRequiredService() ?? new DeepCoinUserClientProvider();
+ var restClient = clientProvider.GetRestClient(userIdentifier, credentials, environment);
+ var socketClient = clientProvider.GetSocketClient(userIdentifier, credentials, environment);
+ return new DeepCoinUserFuturesDataTracker(
+ _serviceProvider?.GetRequiredService>() ?? new NullLogger(),
+ restClient,
+ socketClient,
+ userIdentifier,
+ config
+ );
+ }
}
}
diff --git a/DeepCoin.Net/DeepCoinUserDataTracker.cs b/DeepCoin.Net/DeepCoinUserDataTracker.cs
new file mode 100644
index 0000000..98c1180
--- /dev/null
+++ b/DeepCoin.Net/DeepCoinUserDataTracker.cs
@@ -0,0 +1,63 @@
+using DeepCoin.Net.Interfaces.Clients;
+using CryptoExchange.Net.SharedApis;
+using CryptoExchange.Net.Trackers.UserData;
+using CryptoExchange.Net.Trackers.UserData.Objects;
+using Microsoft.Extensions.Logging;
+
+namespace DeepCoin.Net
+{
+ ///
+ public class DeepCoinUserSpotDataTracker : UserSpotDataTracker
+ {
+ ///
+ /// ctor
+ ///
+ public DeepCoinUserSpotDataTracker(
+ ILogger logger,
+ IDeepCoinRestClient restClient,
+ IDeepCoinSocketClient socketClient,
+ string? userIdentifier,
+ SpotUserDataTrackerConfig? config) : base(
+ logger,
+ restClient.ExchangeApi.SharedClient,
+ restClient.ExchangeApi.SharedClient,
+ restClient.ExchangeApi.SharedClient,
+ socketClient.ExchangeApi.SharedClient,
+ restClient.ExchangeApi.SharedClient,
+ socketClient.ExchangeApi.SharedClient,
+ socketClient.ExchangeApi.SharedClient,
+ userIdentifier,
+ config ?? new SpotUserDataTrackerConfig())
+ {
+ }
+ }
+
+ ///
+ public class DeepCoinUserFuturesDataTracker : UserFuturesDataTracker
+ {
+ ///
+ protected override bool WebsocketPositionUpdatesAreFullSnapshots => false;
+
+ ///
+ /// ctor
+ ///
+ public DeepCoinUserFuturesDataTracker(
+ ILogger logger,
+ IDeepCoinRestClient restClient,
+ IDeepCoinSocketClient socketClient,
+ string? userIdentifier,
+ FuturesUserDataTrackerConfig? config) : base(logger,
+ restClient.ExchangeApi.SharedClient,
+ restClient.ExchangeApi.SharedClient,
+ restClient.ExchangeApi.SharedClient,
+ socketClient.ExchangeApi.SharedClient,
+ restClient.ExchangeApi.SharedClient,
+ socketClient.ExchangeApi.SharedClient,
+ socketClient.ExchangeApi.SharedClient,
+ socketClient.ExchangeApi.SharedClient,
+ userIdentifier,
+ config ?? new FuturesUserDataTrackerConfig())
+ {
+ }
+ }
+}
diff --git a/DeepCoin.Net/Interfaces/IDeepCoinTrackerFactory.cs b/DeepCoin.Net/Interfaces/IDeepCoinTrackerFactory.cs
index 3cc15ef..8688a7c 100644
--- a/DeepCoin.Net/Interfaces/IDeepCoinTrackerFactory.cs
+++ b/DeepCoin.Net/Interfaces/IDeepCoinTrackerFactory.cs
@@ -1,4 +1,7 @@
+using CryptoExchange.Net.Authentication;
using CryptoExchange.Net.Interfaces;
+using CryptoExchange.Net.Trackers.UserData.Interfaces;
+using CryptoExchange.Net.Trackers.UserData.Objects;
namespace DeepCoin.Net.Interfaces
{
@@ -7,5 +10,32 @@ namespace DeepCoin.Net.Interfaces
///
public interface IDeepCoinTrackerFactory : ITrackerFactory
{
+ ///
+ /// Create a new Spot user data tracker
+ ///
+ /// User identifier
+ /// Configuration
+ /// Credentials
+ /// Environment
+ IUserSpotDataTracker CreateUserSpotDataTracker(string userIdentifier, ApiCredentials credentials, SpotUserDataTrackerConfig? config = null, DeepCoinEnvironment? 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, DeepCoinEnvironment? environment = null);
+ ///
+ /// Create a new futures user data tracker
+ ///
+ /// Configuration
+ IUserFuturesDataTracker CreateUserFuturesDataTracker(FuturesUserDataTrackerConfig? config = null);
}
}