mirror of
https://github.com/JKorf/CryptoExchange.Net.git
synced 2026-08-13 01:12:59 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 73377fbb87 | |||
| 3a00d6371a | |||
| caf6d36bcd | |||
| e078a373da | |||
| 007743f5a1 |
@@ -625,6 +625,21 @@ namespace CryptoExchange.Net.Clients
|
||||
return Task.FromResult(CallResult.Ok());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the connection can be used for a new subscription or query with the provided parameters
|
||||
/// </summary>
|
||||
/// <param name="connection">The connection to check</param>
|
||||
/// <param name="address">The address set by the request</param>
|
||||
/// <param name="authenticated">Whether the request needs an authenticated connection</param>
|
||||
/// <param name="topic">Topic of the request</param>
|
||||
/// <returns>True if connection can be used</returns>
|
||||
protected virtual bool ConnectionCanBeUsedFor(SocketConnection connection, string address, bool authenticated, string? topic = null)
|
||||
{
|
||||
return connection.ConnectionUriString.Equals(address.TrimEnd('/'), StringComparison.Ordinal)
|
||||
&& connection.ApiClient.ClientName.Equals(ClientName, StringComparison.Ordinal)
|
||||
&& (AllowTopicsOnTheSameConnection || !connection.Topics.Contains(topic));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a connection for a new subscription or query. Can be an existing if there are open position or a new one.
|
||||
/// </summary>
|
||||
@@ -643,10 +658,7 @@ namespace CryptoExchange.Net.Clients
|
||||
string? topic = null,
|
||||
int individualSubscriptionCount = 1)
|
||||
{
|
||||
var socketQuery = _socketConnections.Where(s => s.Value.ConnectionUriString.Equals(address.TrimEnd('/'), StringComparison.Ordinal)
|
||||
&& s.Value.ApiClient.ClientName.Equals(ClientName, StringComparison.Ordinal)
|
||||
&& (AllowTopicsOnTheSameConnection || !s.Value.Topics.Contains(topic)))
|
||||
.Select(x => x.Value); // Don't ToList this so the query is executed again when called
|
||||
var socketQuery = _socketConnections.Where(s => ConnectionCanBeUsedFor(s.Value, address, authenticated, topic)).Select(x => x.Value); // Don't ToList this so the query is executed again when called
|
||||
|
||||
// If all current socket connections are reconnecting or resubscribing wait for that to finish as we can probably use the existing connection
|
||||
var delayStart = DateTime.UtcNow;
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
<PackageId>CryptoExchange.Net</PackageId>
|
||||
<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>
|
||||
<PackageVersion>12.2.0</PackageVersion>
|
||||
<AssemblyVersion>12.2.0</AssemblyVersion>
|
||||
<FileVersion>12.2.0</FileVersion>
|
||||
<PackageVersion>12.3.0</PackageVersion>
|
||||
<AssemblyVersion>12.3.0</AssemblyVersion>
|
||||
<FileVersion>12.3.0</FileVersion>
|
||||
<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>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
|
||||
@@ -68,9 +68,14 @@ namespace CryptoExchange.Net.SharedApis
|
||||
return ArgumentError.Invalid("TradingMode", $"TradingMode.{tradingMode} is not supported, supported types: {string.Join(", ", supportedTradingModes)}");
|
||||
|
||||
foreach (var param in RequiredExchangeParameters)
|
||||
{
|
||||
{
|
||||
if (param.Names!.All(x => ExchangeParameters.HasValue(exchangeParameters, Exchange, x, param.ValueType) != true))
|
||||
return ArgumentError.Invalid(string.Join("/", param.Names!), $"One of exchange parameters `{string.Join(", ", param.Names!)}` for exchange `{Exchange}` should be provided. Example: {param.ExampleValue}");
|
||||
{
|
||||
if (param.Names.Length == 1)
|
||||
return ArgumentError.Invalid(string.Join("/", param.Names!), $"Exchange parameter `{param.Names[0]}` for exchange `{Exchange}` should be provided. Example: {param.ExampleValue}");
|
||||
else
|
||||
return ArgumentError.Invalid(string.Join("/", param.Names!), $"One of exchange parameters `{string.Join(", ", param.Names!)}` for exchange `{Exchange}` should be provided. Example: {param.ExampleValue}");
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -149,7 +154,12 @@ namespace CryptoExchange.Net.SharedApis
|
||||
foreach (var param in RequiredOptionalParameters)
|
||||
{
|
||||
if (param.Names!.All(x => _requestProperties.Single(p => p.Name == x).GetValue(request, null) == null))
|
||||
return ArgumentError.Invalid(string.Join("/", param.Names!), $"One of optional parameters `{string.Join(", ", param.Names!)}` for exchange `{Exchange}` should be provided. Example: {param.ExampleValue}");
|
||||
{
|
||||
if (param.Names.Length == 1)
|
||||
return ArgumentError.Invalid(string.Join("/", param.Names!), $"Optional parameter `{param.Names[0]}` for exchange `{Exchange}` should be provided. Example: {param.ExampleValue}");
|
||||
else
|
||||
return ArgumentError.Invalid(string.Join("/", param.Names!), $"One of optional parameters `{string.Join(", ", param.Names!)}` for exchange `{Exchange}` should be provided. Example: {param.ExampleValue}");
|
||||
}
|
||||
}
|
||||
|
||||
if (request is SharedSymbolRequest symbolsRequest)
|
||||
|
||||
@@ -54,10 +54,18 @@ namespace CryptoExchange.Net.SharedApis
|
||||
/// Order price
|
||||
/// </summary>
|
||||
public decimal? OrderPrice { get; set; }
|
||||
private decimal? _averagePrice;
|
||||
/// <summary>
|
||||
/// Average price
|
||||
/// Average fill price
|
||||
/// </summary>
|
||||
public decimal? AveragePrice { get; set; }
|
||||
public decimal? AveragePrice
|
||||
{
|
||||
get => _averagePrice > 0 ? _averagePrice
|
||||
: (QuantityFilled?.QuantityInBaseAsset > 0 && QuantityFilled?.QuantityInQuoteAsset > 0
|
||||
? QuantityFilled.QuantityInQuoteAsset / QuantityFilled.QuantityInBaseAsset
|
||||
: null);
|
||||
set => _averagePrice = value;
|
||||
}
|
||||
/// <summary>
|
||||
/// Client order id
|
||||
/// </summary>
|
||||
|
||||
@@ -46,10 +46,18 @@ namespace CryptoExchange.Net.SharedApis
|
||||
/// Order price
|
||||
/// </summary>
|
||||
public decimal? OrderPrice { get; set; }
|
||||
private decimal? _averagePrice;
|
||||
/// <summary>
|
||||
/// Average fill price
|
||||
/// </summary>
|
||||
public decimal? AveragePrice { get; set; }
|
||||
public decimal? AveragePrice
|
||||
{
|
||||
get => _averagePrice > 0 ? _averagePrice
|
||||
: (QuantityFilled?.QuantityInBaseAsset > 0 && QuantityFilled?.QuantityInQuoteAsset > 0
|
||||
? QuantityFilled.QuantityInQuoteAsset / QuantityFilled.QuantityInBaseAsset
|
||||
: null);
|
||||
set => _averagePrice = value;
|
||||
}
|
||||
/// <summary>
|
||||
/// Client order id
|
||||
/// </summary>
|
||||
|
||||
@@ -142,7 +142,7 @@ namespace CryptoExchange.Net.Testing
|
||||
var issues = SystemTextJsonComparer.CompareData(expressionBody.Method.Name, data, originalData, compareNestedProperty, ignoreProperties, useSingleArrayItem ?? false);
|
||||
foreach(var issue in issues)
|
||||
{
|
||||
if (issue is MissingPropertyException)
|
||||
if (issue is MissingPropertyException && !warnings?.Any(x => x.Message == issue.Message) == true)
|
||||
warnings?.Add(issue);
|
||||
else
|
||||
errors.Add(issue);
|
||||
|
||||
@@ -127,6 +127,12 @@ Various:
|
||||
* PlatformInfo now required support environment names in the constructor
|
||||
|
||||
## Release notes
|
||||
* Version 12.3.0 - 23 Jul 2026
|
||||
* Added calculation of AveragePrice on Shared order models if data is available and AveragePrice is not set
|
||||
* Extracted ConnectionCanBeUsedFor method in SocketApiClient for easier custom logic implementation
|
||||
* Updated some Shared APIs error messages
|
||||
* Remove duplicate warnings from testing output
|
||||
|
||||
* Version 12.2.0 - 20 Jul 2026
|
||||
* Added SpotSymbolCatalog to Shared ISpotSymbolRestClient interface
|
||||
* Added FuturesSymbolCatalog to Shared IFuturesSymbolRestClient interface
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
> Base C#/.NET library for cryptocurrency exchange API client implementations. Provides a standardized abstraction (REST, WebSocket, authentication, rate limiting, error handling, order book management, shared cross-exchange interfaces) that 28+ exchange-specific libraries are built on top of.
|
||||
|
||||
CryptoExchange.Net itself is not used directly — install one of the exchange-specific libraries (Binance.Net, Bybit.Net, OKX.Net, Kraken.Net, Coinbase.Net, etc.) or `CryptoClients.Net` to access all exchanges via a single bundle. The base library is what makes the entire ecosystem feel consistent: same `HttpResult<T>` REST result pattern, same `WebSocketResult<UpdateSubscription>` websocket subscription pattern, same DI registration, same shared interfaces across all exchanges. Current version: 12.2.0. Targets netstandard2.0, netstandard2.1, net8.0, net9.0, net10.0. Native AOT supported.
|
||||
CryptoExchange.Net itself is not used directly — install one of the exchange-specific libraries (Binance.Net, Bybit.Net, OKX.Net, Kraken.Net, Coinbase.Net, etc.) or `CryptoClients.Net` to access all exchanges via a single bundle. The base library is what makes the entire ecosystem feel consistent: same `HttpResult<T>` REST result pattern, same `WebSocketResult<UpdateSubscription>` websocket subscription pattern, same DI registration, same shared interfaces across all exchanges. Current version: 12.3.0. Targets netstandard2.0, netstandard2.1, net8.0, net9.0, net10.0. Native AOT supported.
|
||||
|
||||
The standout feature for cross-exchange code is `CryptoExchange.Net.SharedApis` — a set of interfaces (`ISpotTickerRestClient`, `ISpotOrderRestClient`, `IBalanceRestClient`, etc.) implemented by every exchange library. Same call signature works against any exchange.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user