mirror of
https://github.com/JKorf/CryptoExchange.Net
synced 2025-10-27 08:27:19 +00:00
Compare commits
No commits in common. "d433ff7475c578d0fff8896565b4457145ff5e3e" and "a832f0e4d40599da4d2d04541cfdd6dcf9182968" have entirely different histories.
d433ff7475
...
a832f0e4d4
@ -6,9 +6,9 @@
|
|||||||
<PackageId>CryptoExchange.Net.Protobuf</PackageId>
|
<PackageId>CryptoExchange.Net.Protobuf</PackageId>
|
||||||
<Authors>JKorf</Authors>
|
<Authors>JKorf</Authors>
|
||||||
<Description>Protobuf support for CryptoExchange.Net</Description>
|
<Description>Protobuf support for CryptoExchange.Net</Description>
|
||||||
<PackageVersion>9.9.0</PackageVersion>
|
<PackageVersion>9.8.0</PackageVersion>
|
||||||
<AssemblyVersion>9.9.0</AssemblyVersion>
|
<AssemblyVersion>9.8.0</AssemblyVersion>
|
||||||
<FileVersion>9.9.0</FileVersion>
|
<FileVersion>9.8.0</FileVersion>
|
||||||
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
|
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
|
||||||
<PackageTags>CryptoExchange;CryptoExchange.Net</PackageTags>
|
<PackageTags>CryptoExchange;CryptoExchange.Net</PackageTags>
|
||||||
<RepositoryType>git</RepositoryType>
|
<RepositoryType>git</RepositoryType>
|
||||||
@ -41,7 +41,7 @@
|
|||||||
<DocumentationFile>CryptoExchange.Net.Protobuf.xml</DocumentationFile>
|
<DocumentationFile>CryptoExchange.Net.Protobuf.xml</DocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CryptoExchange.Net" Version="9.9.0" />
|
<PackageReference Include="CryptoExchange.Net" Version="9.8.0" />
|
||||||
<PackageReference Include="protobuf-net" Version="3.2.56" />
|
<PackageReference Include="protobuf-net" Version="3.2.56" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@ -5,9 +5,6 @@
|
|||||||
Protobuf support for CryptoExchange.Net.
|
Protobuf support for CryptoExchange.Net.
|
||||||
|
|
||||||
## Release notes
|
## Release notes
|
||||||
* Version 9.9.0 - 06 Oct 2025
|
|
||||||
* Updated CryptoExchange.Net version to 9.9.0, see https://github.com/JKorf/CryptoExchange.Net/releases/
|
|
||||||
|
|
||||||
* Version 9.8.0 - 30 Sep 2025
|
* Version 9.8.0 - 30 Sep 2025
|
||||||
* Updated CryptoExchange.Net version to 9.8.0, see https://github.com/JKorf/CryptoExchange.Net/releases/
|
* Updated CryptoExchange.Net version to 9.8.0, see https://github.com/JKorf/CryptoExchange.Net/releases/
|
||||||
|
|
||||||
|
|||||||
@ -202,7 +202,7 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
await sub;
|
await sub;
|
||||||
|
|
||||||
// assert
|
// assert
|
||||||
ClassicAssert.IsTrue(client.SubClient.TestSubscription.Status != SubscriptionStatus.Subscribed);
|
ClassicAssert.IsFalse(client.SubClient.TestSubscription.Confirmed);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase()]
|
[TestCase()]
|
||||||
@ -225,7 +225,7 @@ namespace CryptoExchange.Net.UnitTests
|
|||||||
await sub;
|
await sub;
|
||||||
|
|
||||||
// assert
|
// assert
|
||||||
Assert.That(client.SubClient.TestSubscription.Status == SubscriptionStatus.Subscribed);
|
Assert.That(client.SubClient.TestSubscription.Confirmed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -269,7 +269,6 @@ namespace CryptoExchange.Net.Clients
|
|||||||
return new CallResult<UpdateSubscription>(new ServerError(new ErrorInfo(ErrorType.WebsocketPaused, "Socket is paused")));
|
return new CallResult<UpdateSubscription>(new ServerError(new ErrorInfo(ErrorType.WebsocketPaused, "Socket is paused")));
|
||||||
}
|
}
|
||||||
|
|
||||||
subscription.Status = SubscriptionStatus.Subscribing;
|
|
||||||
var waitEvent = new AsyncResetEvent(false);
|
var waitEvent = new AsyncResetEvent(false);
|
||||||
var subQuery = subscription.CreateSubscriptionQuery(socketConnection);
|
var subQuery = subscription.CreateSubscriptionQuery(socketConnection);
|
||||||
if (subQuery != null)
|
if (subQuery != null)
|
||||||
@ -280,7 +279,7 @@ namespace CryptoExchange.Net.Clients
|
|||||||
{
|
{
|
||||||
waitEvent?.Set();
|
waitEvent?.Set();
|
||||||
var isTimeout = subResult.Error is CancellationRequestedError;
|
var isTimeout = subResult.Error is CancellationRequestedError;
|
||||||
if (isTimeout && subscription.Status == SubscriptionStatus.Subscribed)
|
if (isTimeout && subscription.Confirmed)
|
||||||
{
|
{
|
||||||
// No response received, but the subscription did receive updates. We'll assume success
|
// No response received, but the subscription did receive updates. We'll assume success
|
||||||
}
|
}
|
||||||
@ -288,7 +287,6 @@ namespace CryptoExchange.Net.Clients
|
|||||||
{
|
{
|
||||||
_logger.FailedToSubscribe(socketConnection.SocketId, subResult.Error?.ToString());
|
_logger.FailedToSubscribe(socketConnection.SocketId, subResult.Error?.ToString());
|
||||||
// If this was a timeout we still need to send an unsubscribe to prevent messages coming in later
|
// If this was a timeout we still need to send an unsubscribe to prevent messages coming in later
|
||||||
subscription.Status = SubscriptionStatus.Pending;
|
|
||||||
await socketConnection.CloseAsync(subscription).ConfigureAwait(false);
|
await socketConnection.CloseAsync(subscription).ConfigureAwait(false);
|
||||||
return new CallResult<UpdateSubscription>(subResult.Error!);
|
return new CallResult<UpdateSubscription>(subResult.Error!);
|
||||||
}
|
}
|
||||||
@ -297,7 +295,7 @@ namespace CryptoExchange.Net.Clients
|
|||||||
subscription.HandleSubQueryResponse(subQuery.Response!);
|
subscription.HandleSubQueryResponse(subQuery.Response!);
|
||||||
}
|
}
|
||||||
|
|
||||||
subscription.Status = SubscriptionStatus.Subscribed;
|
subscription.Confirmed = true;
|
||||||
if (ct != default)
|
if (ct != default)
|
||||||
{
|
{
|
||||||
subscription.CancellationTokenRegistration = ct.Register(async () =>
|
subscription.CancellationTokenRegistration = ct.Register(async () =>
|
||||||
@ -849,7 +847,7 @@ namespace CryptoExchange.Net.Clients
|
|||||||
cs.SubscriptionStates.ForEach(subState =>
|
cs.SubscriptionStates.ForEach(subState =>
|
||||||
{
|
{
|
||||||
sb.AppendLine($"\t\t\tId: {subState.Id}");
|
sb.AppendLine($"\t\t\tId: {subState.Id}");
|
||||||
sb.AppendLine($"\t\t\tStatus: {subState.Status}");
|
sb.AppendLine($"\t\t\tConfirmed: {subState.Confirmed}");
|
||||||
sb.AppendLine($"\t\t\tInvocations: {subState.Invocations}");
|
sb.AppendLine($"\t\t\tInvocations: {subState.Invocations}");
|
||||||
sb.AppendLine($"\t\t\tIdentifiers: [{subState.ListenMatcher.ToString()}]");
|
sb.AppendLine($"\t\t\tIdentifiers: [{subState.ListenMatcher.ToString()}]");
|
||||||
});
|
});
|
||||||
|
|||||||
@ -6,9 +6,9 @@
|
|||||||
<PackageId>CryptoExchange.Net</PackageId>
|
<PackageId>CryptoExchange.Net</PackageId>
|
||||||
<Authors>JKorf</Authors>
|
<Authors>JKorf</Authors>
|
||||||
<Description>CryptoExchange.Net is a base library which is used to implement different cryptocurrency (exchange) API's. It provides a standardized way of implementing different API's, which results in a very similar experience for users of the API implementations.</Description>
|
<Description>CryptoExchange.Net is a base library which is used to implement different cryptocurrency (exchange) API's. It provides a standardized way of implementing different API's, which results in a very similar experience for users of the API implementations.</Description>
|
||||||
<PackageVersion>9.9.0</PackageVersion>
|
<PackageVersion>9.8.0</PackageVersion>
|
||||||
<AssemblyVersion>9.9.0</AssemblyVersion>
|
<AssemblyVersion>9.8.0</AssemblyVersion>
|
||||||
<FileVersion>9.9.0</FileVersion>
|
<FileVersion>9.8.0</FileVersion>
|
||||||
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
|
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
|
||||||
<PackageTags>OKX;OKX.Net;Mexc;Mexc.Net;Kucoin;Kucoin.Net;Kraken;Kraken.Net;Huobi;Huobi.Net;CoinEx;CoinEx.Net;Bybit;Bybit.Net;Bitget;Bitget.Net;Bitfinex;Bitfinex.Net;Binance;Binance.Net;CryptoCurrency;CryptoCurrency Exchange;CryptoExchange.Net</PackageTags>
|
<PackageTags>OKX;OKX.Net;Mexc;Mexc.Net;Kucoin;Kucoin.Net;Kraken;Kraken.Net;Huobi;Huobi.Net;CoinEx;CoinEx.Net;Bybit;Bybit.Net;Bitget;Bitget.Net;Bitfinex;Bitfinex.Net;Binance;Binance.Net;CryptoCurrency;CryptoCurrency Exchange;CryptoExchange.Net</PackageTags>
|
||||||
<RepositoryType>git</RepositoryType>
|
<RepositoryType>git</RepositoryType>
|
||||||
|
|||||||
@ -267,31 +267,4 @@ namespace CryptoExchange.Net.Objects
|
|||||||
Succeed
|
Succeed
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Subscription status
|
|
||||||
/// </summary>
|
|
||||||
public enum SubscriptionStatus
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Pending, waiting before (re)subscription can be started
|
|
||||||
/// </summary>
|
|
||||||
Pending,
|
|
||||||
/// <summary>
|
|
||||||
/// Currently (re)subscribing, will start producing updates soon if subscription is successful
|
|
||||||
/// </summary>
|
|
||||||
Subscribing,
|
|
||||||
/// <summary>
|
|
||||||
/// Subscribed and listening to updates
|
|
||||||
/// </summary>
|
|
||||||
Subscribed,
|
|
||||||
/// <summary>
|
|
||||||
/// Subscription is being closed and will stop producing updates
|
|
||||||
/// </summary>
|
|
||||||
Closing,
|
|
||||||
/// <summary>
|
|
||||||
/// Subscription is closed and will no long produce updates
|
|
||||||
/// </summary>
|
|
||||||
Closed
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,7 +15,6 @@ namespace CryptoExchange.Net.Objects.Sockets
|
|||||||
private readonly Subscription _listener;
|
private readonly Subscription _listener;
|
||||||
|
|
||||||
private object _eventLock = new object();
|
private object _eventLock = new object();
|
||||||
private bool _connectionEventsSubscribed = true;
|
|
||||||
private List<Action> _connectionClosedEventHandlers = new List<Action>();
|
private List<Action> _connectionClosedEventHandlers = new List<Action>();
|
||||||
private List<Action> _connectionLostEventHandlers = new List<Action>();
|
private List<Action> _connectionLostEventHandlers = new List<Action>();
|
||||||
private List<Action<Error>> _resubscribeFailedEventHandlers = new List<Action<Error>>();
|
private List<Action<Error>> _resubscribeFailedEventHandlers = new List<Action<Error>>();
|
||||||
@ -23,11 +22,6 @@ namespace CryptoExchange.Net.Objects.Sockets
|
|||||||
private List<Action> _activityPausedEventHandlers = new List<Action>();
|
private List<Action> _activityPausedEventHandlers = new List<Action>();
|
||||||
private List<Action> _activityUnpausedEventHandlers = new List<Action>();
|
private List<Action> _activityUnpausedEventHandlers = new List<Action>();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Event when the status of the subscription changes
|
|
||||||
/// </summary>
|
|
||||||
public event Action<SubscriptionStatus>? SubscriptionStatusChanged;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Event when the connection is lost. The socket will automatically reconnect when possible.
|
/// Event when the connection is lost. The socket will automatically reconnect when possible.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -119,34 +113,21 @@ namespace CryptoExchange.Net.Objects.Sockets
|
|||||||
_connection.ActivityUnpaused += HandleUnpausedEvent;
|
_connection.ActivityUnpaused += HandleUnpausedEvent;
|
||||||
|
|
||||||
_listener = subscription;
|
_listener = subscription;
|
||||||
_listener.StatusChanged += (x) => SubscriptionStatusChanged?.Invoke(x);
|
_listener.Unsubscribed += HandleUnsubscribed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UnsubscribeConnectionEvents()
|
private void HandleUnsubscribed()
|
||||||
{
|
{
|
||||||
lock (_eventLock)
|
|
||||||
{
|
|
||||||
if (!_connectionEventsSubscribed)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_connection.ConnectionClosed -= HandleConnectionClosedEvent;
|
_connection.ConnectionClosed -= HandleConnectionClosedEvent;
|
||||||
_connection.ConnectionLost -= HandleConnectionLostEvent;
|
_connection.ConnectionLost -= HandleConnectionLostEvent;
|
||||||
_connection.ConnectionRestored -= HandleConnectionRestoredEvent;
|
_connection.ConnectionRestored -= HandleConnectionRestoredEvent;
|
||||||
_connection.ResubscribingFailed -= HandleResubscribeFailedEvent;
|
_connection.ResubscribingFailed -= HandleResubscribeFailedEvent;
|
||||||
_connection.ActivityPaused -= HandlePausedEvent;
|
_connection.ActivityPaused -= HandlePausedEvent;
|
||||||
_connection.ActivityUnpaused -= HandleUnpausedEvent;
|
_connection.ActivityUnpaused -= HandleUnpausedEvent;
|
||||||
_connectionEventsSubscribed = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleConnectionClosedEvent()
|
private void HandleConnectionClosedEvent()
|
||||||
{
|
{
|
||||||
UnsubscribeConnectionEvents();
|
|
||||||
|
|
||||||
// If we're not the subscription closing this connection don't bother emitting
|
|
||||||
if (!_listener.IsClosingConnection)
|
|
||||||
return;
|
|
||||||
|
|
||||||
List<Action> handlers;
|
List<Action> handlers;
|
||||||
lock (_eventLock)
|
lock (_eventLock)
|
||||||
handlers = _connectionClosedEventHandlers.ToList();
|
handlers = _connectionClosedEventHandlers.ToList();
|
||||||
@ -157,12 +138,6 @@ namespace CryptoExchange.Net.Objects.Sockets
|
|||||||
|
|
||||||
private void HandleConnectionLostEvent()
|
private void HandleConnectionLostEvent()
|
||||||
{
|
{
|
||||||
if (!_listener.Active)
|
|
||||||
{
|
|
||||||
UnsubscribeConnectionEvents();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Action> handlers;
|
List<Action> handlers;
|
||||||
lock (_eventLock)
|
lock (_eventLock)
|
||||||
handlers = _connectionLostEventHandlers.ToList();
|
handlers = _connectionLostEventHandlers.ToList();
|
||||||
@ -173,12 +148,6 @@ namespace CryptoExchange.Net.Objects.Sockets
|
|||||||
|
|
||||||
private void HandleConnectionRestoredEvent(TimeSpan period)
|
private void HandleConnectionRestoredEvent(TimeSpan period)
|
||||||
{
|
{
|
||||||
if (!_listener.Active)
|
|
||||||
{
|
|
||||||
UnsubscribeConnectionEvents();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Action<TimeSpan>> handlers;
|
List<Action<TimeSpan>> handlers;
|
||||||
lock (_eventLock)
|
lock (_eventLock)
|
||||||
handlers = _connectionRestoredEventHandlers.ToList();
|
handlers = _connectionRestoredEventHandlers.ToList();
|
||||||
@ -189,12 +158,6 @@ namespace CryptoExchange.Net.Objects.Sockets
|
|||||||
|
|
||||||
private void HandleResubscribeFailedEvent(Error error)
|
private void HandleResubscribeFailedEvent(Error error)
|
||||||
{
|
{
|
||||||
if (!_listener.Active)
|
|
||||||
{
|
|
||||||
UnsubscribeConnectionEvents();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Action<Error>> handlers;
|
List<Action<Error>> handlers;
|
||||||
lock (_eventLock)
|
lock (_eventLock)
|
||||||
handlers = _resubscribeFailedEventHandlers.ToList();
|
handlers = _resubscribeFailedEventHandlers.ToList();
|
||||||
@ -205,12 +168,6 @@ namespace CryptoExchange.Net.Objects.Sockets
|
|||||||
|
|
||||||
private void HandlePausedEvent()
|
private void HandlePausedEvent()
|
||||||
{
|
{
|
||||||
if (!_listener.Active)
|
|
||||||
{
|
|
||||||
UnsubscribeConnectionEvents();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Action> handlers;
|
List<Action> handlers;
|
||||||
lock (_eventLock)
|
lock (_eventLock)
|
||||||
handlers = _activityPausedEventHandlers.ToList();
|
handlers = _activityPausedEventHandlers.ToList();
|
||||||
@ -221,12 +178,6 @@ namespace CryptoExchange.Net.Objects.Sockets
|
|||||||
|
|
||||||
private void HandleUnpausedEvent()
|
private void HandleUnpausedEvent()
|
||||||
{
|
{
|
||||||
if (!_listener.Active)
|
|
||||||
{
|
|
||||||
UnsubscribeConnectionEvents();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Action> handlers;
|
List<Action> handlers;
|
||||||
lock (_eventLock)
|
lock (_eventLock)
|
||||||
handlers = _activityUnpausedEventHandlers.ToList();
|
handlers = _activityUnpausedEventHandlers.ToList();
|
||||||
|
|||||||
@ -296,7 +296,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
|
|
||||||
lock (_listenersLock)
|
lock (_listenersLock)
|
||||||
{
|
{
|
||||||
foreach (var subscription in _listeners.OfType<Subscription>().Where(l => l.UserSubscription && !l.IsClosingConnection))
|
foreach (var subscription in _listeners.OfType<Subscription>().Where(l => l.UserSubscription))
|
||||||
subscription.Reset();
|
subscription.Reset();
|
||||||
|
|
||||||
foreach (var query in _listeners.OfType<Query>().ToList())
|
foreach (var query in _listeners.OfType<Query>().ToList())
|
||||||
@ -527,10 +527,10 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (processor is Subscription subscriptionProcessor && subscriptionProcessor.Status == SubscriptionStatus.Subscribing)
|
if (processor is Subscription subscriptionProcessor && !subscriptionProcessor.Confirmed)
|
||||||
{
|
{
|
||||||
// If this message is for this listener then it is automatically confirmed, even if the subscription is not (yet) confirmed
|
// If this message is for this listener then it is automatically confirmed, even if the subscription is not (yet) confirmed
|
||||||
subscriptionProcessor.Status = SubscriptionStatus.Subscribed;
|
subscriptionProcessor.Confirmed = true;
|
||||||
if (subscriptionProcessor.SubscriptionQuery?.TimeoutBehavior == TimeoutBehavior.Succeed)
|
if (subscriptionProcessor.SubscriptionQuery?.TimeoutBehavior == TimeoutBehavior.Succeed)
|
||||||
// If this subscription has a query waiting for a timeout (success if there is no error response)
|
// If this subscription has a query waiting for a timeout (success if there is no error response)
|
||||||
// then time it out now as the data is being received, so we assume it's successful
|
// then time it out now as the data is being received, so we assume it's successful
|
||||||
@ -657,16 +657,13 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
public async Task CloseAsync(Subscription subscription)
|
public async Task CloseAsync(Subscription subscription)
|
||||||
{
|
{
|
||||||
// If we are resubscribing this subscription at this moment we'll want to wait for a bit until it is finished to avoid concurrency issues
|
// If we are resubscribing this subscription at this moment we'll want to wait for a bit until it is finished to avoid concurrency issues
|
||||||
while (subscription.Status == SubscriptionStatus.Subscribing)
|
while (subscription.IsResubscribing)
|
||||||
await Task.Delay(50).ConfigureAwait(false);
|
await Task.Delay(50).ConfigureAwait(false);
|
||||||
|
|
||||||
subscription.Status = SubscriptionStatus.Closing;
|
subscription.Closed = true;
|
||||||
|
|
||||||
if (Status == SocketStatus.Closing || Status == SocketStatus.Closed || Status == SocketStatus.Disposed)
|
if (Status == SocketStatus.Closing || Status == SocketStatus.Closed || Status == SocketStatus.Disposed)
|
||||||
{
|
|
||||||
subscription.Status = SubscriptionStatus.Closed;
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
_logger.ClosingSubscription(SocketId, subscription.Id);
|
_logger.ClosingSubscription(SocketId, subscription.Id);
|
||||||
if (subscription.CancellationTokenRegistration.HasValue)
|
if (subscription.CancellationTokenRegistration.HasValue)
|
||||||
@ -678,7 +675,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
|
|
||||||
bool shouldCloseConnection;
|
bool shouldCloseConnection;
|
||||||
lock (_listenersLock)
|
lock (_listenersLock)
|
||||||
shouldCloseConnection = _listeners.OfType<Subscription>().All(r => !r.UserSubscription || r.Status == SubscriptionStatus.Closing || r.Status == SubscriptionStatus.Closed) && !DedicatedRequestConnection.IsDedicatedRequestConnection;
|
shouldCloseConnection = _listeners.OfType<Subscription>().All(r => !r.UserSubscription || r.Closed) && !DedicatedRequestConnection.IsDedicatedRequestConnection;
|
||||||
|
|
||||||
if (!anyDuplicateSubscription)
|
if (!anyDuplicateSubscription)
|
||||||
{
|
{
|
||||||
@ -696,7 +693,6 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
|
|
||||||
if (Status == SocketStatus.Closing)
|
if (Status == SocketStatus.Closing)
|
||||||
{
|
{
|
||||||
subscription.Status = SubscriptionStatus.Closed;
|
|
||||||
_logger.AlreadyClosing(SocketId);
|
_logger.AlreadyClosing(SocketId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -704,7 +700,6 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
if (shouldCloseConnection)
|
if (shouldCloseConnection)
|
||||||
{
|
{
|
||||||
Status = SocketStatus.Closing;
|
Status = SocketStatus.Closing;
|
||||||
subscription.IsClosingConnection = true;
|
|
||||||
_logger.ClosingNoMoreSubscriptions(SocketId);
|
_logger.ClosingNoMoreSubscriptions(SocketId);
|
||||||
await CloseAsync().ConfigureAwait(false);
|
await CloseAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@ -712,7 +707,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
lock (_listenersLock)
|
lock (_listenersLock)
|
||||||
_listeners.Remove(subscription);
|
_listeners.Remove(subscription);
|
||||||
|
|
||||||
subscription.Status = SubscriptionStatus.Closed;
|
subscription.InvokeUnsubscribedHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -996,7 +991,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
|
|
||||||
List<Subscription> subList;
|
List<Subscription> subList;
|
||||||
lock (_listenersLock)
|
lock (_listenersLock)
|
||||||
subList = _listeners.OfType<Subscription>().Where(x => x.Active).Skip(batch * batchSize).Take(batchSize).ToList();
|
subList = _listeners.OfType<Subscription>().Where(x => !x.Closed).Skip(batch * batchSize).Take(batchSize).ToList();
|
||||||
|
|
||||||
if (subList.Count == 0)
|
if (subList.Count == 0)
|
||||||
break;
|
break;
|
||||||
@ -1005,32 +1000,34 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
foreach (var subscription in subList)
|
foreach (var subscription in subList)
|
||||||
{
|
{
|
||||||
subscription.ConnectionInvocations = 0;
|
subscription.ConnectionInvocations = 0;
|
||||||
if (!subscription.Active)
|
if (subscription.Closed)
|
||||||
// Can be closed during resubscribing
|
// Can be closed during resubscribing
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
subscription.Status = SubscriptionStatus.Subscribing;
|
subscription.IsResubscribing = true;
|
||||||
var result = await ApiClient.RevitalizeRequestAsync(subscription).ConfigureAwait(false);
|
var result = await ApiClient.RevitalizeRequestAsync(subscription).ConfigureAwait(false);
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
_logger.FailedRequestRevitalization(SocketId, result.Error?.ToString());
|
_logger.FailedRequestRevitalization(SocketId, result.Error?.ToString());
|
||||||
subscription.Status = SubscriptionStatus.Pending;
|
subscription.IsResubscribing = false;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
var subQuery = subscription.CreateSubscriptionQuery(this);
|
var subQuery = subscription.CreateSubscriptionQuery(this);
|
||||||
if (subQuery == null)
|
if (subQuery == null)
|
||||||
{
|
{
|
||||||
subscription.Status = SubscriptionStatus.Subscribed;
|
subscription.IsResubscribing = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var waitEvent = new AsyncResetEvent(false);
|
var waitEvent = new AsyncResetEvent(false);
|
||||||
taskList.Add(SendAndWaitQueryAsync(subQuery, waitEvent).ContinueWith((r) =>
|
taskList.Add(SendAndWaitQueryAsync(subQuery, waitEvent).ContinueWith((r) =>
|
||||||
{
|
{
|
||||||
subscription.Status = r.Result.Success ? SubscriptionStatus.Subscribed: SubscriptionStatus.Pending;
|
subscription.IsResubscribing = false;
|
||||||
subscription.HandleSubQueryResponse(subQuery.Response!);
|
subscription.HandleSubQueryResponse(subQuery.Response!);
|
||||||
waitEvent.Set();
|
waitEvent.Set();
|
||||||
|
if (r.Result.Success)
|
||||||
|
subscription.Confirmed = true;
|
||||||
return r.Result;
|
return r.Result;
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,32 +35,20 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool UserSubscription { get; set; }
|
public bool UserSubscription { get; set; }
|
||||||
|
|
||||||
private SubscriptionStatus _status;
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Current subscription status
|
/// Has the subscription been confirmed
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public SubscriptionStatus Status
|
public bool Confirmed { get; set; }
|
||||||
{
|
|
||||||
get => _status;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (_status == value)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_status = value;
|
|
||||||
Task.Run(() => StatusChanged?.Invoke(value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether the subscription is active
|
/// Is the subscription closed
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool Active => Status != SubscriptionStatus.Closing && Status != SubscriptionStatus.Closed;
|
public bool Closed { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether the unsubscribing of this subscription lead to the closing of the connection
|
/// Is the subscription currently resubscribing
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsClosingConnection { get; set; }
|
public bool IsResubscribing { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Logger
|
/// Logger
|
||||||
@ -89,7 +77,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Listener unsubscribed event
|
/// Listener unsubscribed event
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action<SubscriptionStatus>? StatusChanged;
|
public event Action? Unsubscribed;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Subscription topic
|
/// Subscription topic
|
||||||
@ -179,7 +167,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void Reset()
|
public void Reset()
|
||||||
{
|
{
|
||||||
Status = SubscriptionStatus.Pending;
|
Confirmed = false;
|
||||||
DoHandleReset();
|
DoHandleReset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,16 +185,24 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
Exception?.Invoke(e);
|
Exception?.Invoke(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invoke the unsubscribed event
|
||||||
|
/// </summary>
|
||||||
|
public void InvokeUnsubscribedHandler()
|
||||||
|
{
|
||||||
|
Unsubscribed?.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// State of this subscription
|
/// State of this subscription
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="Id">The id of the subscription</param>
|
/// <param name="Id">The id of the subscription</param>
|
||||||
/// <param name="Status">Subscription status</param>
|
/// <param name="Confirmed">True when the subscription query is handled (either accepted or rejected)</param>
|
||||||
/// <param name="Invocations">Number of times this subscription got a message</param>
|
/// <param name="Invocations">Number of times this subscription got a message</param>
|
||||||
/// <param name="ListenMatcher">Matcher for this subscription</param>
|
/// <param name="ListenMatcher">Matcher for this subscription</param>
|
||||||
public record SubscriptionState(
|
public record SubscriptionState(
|
||||||
int Id,
|
int Id,
|
||||||
SubscriptionStatus Status,
|
bool Confirmed,
|
||||||
int Invocations,
|
int Invocations,
|
||||||
MessageMatcher ListenMatcher
|
MessageMatcher ListenMatcher
|
||||||
);
|
);
|
||||||
@ -217,7 +213,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public SubscriptionState GetState()
|
public SubscriptionState GetState()
|
||||||
{
|
{
|
||||||
return new SubscriptionState(Id, Status, TotalInvocations, MessageMatcher);
|
return new SubscriptionState(Id, Confirmed, TotalInvocations, MessageMatcher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -18,7 +18,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// <param name="authenticated"></param>
|
/// <param name="authenticated"></param>
|
||||||
public SystemSubscription(ILogger logger, bool authenticated = false) : base(logger, authenticated, false)
|
public SystemSubscription(ILogger logger, bool authenticated = false) : base(logger, authenticated, false)
|
||||||
{
|
{
|
||||||
Status = SubscriptionStatus.Subscribed;
|
Confirmed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@ -5,31 +5,30 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Binance.Net" Version="11.8.0" />
|
<PackageReference Include="Binance.Net" Version="11.7.1" />
|
||||||
<PackageReference Include="Bitfinex.Net" Version="9.8.0" />
|
<PackageReference Include="Bitfinex.Net" Version="9.7.0" />
|
||||||
<PackageReference Include="BitMart.Net" Version="2.9.0" />
|
<PackageReference Include="BitMart.Net" Version="2.8.0" />
|
||||||
<PackageReference Include="BloFin.Net" Version="1.1.0" />
|
<PackageReference Include="BloFin.Net" Version="1.0.0" />
|
||||||
<PackageReference Include="Bybit.Net" Version="5.9.0" />
|
<PackageReference Include="Bybit.Net" Version="5.8.0" />
|
||||||
<PackageReference Include="CoinEx.Net" Version="9.8.0" />
|
<PackageReference Include="CoinEx.Net" Version="9.7.0" />
|
||||||
<PackageReference Include="CoinW.Net" Version="1.5.0" />
|
<PackageReference Include="CoinW.Net" Version="1.4.0" />
|
||||||
<PackageReference Include="CryptoCom.Net" Version="2.9.0" />
|
<PackageReference Include="CryptoCom.Net" Version="2.8.0" />
|
||||||
<PackageReference Include="DeepCoin.Net" Version="2.8.0" />
|
<PackageReference Include="DeepCoin.Net" Version="2.7.0" />
|
||||||
<PackageReference Include="GateIo.Net" Version="2.9.1" />
|
<PackageReference Include="GateIo.Net" Version="2.8.1" />
|
||||||
<PackageReference Include="HyperLiquid.Net" Version="2.13.0" />
|
<PackageReference Include="HyperLiquid.Net" Version="2.12.0" />
|
||||||
<PackageReference Include="JK.BingX.Net" Version="2.8.0" />
|
<PackageReference Include="JK.BingX.Net" Version="2.7.0" />
|
||||||
<PackageReference Include="JK.Bitget.Net" Version="2.8.0" />
|
<PackageReference Include="JK.Bitget.Net" Version="2.7.1" />
|
||||||
<PackageReference Include="JK.Mexc.Net" Version="3.9.0" />
|
<PackageReference Include="JK.Mexc.Net" Version="3.8.0" />
|
||||||
<PackageReference Include="JK.OKX.Net" Version="3.8.0" />
|
<PackageReference Include="JK.OKX.Net" Version="3.7.1" />
|
||||||
<PackageReference Include="Jkorf.Aster.Net" Version="1.0.0" />
|
<PackageReference Include="JKorf.BitMEX.Net" Version="2.7.0" />
|
||||||
<PackageReference Include="JKorf.BitMEX.Net" Version="2.8.0" />
|
<PackageReference Include="JKorf.Coinbase.Net" Version="2.7.0" />
|
||||||
<PackageReference Include="JKorf.Coinbase.Net" Version="2.8.0" />
|
<PackageReference Include="JKorf.HTX.Net" Version="7.7.0" />
|
||||||
<PackageReference Include="JKorf.HTX.Net" Version="7.8.0" />
|
<PackageReference Include="KrakenExchange.Net" Version="6.7.0" />
|
||||||
<PackageReference Include="KrakenExchange.Net" Version="6.8.0" />
|
<PackageReference Include="Kucoin.Net" Version="7.7.1" />
|
||||||
<PackageReference Include="Kucoin.Net" Version="7.8.0" />
|
|
||||||
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
|
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
|
||||||
<PackageReference Include="Toobit.Net" Version="1.7.0" />
|
<PackageReference Include="Toobit.Net" Version="1.6.0" />
|
||||||
<PackageReference Include="WhiteBit.Net" Version="2.9.0" />
|
<PackageReference Include="WhiteBit.Net" Version="2.8.0" />
|
||||||
<PackageReference Include="XT.Net" Version="2.8.0" />
|
<PackageReference Include="XT.Net" Version="2.7.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
@page "/"
|
@page "/"
|
||||||
@inject IAsterRestClient asterClient
|
|
||||||
@inject IBinanceRestClient binanceClient
|
@inject IBinanceRestClient binanceClient
|
||||||
@inject IBingXRestClient bingXClient
|
@inject IBingXRestClient bingXClient
|
||||||
@inject IBitfinexRestClient bitfinexClient
|
@inject IBitfinexRestClient bitfinexClient
|
||||||
@ -35,7 +34,6 @@
|
|||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
var asterTask = asterClient.SpotApi.ExchangeData.GetTickerAsync("BTCUSDT");
|
|
||||||
var binanceTask = binanceClient.SpotApi.ExchangeData.GetTickerAsync("BTCUSDT");
|
var binanceTask = binanceClient.SpotApi.ExchangeData.GetTickerAsync("BTCUSDT");
|
||||||
var bingXTask = bingXClient.SpotApi.ExchangeData.GetTickersAsync("BTC-USDT");
|
var bingXTask = bingXClient.SpotApi.ExchangeData.GetTickersAsync("BTC-USDT");
|
||||||
var bitfinexTask = bitfinexClient.SpotApi.ExchangeData.GetTickerAsync("tBTCUSD");
|
var bitfinexTask = bitfinexClient.SpotApi.ExchangeData.GetTickerAsync("tBTCUSD");
|
||||||
@ -51,7 +49,7 @@
|
|||||||
var deepCoinTask = deepCoinClient.ExchangeApi.ExchangeData.GetTickersAsync(DeepCoin.Net.Enums.SymbolType.Spot);
|
var deepCoinTask = deepCoinClient.ExchangeApi.ExchangeData.GetTickersAsync(DeepCoin.Net.Enums.SymbolType.Spot);
|
||||||
var gateioTask = gateioClient.SpotApi.ExchangeData.GetTickersAsync("BTC_USDT");
|
var gateioTask = gateioClient.SpotApi.ExchangeData.GetTickersAsync("BTC_USDT");
|
||||||
var htxTask = htxClient.SpotApi.ExchangeData.GetTickerAsync("btcusdt");
|
var htxTask = htxClient.SpotApi.ExchangeData.GetTickerAsync("btcusdt");
|
||||||
var hyperLiquidTask = hyperLiquidClient.FuturesApi.ExchangeData.GetExchangeInfoAndTickersAsync();
|
var hyperLiquidTask = hyperLiquidClient.FuturesApi.ExchangeData.GetExchangeInfoAndTickersAsync(); // HyperLiquid does not have BTC spot trading
|
||||||
var krakenTask = krakenClient.SpotApi.ExchangeData.GetTickerAsync("XBTUSD");
|
var krakenTask = krakenClient.SpotApi.ExchangeData.GetTickerAsync("XBTUSD");
|
||||||
var kucoinTask = kucoinClient.SpotApi.ExchangeData.GetTickerAsync("BTC-USDT");
|
var kucoinTask = kucoinClient.SpotApi.ExchangeData.GetTickerAsync("BTC-USDT");
|
||||||
var mexcTask = mexcClient.SpotApi.ExchangeData.GetTickerAsync("BTCUSDT");
|
var mexcTask = mexcClient.SpotApi.ExchangeData.GetTickerAsync("BTCUSDT");
|
||||||
@ -60,10 +58,7 @@
|
|||||||
var whitebitTask = whitebitClient.V4Api.ExchangeData.GetTickersAsync();
|
var whitebitTask = whitebitClient.V4Api.ExchangeData.GetTickersAsync();
|
||||||
var xtTask = xtClient.SpotApi.ExchangeData.GetTickersAsync("btc_usdt");
|
var xtTask = xtClient.SpotApi.ExchangeData.GetTickersAsync("btc_usdt");
|
||||||
|
|
||||||
await Task.WhenAll(asterTask, binanceTask, bingXTask, bitfinexTask, bitgetTask, bitmartTask, bloFinTask, bitmexTask, bybitTask, coinexTask, coinWTask, deepCoinTask, gateioTask, htxTask, krakenTask, kucoinTask, mexcTask, okxTask);
|
await Task.WhenAll(binanceTask, bingXTask, bitfinexTask, bitgetTask, bitmartTask, bybitTask, coinexTask, deepCoinTask, gateioTask, htxTask, krakenTask, kucoinTask, mexcTask, okxTask);
|
||||||
|
|
||||||
if (asterTask.Result.Success)
|
|
||||||
_prices.Add("Aster", asterTask.Result.Data.LastPrice);
|
|
||||||
|
|
||||||
if (binanceTask.Result.Success)
|
if (binanceTask.Result.Success)
|
||||||
_prices.Add("Binance", binanceTask.Result.Data.LastPrice);
|
_prices.Add("Binance", binanceTask.Result.Data.LastPrice);
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
@page "/LiveData"
|
@page "/LiveData"
|
||||||
@inject IAsterSocketClient asterSocketClient
|
|
||||||
@inject IBinanceSocketClient binanceSocketClient
|
@inject IBinanceSocketClient binanceSocketClient
|
||||||
@inject IBingXSocketClient bingXSocketClient
|
@inject IBingXSocketClient bingXSocketClient
|
||||||
@inject IBitfinexSocketClient bitfinexSocketClient
|
@inject IBitfinexSocketClient bitfinexSocketClient
|
||||||
@ -44,8 +43,6 @@
|
|||||||
{
|
{
|
||||||
var tasks = new Task<CallResult<UpdateSubscription>>[]
|
var tasks = new Task<CallResult<UpdateSubscription>>[]
|
||||||
{
|
{
|
||||||
// Aster doesn't support the ETH/BTC pair
|
|
||||||
//asterSocketClient.SpotApi.ExchangeData.SubscribeToTickerUpdatesAsync("ETHBTC", data => UpdateData("Aster", data.Data.LastPrice)),
|
|
||||||
binanceSocketClient.SpotApi.ExchangeData.SubscribeToTickerUpdatesAsync("ETHBTC", data => UpdateData("Binance", data.Data.LastPrice)),
|
binanceSocketClient.SpotApi.ExchangeData.SubscribeToTickerUpdatesAsync("ETHBTC", data => UpdateData("Binance", data.Data.LastPrice)),
|
||||||
bingXSocketClient.SpotApi.SubscribeToTickerUpdatesAsync("ETH-BTC", data => UpdateData("BingX", data.Data.LastPrice)),
|
bingXSocketClient.SpotApi.SubscribeToTickerUpdatesAsync("ETH-BTC", data => UpdateData("BingX", data.Data.LastPrice)),
|
||||||
bitfinexSocketClient.SpotApi.SubscribeToTickerUpdatesAsync("tETHBTC", data => UpdateData("Bitfinex", data.Data.LastPrice)),
|
bitfinexSocketClient.SpotApi.SubscribeToTickerUpdatesAsync("tETHBTC", data => UpdateData("Bitfinex", data.Data.LastPrice)),
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
@page "/OrderBooks"
|
@page "/OrderBooks"
|
||||||
@using System.Collections.Concurrent
|
@using System.Collections.Concurrent
|
||||||
@using System.Timers
|
@using System.Timers
|
||||||
@using Aster.Net.Interfaces
|
|
||||||
@using Binance.Net.Interfaces
|
@using Binance.Net.Interfaces
|
||||||
@using BingX.Net.Interfaces
|
@using BingX.Net.Interfaces
|
||||||
@using Bitfinex.Net.Interfaces
|
@using Bitfinex.Net.Interfaces
|
||||||
@ -28,7 +27,6 @@
|
|||||||
@using Toobit.Net.Interfaces;
|
@using Toobit.Net.Interfaces;
|
||||||
@using WhiteBit.Net.Interfaces
|
@using WhiteBit.Net.Interfaces
|
||||||
@using XT.Net.Interfaces
|
@using XT.Net.Interfaces
|
||||||
@inject IAsterOrderBookFactory asterFactory
|
|
||||||
@inject IBinanceOrderBookFactory binanceFactory
|
@inject IBinanceOrderBookFactory binanceFactory
|
||||||
@inject IBingXOrderBookFactory bingXFactory
|
@inject IBingXOrderBookFactory bingXFactory
|
||||||
@inject IBitfinexOrderBookFactory bitfinexFactory
|
@inject IBitfinexOrderBookFactory bitfinexFactory
|
||||||
@ -85,7 +83,6 @@
|
|||||||
|
|
||||||
_books = new Dictionary<string, ISymbolOrderBook>
|
_books = new Dictionary<string, ISymbolOrderBook>
|
||||||
{
|
{
|
||||||
{ "Aster", binanceFactory.CreateSpot("ETHUSDT") },
|
|
||||||
{ "Binance", binanceFactory.CreateSpot("ETHBTC") },
|
{ "Binance", binanceFactory.CreateSpot("ETHBTC") },
|
||||||
{ "BingX", bingXFactory.CreateSpot("ETH-BTC") },
|
{ "BingX", bingXFactory.CreateSpot("ETH-BTC") },
|
||||||
{ "Bitfinex", bitfinexFactory.Create("tETHBTC") },
|
{ "Bitfinex", bitfinexFactory.Create("tETHBTC") },
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
@page "/Trackers"
|
@page "/Trackers"
|
||||||
@using System.Collections.Concurrent
|
@using System.Collections.Concurrent
|
||||||
@using System.Timers
|
@using System.Timers
|
||||||
@using Aster.Net.Interfaces
|
|
||||||
@using Binance.Net.Interfaces
|
@using Binance.Net.Interfaces
|
||||||
@using BingX.Net.Interfaces
|
@using BingX.Net.Interfaces
|
||||||
@using Bitfinex.Net.Interfaces
|
@using Bitfinex.Net.Interfaces
|
||||||
@ -29,7 +28,6 @@
|
|||||||
@using Toobit.Net.Interfaces;
|
@using Toobit.Net.Interfaces;
|
||||||
@using WhiteBit.Net.Interfaces
|
@using WhiteBit.Net.Interfaces
|
||||||
@using XT.Net.Interfaces
|
@using XT.Net.Interfaces
|
||||||
@inject IAsterTrackerFactory asterFactory
|
|
||||||
@inject IBinanceTrackerFactory binanceFactory
|
@inject IBinanceTrackerFactory binanceFactory
|
||||||
@inject IBingXTrackerFactory bingXFactory
|
@inject IBingXTrackerFactory bingXFactory
|
||||||
@inject IBitfinexTrackerFactory bitfinexFactory
|
@inject IBitfinexTrackerFactory bitfinexFactory
|
||||||
@ -81,7 +79,6 @@
|
|||||||
|
|
||||||
_trackers = new List<ITradeTracker>
|
_trackers = new List<ITradeTracker>
|
||||||
{
|
{
|
||||||
{ asterFactory.CreateTradeTracker(usdtSpotSymbol, period: TimeSpan.FromMinutes(5)) },
|
|
||||||
{ binanceFactory.CreateTradeTracker(usdtSpotSymbol, period: TimeSpan.FromMinutes(5)) },
|
{ binanceFactory.CreateTradeTracker(usdtSpotSymbol, period: TimeSpan.FromMinutes(5)) },
|
||||||
{ bingXFactory.CreateTradeTracker(usdtSpotSymbol, period: TimeSpan.FromMinutes(5)) },
|
{ bingXFactory.CreateTradeTracker(usdtSpotSymbol, period: TimeSpan.FromMinutes(5)) },
|
||||||
{ bitfinexFactory.CreateTradeTracker(usdtSpotSymbol, period: TimeSpan.FromMinutes(5)) },
|
{ bitfinexFactory.CreateTradeTracker(usdtSpotSymbol, period: TimeSpan.FromMinutes(5)) },
|
||||||
|
|||||||
@ -33,7 +33,6 @@ namespace BlazorClient
|
|||||||
restOptions.ApiCredentials = new ApiCredentials("KEY", "SECRET");
|
restOptions.ApiCredentials = new ApiCredentials("KEY", "SECRET");
|
||||||
});
|
});
|
||||||
|
|
||||||
services.AddAster();
|
|
||||||
services.AddBingX();
|
services.AddBingX();
|
||||||
services.AddBitfinex();
|
services.AddBitfinex();
|
||||||
services.AddBitget();
|
services.AddBitget();
|
||||||
|
|||||||
@ -8,7 +8,6 @@
|
|||||||
@using Microsoft.JSInterop
|
@using Microsoft.JSInterop
|
||||||
@using BlazorClient
|
@using BlazorClient
|
||||||
@using BlazorClient.Shared
|
@using BlazorClient.Shared
|
||||||
@using Aster.Net.Interfaces.Clients;
|
|
||||||
@using Binance.Net.Interfaces.Clients;
|
@using Binance.Net.Interfaces.Clients;
|
||||||
@using BingX.Net.Interfaces.Clients;
|
@using BingX.Net.Interfaces.Clients;
|
||||||
@using Bitfinex.Net.Interfaces.Clients;
|
@using Bitfinex.Net.Interfaces.Clients;
|
||||||
|
|||||||
@ -12,7 +12,6 @@ Full list of all libraries part of the CryptoExchange.Net ecosystem. Consider us
|
|||||||
|
|
||||||
||Exchange|Type|Repository|Nuget|Referral Link|Referral Fee Discount|
|
||Exchange|Type|Repository|Nuget|Referral Link|Referral Fee Discount|
|
||||||
|--|--|--|--|--|--|--|
|
|--|--|--|--|--|--|--|
|
||||||
||Aster|DEX|[JKorf/Aster.Net](https://github.com/JKorf/Aster.Net)|[](https://www.nuget.org/packages/JKorf.Aster.Net)|[Link](https://www.asterdex.com/en/referral/FD2E11)|4%|
|
|
||||||
||Binance|CEX|[JKorf/Binance.Net](https://github.com/JKorf/Binance.Net)|[](https://www.nuget.org/packages/Binance.Net)|[Link](https://accounts.binance.com/register?ref=X5K3F2ZG)|20%|
|
||Binance|CEX|[JKorf/Binance.Net](https://github.com/JKorf/Binance.Net)|[](https://www.nuget.org/packages/Binance.Net)|[Link](https://accounts.binance.com/register?ref=X5K3F2ZG)|20%|
|
||||||
||BingX|CEX|[JKorf/BingX.Net](https://github.com/JKorf/BingX.Net)|[](https://www.nuget.org/packages/JK.BingX.Net)|[Link](https://bingx.com/invite/FFHRJKWG/)|20%|
|
||BingX|CEX|[JKorf/BingX.Net](https://github.com/JKorf/BingX.Net)|[](https://www.nuget.org/packages/JK.BingX.Net)|[Link](https://bingx.com/invite/FFHRJKWG/)|20%|
|
||||||
||Bitfinex|CEX|[JKorf/Bitfinex.Net](https://github.com/JKorf/Bitfinex.Net)|[](https://www.nuget.org/packages/Bitfinex.Net)|-|-|
|
||Bitfinex|CEX|[JKorf/Bitfinex.Net](https://github.com/JKorf/Bitfinex.Net)|[](https://www.nuget.org/packages/Bitfinex.Net)|-|-|
|
||||||
@ -65,11 +64,6 @@ Make a one time donation in a crypto currency of your choice. If you prefer to d
|
|||||||
Alternatively, sponsor me on Github using [Github Sponsors](https://github.com/sponsors/JKorf).
|
Alternatively, sponsor me on Github using [Github Sponsors](https://github.com/sponsors/JKorf).
|
||||||
|
|
||||||
## Release notes
|
## Release notes
|
||||||
* Version 9.9.0 - 06 Oct 2025
|
|
||||||
* Updated socket Subscription status handling
|
|
||||||
* Added SubscriptionStatusChanged event to UpdateSubscription (SubscribeAsync methods reponse)
|
|
||||||
* Fixed timing issue for connection events in UpdateSubscription
|
|
||||||
|
|
||||||
* Version 9.8.0 - 30 Sep 2025
|
* Version 9.8.0 - 30 Sep 2025
|
||||||
* Added ContractAddress to SharedAsset model
|
* Added ContractAddress to SharedAsset model
|
||||||
* Added ITrackerFactory interface
|
* Added ITrackerFactory interface
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user