mirror of
https://github.com/JKorf/CryptoExchange.Net.git
synced 2026-10-22 19:10:55 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6df3dcc422 | |||
| 9eceaf1eea | |||
| f1ad4e9920 | |||
| ee53dfe139 | |||
| 186f30d4b5 |
@@ -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>13.2.0</PackageVersion>
|
<PackageVersion>13.2.2</PackageVersion>
|
||||||
<AssemblyVersion>13.2.0</AssemblyVersion>
|
<AssemblyVersion>13.2.2</AssemblyVersion>
|
||||||
<FileVersion>13.2.0</FileVersion>
|
<FileVersion>13.2.2</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>
|
||||||
|
|||||||
@@ -1083,6 +1083,10 @@ namespace CryptoExchange.Net.Sockets.Default
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected bool IsCoveredByEarlierSubscription(Subscription subscription)
|
protected bool IsCoveredByEarlierSubscription(Subscription subscription)
|
||||||
{
|
{
|
||||||
|
if (subscription.MessageRouter.Routes.Length == 0)
|
||||||
|
// Can be subscription which only knows what to listen to after receiving the subscribe response, for example Bitfinex
|
||||||
|
return false;
|
||||||
|
|
||||||
foreach (var other in _listeners.OfType<Subscription>())
|
foreach (var other in _listeners.OfType<Subscription>())
|
||||||
{
|
{
|
||||||
if (other == subscription)
|
if (other == subscription)
|
||||||
|
|||||||
@@ -168,12 +168,18 @@ namespace CryptoExchange.Net.Testing
|
|||||||
{
|
{
|
||||||
// Validate request body
|
// Validate request body
|
||||||
Dictionary<string, object> bodyParameters;
|
Dictionary<string, object> bodyParameters;
|
||||||
if (result.RequestBody!.StartsWith("{") || result.RequestBody.StartsWith("["))
|
if (string.IsNullOrEmpty(result.RequestBody))
|
||||||
{
|
{
|
||||||
|
bodyParameters = new Dictionary<string, object>();
|
||||||
|
}
|
||||||
|
else if (result.RequestBody!.StartsWith("{") || result.RequestBody.StartsWith("["))
|
||||||
|
{
|
||||||
|
// Json
|
||||||
bodyParameters = JsonSerializer.Deserialize<Dictionary<string, object>>(result.RequestBody!)!;
|
bodyParameters = JsonSerializer.Deserialize<Dictionary<string, object>>(result.RequestBody!)!;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// Form data
|
||||||
var splitKvp = result.RequestBody.Split('&');
|
var splitKvp = result.RequestBody.Split('&');
|
||||||
bodyParameters = splitKvp.Select(x => x.Split('=')).ToDictionary(x => x[0], x => (object)x[1]);
|
bodyParameters = splitKvp.Select(x => x.Split('=')).ToDictionary(x => x[0], x => (object)x[1]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,10 +28,11 @@ namespace CryptoExchange.Net.Trackers.UserData.ItemTrackers
|
|||||||
SharedAccountType accountType,
|
SharedAccountType accountType,
|
||||||
TrackerItemConfig config,
|
TrackerItemConfig config,
|
||||||
ExchangeParameters? exchangeParameters = null
|
ExchangeParameters? exchangeParameters = null
|
||||||
) : base(logger, symbolTracker, UserDataType.Balances, restClient.Exchange, config)
|
) : base(logger, symbolTracker, UserDataType.Balances, restClient.Exchange)
|
||||||
{
|
{
|
||||||
if (_socketClient == null)
|
if (socketClient == null)
|
||||||
config = config with { PollIntervalConnected = config.PollIntervalDisconnected };
|
config = config with { PollIntervalConnected = config.PollIntervalDisconnected };
|
||||||
|
SetConfig(config);
|
||||||
|
|
||||||
_restClient = restClient;
|
_restClient = restClient;
|
||||||
_socketClient = socketClient;
|
_socketClient = socketClient;
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ namespace CryptoExchange.Net.Trackers.UserData.ItemTrackers
|
|||||||
private readonly Dictionary<string, int> _openOrderNotReturnedTimes = new();
|
private readonly Dictionary<string, int> _openOrderNotReturnedTimes = new();
|
||||||
private readonly TimeSpan _pollOverlapPeriod = TimeSpan.FromSeconds(3);
|
private readonly TimeSpan _pollOverlapPeriod = TimeSpan.FromSeconds(3);
|
||||||
|
|
||||||
|
private bool _openOrderWarningDone = false;
|
||||||
internal event Func<UpdateSource, SharedUserTrade[], Task>? OnTradeUpdate;
|
internal event Func<UpdateSource, SharedUserTrade[], Task>? OnTradeUpdate;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -39,10 +40,11 @@ namespace CryptoExchange.Net.Trackers.UserData.ItemTrackers
|
|||||||
IEnumerable<SharedSymbol> symbols,
|
IEnumerable<SharedSymbol> symbols,
|
||||||
bool onlyTrackProvidedSymbols,
|
bool onlyTrackProvidedSymbols,
|
||||||
ExchangeParameters? exchangeParameters = null
|
ExchangeParameters? exchangeParameters = null
|
||||||
) : base(logger, symbolTracker, UserDataType.Orders, openRestClient.Exchange, config)
|
) : base(logger, symbolTracker, UserDataType.Orders, openRestClient.Exchange)
|
||||||
{
|
{
|
||||||
if (_socketClient == null)
|
if (socketClient == null)
|
||||||
config = config with { PollIntervalConnected = config.PollIntervalDisconnected };
|
config = config with { PollIntervalConnected = config.PollIntervalDisconnected };
|
||||||
|
SetConfig(config);
|
||||||
|
|
||||||
_openOrdersClient = openRestClient;
|
_openOrdersClient = openRestClient;
|
||||||
_closedOrdersClient = closedRestClient;
|
_closedOrdersClient = closedRestClient;
|
||||||
@@ -234,7 +236,14 @@ namespace CryptoExchange.Net.Trackers.UserData.ItemTrackers
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
foreach (var symbol in _symbolTracker.GetTrackedSymbols())
|
var trackedSymbols = _symbolTracker.GetTrackedSymbols();
|
||||||
|
if (!_openOrderWarningDone && trackedSymbols.Count() == 0)
|
||||||
|
{
|
||||||
|
_openOrderWarningDone = true;
|
||||||
|
_logger.LogDebug("No tracked symbols specified while symbol is required to retrieve open orders. Tracked symbols should be updated before orders may be returned");
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var symbol in trackedSymbols)
|
||||||
{
|
{
|
||||||
var openOrdersResult = await _openOrdersClient.GetOpenFuturesOrdersAsync(new GetOpenOrdersRequest(symbol, exchangeParameters: _exchangeParameters)).ConfigureAwait(false);
|
var openOrdersResult = await _openOrdersClient.GetOpenFuturesOrdersAsync(new GetOpenOrdersRequest(symbol, exchangeParameters: _exchangeParameters)).ConfigureAwait(false);
|
||||||
if (!openOrdersResult.Success)
|
if (!openOrdersResult.Success)
|
||||||
|
|||||||
@@ -34,10 +34,11 @@ namespace CryptoExchange.Net.Trackers.UserData.ItemTrackers
|
|||||||
IEnumerable<SharedSymbol> symbols,
|
IEnumerable<SharedSymbol> symbols,
|
||||||
bool onlyTrackProvidedSymbols,
|
bool onlyTrackProvidedSymbols,
|
||||||
ExchangeParameters? exchangeParameters = null
|
ExchangeParameters? exchangeParameters = null
|
||||||
) : base(logger, symbolTracker, UserDataType.Trades, restClient.Exchange, config)
|
) : base(logger, symbolTracker, UserDataType.Trades, restClient.Exchange)
|
||||||
{
|
{
|
||||||
if (_socketClient == null)
|
if (socketClient == null)
|
||||||
config = config with { PollIntervalConnected = config.PollIntervalDisconnected };
|
config = config with { PollIntervalConnected = config.PollIntervalDisconnected };
|
||||||
|
SetConfig(config);
|
||||||
|
|
||||||
_restClient = restClient;
|
_restClient = restClient;
|
||||||
_socketClient = socketClient;
|
_socketClient = socketClient;
|
||||||
|
|||||||
@@ -37,10 +37,11 @@ namespace CryptoExchange.Net.Trackers.UserData.ItemTrackers
|
|||||||
bool onlyTrackProvidedSymbols,
|
bool onlyTrackProvidedSymbols,
|
||||||
bool websocketPositionUpdatesAreFullSnapshots,
|
bool websocketPositionUpdatesAreFullSnapshots,
|
||||||
ExchangeParameters? exchangeParameters = null
|
ExchangeParameters? exchangeParameters = null
|
||||||
) : base(logger, symbolTracker, UserDataType.Positions, restClient.Exchange, config)
|
) : base(logger, symbolTracker, UserDataType.Positions, restClient.Exchange)
|
||||||
{
|
{
|
||||||
if (_socketClient == null)
|
if (socketClient == null)
|
||||||
config = config with { PollIntervalConnected = config.PollIntervalDisconnected };
|
config = config with { PollIntervalConnected = config.PollIntervalDisconnected };
|
||||||
|
SetConfig(config);
|
||||||
|
|
||||||
_restClient = restClient;
|
_restClient = restClient;
|
||||||
_socketClient = socketClient;
|
_socketClient = socketClient;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ namespace CryptoExchange.Net.Trackers.UserData.ItemTrackers
|
|||||||
private readonly bool _timeFilterSupportedClosedOrders;
|
private readonly bool _timeFilterSupportedClosedOrders;
|
||||||
private readonly Dictionary<string, int> _openOrderNotReturnedTimes = new();
|
private readonly Dictionary<string, int> _openOrderNotReturnedTimes = new();
|
||||||
private readonly TimeSpan _pollOverlapPeriod = TimeSpan.FromSeconds(3);
|
private readonly TimeSpan _pollOverlapPeriod = TimeSpan.FromSeconds(3);
|
||||||
|
private bool _openOrderWarningDone = false;
|
||||||
|
|
||||||
internal event Func<UpdateSource, SharedUserTrade[], Task>? OnTradeUpdate;
|
internal event Func<UpdateSource, SharedUserTrade[], Task>? OnTradeUpdate;
|
||||||
|
|
||||||
@@ -39,10 +40,11 @@ namespace CryptoExchange.Net.Trackers.UserData.ItemTrackers
|
|||||||
IEnumerable<SharedSymbol> symbols,
|
IEnumerable<SharedSymbol> symbols,
|
||||||
bool onlyTrackProvidedSymbols,
|
bool onlyTrackProvidedSymbols,
|
||||||
ExchangeParameters? exchangeParameters = null
|
ExchangeParameters? exchangeParameters = null
|
||||||
) : base(logger, symbolTracker, UserDataType.Orders, openOrderClient.Exchange, config)
|
) : base(logger, symbolTracker, UserDataType.Orders, openOrderClient.Exchange)
|
||||||
{
|
{
|
||||||
if (_socketClient == null)
|
if (socketClient == null)
|
||||||
config = config with { PollIntervalConnected = config.PollIntervalDisconnected };
|
config = config with { PollIntervalConnected = config.PollIntervalDisconnected };
|
||||||
|
SetConfig(config);
|
||||||
|
|
||||||
_openOrderClient = openOrderClient;
|
_openOrderClient = openOrderClient;
|
||||||
_closedOrderClient = closedOrderClient;
|
_closedOrderClient = closedOrderClient;
|
||||||
@@ -244,7 +246,14 @@ namespace CryptoExchange.Net.Trackers.UserData.ItemTrackers
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
foreach (var symbol in _symbolTracker.GetTrackedSymbols())
|
var trackedSymbols = _symbolTracker.GetTrackedSymbols();
|
||||||
|
if (!_openOrderWarningDone && trackedSymbols.Count() == 0)
|
||||||
|
{
|
||||||
|
_openOrderWarningDone = true;
|
||||||
|
_logger.LogDebug("No tracked symbols specified while symbol is required to retrieve open orders. Tracked symbols should be updated before orders may be returned");
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var symbol in trackedSymbols)
|
||||||
{
|
{
|
||||||
var openOrdersResult = await _openOrderClient.GetOpenSpotOrdersAsync(new GetOpenOrdersRequest(symbol, exchangeParameters: _exchangeParameters)).ConfigureAwait(false);
|
var openOrdersResult = await _openOrderClient.GetOpenSpotOrdersAsync(new GetOpenOrdersRequest(symbol, exchangeParameters: _exchangeParameters)).ConfigureAwait(false);
|
||||||
if (!openOrdersResult.Success)
|
if (!openOrdersResult.Success)
|
||||||
|
|||||||
@@ -34,10 +34,11 @@ namespace CryptoExchange.Net.Trackers.UserData.ItemTrackers
|
|||||||
IEnumerable<SharedSymbol> symbols,
|
IEnumerable<SharedSymbol> symbols,
|
||||||
bool onlyTrackProvidedSymbols,
|
bool onlyTrackProvidedSymbols,
|
||||||
ExchangeParameters? exchangeParameters = null
|
ExchangeParameters? exchangeParameters = null
|
||||||
) : base(logger, symbolTracker, UserDataType.Trades, restClient.Exchange, config)
|
) : base(logger, symbolTracker, UserDataType.Trades, restClient.Exchange)
|
||||||
{
|
{
|
||||||
if (_socketClient == null)
|
if (socketClient == null)
|
||||||
config = config with { PollIntervalConnected = config.PollIntervalDisconnected };
|
config = config with { PollIntervalConnected = config.PollIntervalDisconnected };
|
||||||
|
SetConfig(config);
|
||||||
|
|
||||||
_restClient = restClient;
|
_restClient = restClient;
|
||||||
_socketClient = socketClient;
|
_socketClient = socketClient;
|
||||||
|
|||||||
@@ -242,15 +242,21 @@ namespace CryptoExchange.Net.Trackers.UserData.ItemTrackers
|
|||||||
ILogger logger,
|
ILogger logger,
|
||||||
UserDataSymbolTracker symbolTracker,
|
UserDataSymbolTracker symbolTracker,
|
||||||
UserDataType dataType,
|
UserDataType dataType,
|
||||||
string exchange,
|
string exchange) : base(logger, dataType, exchange)
|
||||||
TrackerItemConfig config) : base(logger, dataType, exchange)
|
{
|
||||||
|
_isSymbolModel = typeof(T).IsSubclassOf(typeof(SharedSymbolModel));
|
||||||
|
_symbolTracker = symbolTracker;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set the tracker item config
|
||||||
|
/// </summary>
|
||||||
|
protected void SetConfig(TrackerItemConfig config)
|
||||||
{
|
{
|
||||||
_pollIntervalDisconnected = config.PollIntervalDisconnected;
|
_pollIntervalDisconnected = config.PollIntervalDisconnected;
|
||||||
_pollIntervalConnected = config.PollIntervalConnected;
|
_pollIntervalConnected = config.PollIntervalConnected;
|
||||||
_pollAtStart = config.PollAtStart;
|
_pollAtStart = config.PollAtStart;
|
||||||
_retentionTime = config is TrackerTimedItemConfig timeConfig ? timeConfig.RetentionTime : TimeSpan.MaxValue;
|
_retentionTime = config is TrackerTimedItemConfig timeConfig ? timeConfig.RetentionTime : TimeSpan.MaxValue;
|
||||||
_isSymbolModel = typeof(T).IsSubclassOf(typeof(SharedSymbolModel));
|
|
||||||
_symbolTracker = symbolTracker;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -127,6 +127,14 @@ Various:
|
|||||||
* PlatformInfo now required support environment names in the constructor
|
* PlatformInfo now required support environment names in the constructor
|
||||||
|
|
||||||
## Release notes
|
## Release notes
|
||||||
|
* Version 13.2.2 - 22 Oct 2026
|
||||||
|
* Fixed UserDataTracker config not getting set correctly
|
||||||
|
* Added UserDataTracker warning for missing tracked symbols if open orders request requires it
|
||||||
|
|
||||||
|
* Version 13.2.1 - 19 Oct 2026
|
||||||
|
* Fixed subscription without any predefined routes failing to subscribe
|
||||||
|
* Fixed test validation failing with empty body string
|
||||||
|
|
||||||
* Version 13.2.0 - 13 Oct 2026
|
* Version 13.2.0 - 13 Oct 2026
|
||||||
* Added Shared API ISubscribeFundingInfoSocket
|
* Added Shared API ISubscribeFundingInfoSocket
|
||||||
* Added DelayAfterConnect to SocketApiOptions
|
* Added DelayAfterConnect to SocketApiOptions
|
||||||
|
|||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
# CryptoExchange.Net — full AI context
|
# CryptoExchange.Net — full AI context
|
||||||
|
|
||||||
Library: CryptoExchange.Net
|
Library: CryptoExchange.Net
|
||||||
Library version: 13.2.0
|
Library version: 13.2.2
|
||||||
CryptoExchange.Net package version: 13.2.0
|
CryptoExchange.Net package version: 13.2.2
|
||||||
Language: C#/.NET
|
Language: C#/.NET
|
||||||
Targets: netstandard2.0, netstandard2.1, net8.0, net9.0, net10.0
|
Targets: netstandard2.0, netstandard2.1, net8.0, net9.0, net10.0
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
> Base C#/.NET library used by 28+ cryptocurrency exchange clients. It standardizes REST, WebSocket, authentication, rate limiting, results, and exchange-agnostic Shared APIs.
|
> Base C#/.NET library used by 28+ cryptocurrency exchange clients. It standardizes REST, WebSocket, authentication, rate limiting, results, and exchange-agnostic Shared APIs.
|
||||||
|
|
||||||
CryptoExchange.Net is not an exchange client by itself. Install exchange-specific packages such as Binance.Net, Bybit.Net, JK.OKX.Net, Kraken.Net, or Coinbase.Net, or install `CryptoClients.Net` for the bundle. Current release: 13.2.0. Targets netstandard2.0, netstandard2.1, net8.0, net9.0, and net10.0; Native AOT is supported.
|
CryptoExchange.Net is not an exchange client by itself. Install exchange-specific packages such as Binance.Net, Bybit.Net, JK.OKX.Net, Kraken.Net, or Coinbase.Net, or install `CryptoClients.Net` for the bundle. Current release: 13.2.2. Targets netstandard2.0, netstandard2.1, net8.0, net9.0, and net10.0; Native AOT is supported.
|
||||||
|
|
||||||
## Shared API V2
|
## Shared API V2
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user