1
0
mirror of https://github.com/JKorf/CryptoExchange.Net synced 2025-06-08 00:16:27 +00:00

Compare commits

..

No commits in common. "master" and "9.0.0" have entirely different histories.

27 changed files with 128 additions and 344 deletions

View File

@ -7,7 +7,6 @@ using System.Text.Json.Serialization;
using NUnit.Framework.Legacy; using NUnit.Framework.Legacy;
using CryptoExchange.Net.Converters; using CryptoExchange.Net.Converters;
using CryptoExchange.Net.Testing.Comparers; using CryptoExchange.Net.Testing.Comparers;
using CryptoExchange.Net.SharedApis;
namespace CryptoExchange.Net.UnitTests namespace CryptoExchange.Net.UnitTests
{ {
@ -299,40 +298,6 @@ namespace CryptoExchange.Net.UnitTests
Assert.That(deserialized.Prop8.Prop31, Is.EqualTo(5)); Assert.That(deserialized.Prop8.Prop31, Is.EqualTo(5));
Assert.That(deserialized.Prop8.Prop32, Is.EqualTo("101")); Assert.That(deserialized.Prop8.Prop32, Is.EqualTo("101"));
} }
[TestCase(TradingMode.Spot, "ETH", "USDT", null)]
[TestCase(TradingMode.PerpetualLinear, "ETH", "USDT", null)]
[TestCase(TradingMode.DeliveryLinear, "ETH", "USDT", 1748432430)]
public void TestSharedSymbolConversion(TradingMode tradingMode, string baseAsset, string quoteAsset, int? deliverTime)
{
DateTime? time = deliverTime == null ? null : DateTimeConverter.ParseFromDouble(deliverTime.Value);
var symbol = new SharedSymbol(tradingMode, baseAsset, quoteAsset, time);
var serialized = JsonSerializer.Serialize(symbol);
var restored = JsonSerializer.Deserialize<SharedSymbol>(serialized);
Assert.That(restored.TradingMode, Is.EqualTo(symbol.TradingMode));
Assert.That(restored.BaseAsset, Is.EqualTo(symbol.BaseAsset));
Assert.That(restored.QuoteAsset, Is.EqualTo(symbol.QuoteAsset));
Assert.That(restored.DeliverTime, Is.EqualTo(symbol.DeliverTime));
}
[TestCase(0.1, null, null)]
[TestCase(0.1, 0.1, null)]
[TestCase(0.1, 0.1, 0.1)]
[TestCase(null, 0.1, null)]
[TestCase(null, 0.1, 0.1)]
public void TestSharedQuantityConversion(double? baseQuantity, double? quoteQuantity, double? contractQuantity)
{
var symbol = new SharedOrderQuantity((decimal?)baseQuantity, (decimal?)quoteQuantity, (decimal?)contractQuantity);
var serialized = JsonSerializer.Serialize(symbol);
var restored = JsonSerializer.Deserialize<SharedOrderQuantity>(serialized);
Assert.That(restored.QuantityInBaseAsset, Is.EqualTo(symbol.QuantityInBaseAsset));
Assert.That(restored.QuantityInQuoteAsset, Is.EqualTo(symbol.QuantityInQuoteAsset));
Assert.That(restored.QuantityInContracts, Is.EqualTo(symbol.QuantityInContracts));
}
} }
public class STJDecimalObject public class STJDecimalObject

View File

@ -114,7 +114,7 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations
public CallResult ConnectSocketSub(SocketConnection sub) public CallResult ConnectSocketSub(SocketConnection sub)
{ {
return ConnectSocketAsync(sub, default).Result; return ConnectSocketAsync(sub).Result;
} }
public override string GetListenerIdentifier(IMessageAccessor message) public override string GetListenerIdentifier(IMessageAccessor message)

View File

@ -244,7 +244,7 @@ namespace CryptoExchange.Net.Clients
var needsConnecting = !socketConnection.Connected; var needsConnecting = !socketConnection.Connected;
var connectResult = await ConnectIfNeededAsync(socketConnection, subscription.Authenticated, ct).ConfigureAwait(false); var connectResult = await ConnectIfNeededAsync(socketConnection, subscription.Authenticated).ConfigureAwait(false);
if (!connectResult) if (!connectResult)
return new CallResult<UpdateSubscription>(connectResult.Error!); return new CallResult<UpdateSubscription>(connectResult.Error!);
@ -268,7 +268,7 @@ namespace CryptoExchange.Net.Clients
if (subQuery != null) if (subQuery != null)
{ {
// Send the request and wait for answer // Send the request and wait for answer
var subResult = await socketConnection.SendAndWaitQueryAsync(subQuery, waitEvent, ct).ConfigureAwait(false); var subResult = await socketConnection.SendAndWaitQueryAsync(subQuery, waitEvent).ConfigureAwait(false);
if (!subResult) if (!subResult)
{ {
waitEvent?.Set(); waitEvent?.Set();
@ -352,7 +352,7 @@ namespace CryptoExchange.Net.Clients
released = true; released = true;
} }
var connectResult = await ConnectIfNeededAsync(socketConnection, query.Authenticated, ct).ConfigureAwait(false); var connectResult = await ConnectIfNeededAsync(socketConnection, query.Authenticated).ConfigureAwait(false);
if (!connectResult) if (!connectResult)
return new CallResult<THandlerResponse>(connectResult.Error!); return new CallResult<THandlerResponse>(connectResult.Error!);
} }
@ -379,14 +379,13 @@ namespace CryptoExchange.Net.Clients
/// </summary> /// </summary>
/// <param name="socket">The connection to check</param> /// <param name="socket">The connection to check</param>
/// <param name="authenticated">Whether the socket should authenticated</param> /// <param name="authenticated">Whether the socket should authenticated</param>
/// <param name="ct">Cancellation token</param>
/// <returns></returns> /// <returns></returns>
protected virtual async Task<CallResult> ConnectIfNeededAsync(SocketConnection socket, bool authenticated, CancellationToken ct) protected virtual async Task<CallResult> ConnectIfNeededAsync(SocketConnection socket, bool authenticated)
{ {
if (socket.Connected) if (socket.Connected)
return CallResult.SuccessResult; return CallResult.SuccessResult;
var connectResult = await ConnectSocketAsync(socket, ct).ConfigureAwait(false); var connectResult = await ConnectSocketAsync(socket).ConfigureAwait(false);
if (!connectResult) if (!connectResult)
return connectResult; return connectResult;
@ -580,11 +579,10 @@ namespace CryptoExchange.Net.Clients
/// Connect a socket /// Connect a socket
/// </summary> /// </summary>
/// <param name="socketConnection">The socket to connect</param> /// <param name="socketConnection">The socket to connect</param>
/// <param name="ct">Cancellation token</param>
/// <returns></returns> /// <returns></returns>
protected virtual async Task<CallResult> ConnectSocketAsync(SocketConnection socketConnection, CancellationToken ct) protected virtual async Task<CallResult> ConnectSocketAsync(SocketConnection socketConnection)
{ {
var connectResult = await socketConnection.ConnectAsync(ct).ConfigureAwait(false); var connectResult = await socketConnection.ConnectAsync().ConfigureAwait(false);
if (connectResult) if (connectResult)
{ {
socketConnections.TryAdd(socketConnection.SocketId, socketConnection); socketConnections.TryAdd(socketConnection.SocketId, socketConnection);
@ -716,7 +714,7 @@ namespace CryptoExchange.Net.Clients
if (!socketResult) if (!socketResult)
return socketResult.AsDataless(); return socketResult.AsDataless();
var connectResult = await ConnectIfNeededAsync(socketResult.Data, item.Authenticated, default).ConfigureAwait(false); var connectResult = await ConnectIfNeededAsync(socketResult.Data, item.Authenticated).ConfigureAwait(false);
if (!connectResult) if (!connectResult)
return new CallResult(connectResult.Error!); return new CallResult(connectResult.Error!);
} }

View File

@ -1,60 +0,0 @@
using CryptoExchange.Net.SharedApis;
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace CryptoExchange.Net.Converters.SystemTextJson
{
internal class SharedQuantityConverter : SharedQuantityReferenceConverter<SharedQuantity> { }
internal class SharedOrderQuantityConverter : SharedQuantityReferenceConverter<SharedOrderQuantity> { }
internal class SharedQuantityReferenceConverter<T> : JsonConverter<T> where T: SharedQuantityReference, new()
{
public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.StartArray)
throw new Exception("");
reader.Read(); // Start array
var baseQuantity = reader.TokenType == JsonTokenType.Null ? (decimal?)null : reader.GetDecimal();
reader.Read();
var quoteQuantity = reader.TokenType == JsonTokenType.Null ? (decimal?)null : reader.GetDecimal();
reader.Read();
var contractQuantity = reader.TokenType == JsonTokenType.Null ? (decimal?)null : reader.GetDecimal();
reader.Read();
if (reader.TokenType != JsonTokenType.EndArray)
throw new Exception("");
reader.Read(); // End array
var result = new T();
result.QuantityInBaseAsset = baseQuantity;
result.QuantityInQuoteAsset = quoteQuantity;
result.QuantityInContracts = contractQuantity;
return result;
}
public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options)
{
writer.WriteStartArray();
if (value.QuantityInBaseAsset == null)
writer.WriteNullValue();
else
writer.WriteNumberValue(value.QuantityInBaseAsset.Value);
if (value.QuantityInQuoteAsset == null)
writer.WriteNullValue();
else
writer.WriteNumberValue(value.QuantityInQuoteAsset.Value);
if (value.QuantityInContracts == null)
writer.WriteNullValue();
else
writer.WriteNumberValue(value.QuantityInContracts.Value);
writer.WriteEndArray();
}
}
}

View File

@ -1,46 +0,0 @@
using CryptoExchange.Net.SharedApis;
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace CryptoExchange.Net.Converters.SystemTextJson
{
internal class SharedSymbolConverter : JsonConverter<SharedSymbol>
{
public override SharedSymbol? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.StartArray)
throw new Exception("");
reader.Read(); // Start array
var tradingMode = (TradingMode)Enum.Parse(typeof(TradingMode), reader.GetString()!);
reader.Read();
var baseAsset = reader.GetString()!;
reader.Read();
var quoteAsset = reader.GetString()!;
reader.Read();
var timeStr = reader.GetString()!;
var deliverTime = string.IsNullOrEmpty(timeStr) ? (DateTime?)null : DateTime.Parse(timeStr);
reader.Read();
if (reader.TokenType != JsonTokenType.EndArray)
throw new Exception("");
reader.Read(); // End array
return new SharedSymbol(tradingMode, baseAsset, quoteAsset, deliverTime);
}
public override void Write(Utf8JsonWriter writer, SharedSymbol value, JsonSerializerOptions options)
{
writer.WriteStartArray();
writer.WriteStringValue(value.TradingMode.ToString());
writer.WriteStringValue(value.BaseAsset);
writer.WriteStringValue(value.QuoteAsset);
writer.WriteStringValue(value.DeliverTime?.ToString());
writer.WriteEndArray();
}
}
}

View File

@ -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.1.0</PackageVersion> <PackageVersion>9.0.0</PackageVersion>
<AssemblyVersion>9.1.0</AssemblyVersion> <AssemblyVersion>9.0.0</AssemblyVersion>
<FileVersion>9.1.0</FileVersion> <FileVersion>9.0.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</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</PackageTags>
<RepositoryType>git</RepositoryType> <RepositoryType>git</RepositoryType>
@ -27,7 +27,7 @@
<None Include="Icon\icon.png" Pack="true" PackagePath="\" /> <None Include="Icon\icon.png" Pack="true" PackagePath="\" />
<None Include="..\README.md" Pack="true" PackagePath="\" /> <None Include="..\README.md" Pack="true" PackagePath="\" />
</ItemGroup> </ItemGroup>
<PropertyGroup Label="AOT" Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net7.0'))"> <PropertyGroup Label="AOT" Condition=" '$(TargetFramework)' == 'NET8_0' Or '$(TargetFramework)' == 'NET9_0' ">
<IsAotCompatible>true</IsAotCompatible> <IsAotCompatible>true</IsAotCompatible>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Label="Deterministic Build" Condition="'$(Configuration)' == 'Release'"> <PropertyGroup Label="Deterministic Build" Condition="'$(Configuration)' == 'Release'">
@ -37,6 +37,12 @@
<EmbedUntrackedSources>true</EmbedUntrackedSources> <EmbedUntrackedSources>true</EmbedUntrackedSources>
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild> <ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
</PropertyGroup> </PropertyGroup>
<ItemGroup Label="Deterministic Build" Condition="'$(Configuration)' == 'Release'">
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<PropertyGroup> <PropertyGroup>
<DocumentationFile>CryptoExchange.Net.xml</DocumentationFile> <DocumentationFile>CryptoExchange.Net.xml</DocumentationFile>
</PropertyGroup> </PropertyGroup>
@ -51,11 +57,10 @@
</PackageReference> </PackageReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.5" /> <PackageReference Include="Microsoft.Extensions.Http" Version="9.0.0" />
<PackageReference Include="System.Text.Json" Version="9.0.5" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.0" />
</ItemGroup> <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.0" />
<ItemGroup Label="Transitive Client Packages"> <PackageReference Include="System.Text.Json" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="9.0.5" /> <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.5" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -1,7 +1,6 @@
using CryptoExchange.Net.Objects; using CryptoExchange.Net.Objects;
using System; using System;
using System.Net.WebSockets; using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace CryptoExchange.Net.Interfaces namespace CryptoExchange.Net.Interfaces
@ -76,7 +75,7 @@ namespace CryptoExchange.Net.Interfaces
/// Connect the socket /// Connect the socket
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
Task<CallResult> ConnectAsync(CancellationToken ct); Task<CallResult> ConnectAsync();
/// <summary> /// <summary>
/// Send data /// Send data
/// </summary> /// </summary>

View File

@ -8,7 +8,6 @@ namespace CryptoExchange.Net.Logging.Extensions
{ {
private static readonly Action<ILogger, int, Exception?> _connecting; private static readonly Action<ILogger, int, Exception?> _connecting;
private static readonly Action<ILogger, int, string, Exception?> _connectionFailed; private static readonly Action<ILogger, int, string, Exception?> _connectionFailed;
private static readonly Action<ILogger, int, Exception?> _connectingCanceled;
private static readonly Action<ILogger, int, Uri, Exception?> _connected; private static readonly Action<ILogger, int, Uri, Exception?> _connected;
private static readonly Action<ILogger, int, Exception?> _startingProcessing; private static readonly Action<ILogger, int, Exception?> _startingProcessing;
private static readonly Action<ILogger, int, Exception?> _finishedProcessing; private static readonly Action<ILogger, int, Exception?> _finishedProcessing;
@ -190,12 +189,6 @@ namespace CryptoExchange.Net.Logging.Extensions
new EventId(1030, "SocketPingTimeout"), new EventId(1030, "SocketPingTimeout"),
"[Sckt {Id}] ping frame timeout; reconnecting socket"); "[Sckt {Id}] ping frame timeout; reconnecting socket");
_connectingCanceled = LoggerMessage.Define<int>(
LogLevel.Debug,
new EventId(1031, "ConnectingCanceled"),
"[Sckt {SocketId}] connecting canceled");
} }
public static void SocketConnecting( public static void SocketConnecting(
@ -377,11 +370,5 @@ namespace CryptoExchange.Net.Logging.Extensions
{ {
_socketPingTimeout(logger, socketId, null); _socketPingTimeout(logger, socketId, null);
} }
public static void SocketConnectingCanceled(
this ILogger logger, int socketId)
{
_connectingCanceled(logger, socketId, null);
}
} }
} }

View File

@ -1,8 +1,6 @@
using CryptoExchange.Net.Converters.SystemTextJson; using System;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using System.Text.Json.Serialization;
namespace CryptoExchange.Net.SharedApis namespace CryptoExchange.Net.SharedApis
{ {
@ -27,7 +25,7 @@ namespace CryptoExchange.Net.SharedApis
/// <summary> /// <summary>
/// ctor /// ctor
/// </summary> /// </summary>
internal SharedQuantityReference(decimal? baseAssetQuantity, decimal? quoteAssetQuantity, decimal? contractQuantity) protected SharedQuantityReference(decimal? baseAssetQuantity, decimal? quoteAssetQuantity, decimal? contractQuantity)
{ {
QuantityInBaseAsset = baseAssetQuantity; QuantityInBaseAsset = baseAssetQuantity;
QuantityInQuoteAsset = quoteAssetQuantity; QuantityInQuoteAsset = quoteAssetQuantity;
@ -38,7 +36,6 @@ namespace CryptoExchange.Net.SharedApis
/// <summary> /// <summary>
/// Quantity for an order /// Quantity for an order
/// </summary> /// </summary>
[JsonConverter(typeof(SharedQuantityConverter))]
public record SharedQuantity : SharedQuantityReference public record SharedQuantity : SharedQuantityReference
{ {
private SharedQuantity(decimal? baseAssetQuantity, decimal? quoteAssetQuantity, decimal? contractQuantity) private SharedQuantity(decimal? baseAssetQuantity, decimal? quoteAssetQuantity, decimal? contractQuantity)
@ -46,11 +43,6 @@ namespace CryptoExchange.Net.SharedApis
{ {
} }
/// <summary>
/// ctor
/// </summary>
public SharedQuantity() : base(null, null, null) { }
/// <summary> /// <summary>
/// Specify quantity in base asset /// Specify quantity in base asset
/// </summary> /// </summary>
@ -106,7 +98,6 @@ namespace CryptoExchange.Net.SharedApis
/// <summary> /// <summary>
/// Order quantity /// Order quantity
/// </summary> /// </summary>
[JsonConverter(typeof(SharedOrderQuantityConverter))]
public record SharedOrderQuantity : SharedQuantityReference public record SharedOrderQuantity : SharedQuantityReference
{ {
/// <summary> /// <summary>

View File

@ -1,15 +1,12 @@
using CryptoExchange.Net.Converters.SystemTextJson; using CryptoExchange.Net.Objects;
using CryptoExchange.Net.Objects;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace CryptoExchange.Net.SharedApis namespace CryptoExchange.Net.SharedApis
{ {
/// <summary> /// <summary>
/// A symbol representation based on a base and quote asset /// A symbol representation based on a base and quote asset
/// </summary> /// </summary>
[JsonConverter(typeof(SharedSymbolConverter))]
public record SharedSymbol public record SharedSymbol
{ {
/// <summary> /// <summary>

View File

@ -166,9 +166,9 @@ namespace CryptoExchange.Net.Sockets
} }
/// <inheritdoc /> /// <inheritdoc />
public virtual async Task<CallResult> ConnectAsync(CancellationToken ct) public virtual async Task<CallResult> ConnectAsync()
{ {
var connectResult = await ConnectInternalAsync(ct).ConfigureAwait(false); var connectResult = await ConnectInternalAsync().ConfigureAwait(false);
if (!connectResult) if (!connectResult)
return connectResult; return connectResult;
@ -215,7 +215,7 @@ namespace CryptoExchange.Net.Sockets
return socket; return socket;
} }
private async Task<CallResult> ConnectInternalAsync(CancellationToken ct) private async Task<CallResult> ConnectInternalAsync()
{ {
_logger.SocketConnecting(Id); _logger.SocketConnecting(Id);
try try
@ -229,16 +229,12 @@ namespace CryptoExchange.Net.Sockets
} }
using CancellationTokenSource tcs = new(TimeSpan.FromSeconds(10)); using CancellationTokenSource tcs = new(TimeSpan.FromSeconds(10));
using var linked = CancellationTokenSource.CreateLinkedTokenSource(tcs.Token, _ctsSource.Token, ct); using var linked = CancellationTokenSource.CreateLinkedTokenSource(tcs.Token, _ctsSource.Token);
await _socket.ConnectAsync(Uri, linked.Token).ConfigureAwait(false); await _socket.ConnectAsync(Uri, linked.Token).ConfigureAwait(false);
} }
catch (Exception e) catch (Exception e)
{ {
if (ct.IsCancellationRequested) if (!_ctsSource.IsCancellationRequested)
{
_logger.SocketConnectingCanceled(Id);
}
else if (!_ctsSource.IsCancellationRequested)
{ {
// if _ctsSource was canceled this was already logged // if _ctsSource was canceled this was already logged
_logger.SocketConnectionFailed(Id, e.Message, e); _logger.SocketConnectionFailed(Id, e.Message, e);
@ -329,7 +325,7 @@ namespace CryptoExchange.Net.Sockets
while (_sendBuffer.TryDequeue(out _)) { } // Clear send buffer while (_sendBuffer.TryDequeue(out _)) { } // Clear send buffer
_reconnectAttempt++; _reconnectAttempt++;
var connected = await ConnectInternalAsync(default).ConfigureAwait(false); var connected = await ConnectInternalAsync().ConfigureAwait(false);
if (!connected) if (!connected)
{ {
// Delay between reconnect attempts // Delay between reconnect attempts

View File

@ -79,11 +79,6 @@ namespace CryptoExchange.Net.Sockets
/// </summary> /// </summary>
public int Weight { get; } public int Weight { get; }
/// <summary>
/// Whether the query should wait for a response or not
/// </summary>
public bool ExpectsResponse { get; set; } = true;
/// <summary> /// <summary>
/// Get the type the message should be deserialized to /// Get the type the message should be deserialized to
/// </summary> /// </summary>
@ -120,21 +115,12 @@ namespace CryptoExchange.Net.Sockets
/// Signal that the request has been send and the timeout timer should start /// Signal that the request has been send and the timeout timer should start
/// </summary> /// </summary>
public void IsSend(TimeSpan timeout) public void IsSend(TimeSpan timeout)
{
RequestTimestamp = DateTime.UtcNow;
if (ExpectsResponse)
{ {
// Start timeout countdown // Start timeout countdown
RequestTimestamp = DateTime.UtcNow;
_cts = new CancellationTokenSource(timeout); _cts = new CancellationTokenSource(timeout);
_cts.Token.Register(Timeout, false); _cts.Token.Register(Timeout, false);
} }
else
{
Completed = true;
Result = CallResult.SuccessResult;
_event.Set();
}
}
/// <summary> /// <summary>
/// Wait until timeout or the request is completed /// Wait until timeout or the request is completed

View File

@ -571,7 +571,7 @@ namespace CryptoExchange.Net.Sockets
/// Connect the websocket /// Connect the websocket
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public async Task<CallResult> ConnectAsync(CancellationToken ct) => await _socket.ConnectAsync(ct).ConfigureAwait(false); public async Task<CallResult> ConnectAsync() => await _socket.ConnectAsync().ConfigureAwait(false);
/// <summary> /// <summary>
/// Retrieve the underlying socket /// Retrieve the underlying socket

View File

@ -10,11 +10,6 @@ using System.Text.Json.Serialization;
using CryptoExchange.Net.Converters; using CryptoExchange.Net.Converters;
using CryptoExchange.Net.Converters.SystemTextJson; using CryptoExchange.Net.Converters.SystemTextJson;
#pragma warning disable IL2026
#pragma warning disable IL2070
#pragma warning disable IL2075
#pragma warning disable IL3050
namespace CryptoExchange.Net.Testing.Comparers namespace CryptoExchange.Net.Testing.Comparers
{ {
internal class SystemTextJsonComparer internal class SystemTextJsonComparer

View File

@ -2,14 +2,10 @@
using System.Net.WebSockets; using System.Net.WebSockets;
using System.Text; using System.Text;
using System.Text.Json; using System.Text.Json;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using CryptoExchange.Net.Interfaces; using CryptoExchange.Net.Interfaces;
using CryptoExchange.Net.Objects; using CryptoExchange.Net.Objects;
#pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code
#pragma warning disable IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.
namespace CryptoExchange.Net.Testing.Implementations namespace CryptoExchange.Net.Testing.Implementations
{ {
internal class TestSocket : IWebsocket internal class TestSocket : IWebsocket
@ -51,7 +47,7 @@ namespace CryptoExchange.Net.Testing.Implementations
} }
} }
public Task<CallResult> ConnectAsync(CancellationToken ct) public Task<CallResult> ConnectAsync()
{ {
Connected = CanConnect; Connected = CanConnect;
return Task.FromResult(CanConnect ? new CallResult(null) : new CallResult(new CantConnectError())); return Task.FromResult(CanConnect ? new CallResult(null) : new CallResult(new CantConnectError()));

View File

@ -94,14 +94,7 @@ namespace CryptoExchange.Net.Testing
TUpdate? update = default; TUpdate? update = default;
// Invoke subscription method // Invoke subscription method
try
{
var task = methodInvoke(_client, x => { update = x.Data; }); var task = methodInvoke(_client, x => { update = x.Data; });
}
catch(Exception)
{
throw;
}
var replaceValues = new Dictionary<string, string>(); var replaceValues = new Dictionary<string, string>();
while (true) while (true)

View File

@ -15,11 +15,6 @@ using CryptoExchange.Net.Objects;
using CryptoExchange.Net.Objects.Sockets; using CryptoExchange.Net.Objects.Sockets;
using CryptoExchange.Net.Testing.Implementations; using CryptoExchange.Net.Testing.Implementations;
#pragma warning disable IL2026
#pragma warning disable IL2070
#pragma warning disable IL2075
#pragma warning disable IL3050
namespace CryptoExchange.Net.Testing namespace CryptoExchange.Net.Testing
{ {
/// <summary> /// <summary>

View File

@ -5,27 +5,26 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Binance.Net" Version="11.0.0" /> <PackageReference Include="Binance.Net" Version="10.18.0" />
<PackageReference Include="Bitfinex.Net" Version="9.0.0" /> <PackageReference Include="Bitfinex.Net" Version="8.1.1" />
<PackageReference Include="BitMart.Net" Version="2.0.0" /> <PackageReference Include="BitMart.Net" Version="1.14.0" />
<PackageReference Include="Bybit.Net" Version="5.0.0" /> <PackageReference Include="Bybit.Net" Version="4.3.2" />
<PackageReference Include="CoinEx.Net" Version="9.0.1" /> <PackageReference Include="CoinEx.Net" Version="8.0.1" />
<PackageReference Include="CryptoCom.Net" Version="2.0.0" /> <PackageReference Include="CryptoCom.Net" Version="1.6.0" />
<PackageReference Include="DeepCoin.Net" Version="2.0.0" /> <PackageReference Include="DeepCoin.Net" Version="1.0.0" />
<PackageReference Include="GateIo.Net" Version="2.0.0" /> <PackageReference Include="GateIo.Net" Version="1.20.1" />
<PackageReference Include="HyperLiquid.Net" Version="2.0.0" /> <PackageReference Include="HyperLiquid.Net" Version="1.1.0" />
<PackageReference Include="JK.BingX.Net" Version="2.0.0" /> <PackageReference Include="JK.BingX.Net" Version="1.21.0" />
<PackageReference Include="JK.Bitget.Net" Version="2.0.0" /> <PackageReference Include="JK.Bitget.Net" Version="1.21.0" />
<PackageReference Include="JK.Mexc.Net" Version="3.0.0" /> <PackageReference Include="JK.Mexc.Net" Version="2.1.0" />
<PackageReference Include="JK.OKX.Net" Version="3.0.0" /> <PackageReference Include="JK.OKX.Net" Version="2.15.0" />
<PackageReference Include="JKorf.BitMEX.Net" Version="2.0.0" /> <PackageReference Include="JKorf.BitMEX.Net" Version="1.1.0" />
<PackageReference Include="JKorf.Coinbase.Net" Version="2.0.0" /> <PackageReference Include="JKorf.Coinbase.Net" Version="1.8.1" />
<PackageReference Include="JKorf.HTX.Net" Version="7.0.0" /> <PackageReference Include="JKorf.HTX.Net" Version="6.9.0" />
<PackageReference Include="KrakenExchange.Net" Version="6.0.0" /> <PackageReference Include="KrakenExchange.Net" Version="5.7.1" />
<PackageReference Include="Kucoin.Net" Version="7.0.0" /> <PackageReference Include="Kucoin.Net" Version="6.0.0" />
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" /> <PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
<PackageReference Include="WhiteBit.Net" Version="2.0.0" /> <PackageReference Include="WhiteBit.Net" Version="1.4.0" />
<PackageReference Include="XT.Net" Version="2.0.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -18,7 +18,6 @@
@inject IMexcRestClient mexcClient @inject IMexcRestClient mexcClient
@inject IOKXRestClient okxClient @inject IOKXRestClient okxClient
@inject IWhiteBitRestClient whitebitClient @inject IWhiteBitRestClient whitebitClient
@inject IXTRestClient xtClient
<h3>BTC-USD prices:</h3> <h3>BTC-USD prices:</h3>
@foreach(var price in _prices.OrderBy(p => p.Key)) @foreach(var price in _prices.OrderBy(p => p.Key))
@ -34,7 +33,7 @@
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");
var bitgetTask = bitgetClient.SpotApiV2.ExchangeData.GetTickersAsync("BTCUSDT"); var bitgetTask = bitgetClient.SpotApi.ExchangeData.GetTickerAsync("BTCUSDT_SPBL");
var bitmartTask = bitmartClient.SpotApi.ExchangeData.GetTickerAsync("BTC_USDT"); var bitmartTask = bitmartClient.SpotApi.ExchangeData.GetTickerAsync("BTC_USDT");
var bitmexTask = bitmexClient.ExchangeApi.ExchangeData.GetSymbolsAsync("XBT_USDT"); var bitmexTask = bitmexClient.ExchangeApi.ExchangeData.GetSymbolsAsync("XBT_USDT");
var bybitTask = bybitClient.V5Api.ExchangeData.GetSpotTickersAsync("BTCUSDT"); var bybitTask = bybitClient.V5Api.ExchangeData.GetSpotTickersAsync("BTCUSDT");
@ -50,7 +49,6 @@
var mexcTask = mexcClient.SpotApi.ExchangeData.GetTickerAsync("BTCUSDT"); var mexcTask = mexcClient.SpotApi.ExchangeData.GetTickerAsync("BTCUSDT");
var okxTask = okxClient.UnifiedApi.ExchangeData.GetTickerAsync("BTCUSDT"); var okxTask = okxClient.UnifiedApi.ExchangeData.GetTickerAsync("BTCUSDT");
var whitebitTask = whitebitClient.V4Api.ExchangeData.GetTickersAsync(); var whitebitTask = whitebitClient.V4Api.ExchangeData.GetTickersAsync();
var xtTask = xtClient.SpotApi.ExchangeData.GetTickersAsync("eth_btc");
await Task.WhenAll(binanceTask, bingXTask, bitfinexTask, bitgetTask, bitmartTask, bybitTask, coinexTask, deepCoinTask, gateioTask, htxTask, krakenTask, kucoinTask, mexcTask, okxTask); await Task.WhenAll(binanceTask, bingXTask, bitfinexTask, bitgetTask, bitmartTask, bybitTask, coinexTask, deepCoinTask, gateioTask, htxTask, krakenTask, kucoinTask, mexcTask, okxTask);
@ -64,10 +62,10 @@
_prices.Add("Bitfinex", bitfinexTask.Result.Data.LastPrice); _prices.Add("Bitfinex", bitfinexTask.Result.Data.LastPrice);
if (bitgetTask.Result.Success) if (bitgetTask.Result.Success)
_prices.Add("Bitget", bitgetTask.Result.Data.Single().LastPrice); _prices.Add("Bitget", bitgetTask.Result.Data.ClosePrice);
if (bitmartTask.Result.Success) if (bitmartTask.Result.Success)
_prices.Add("BitMart", bitmartTask.Result.Data.LastPrice); _prices.Add("BitMart", bitgetTask.Result.Data.ClosePrice);
if (bitmexTask.Result.Success) if (bitmexTask.Result.Success)
_prices.Add("BitMEX", bitmexTask.Result.Data.First().LastPrice); _prices.Add("BitMEX", bitmexTask.Result.Data.First().LastPrice);
@ -121,9 +119,6 @@
var tickers = whitebitTask.Result.Data; var tickers = whitebitTask.Result.Data;
_prices.Add("WhiteBit", tickers.Single(x => x.Symbol == "BTC_USDT").LastPrice); _prices.Add("WhiteBit", tickers.Single(x => x.Symbol == "BTC_USDT").LastPrice);
} }
if (xtTask.Result.Success)
_prices.Add("XT", xtTask.Result.Data.Single().LastPrice ?? 0);
} }
} }

View File

@ -18,12 +18,10 @@
@inject IMexcSocketClient mexcSocketClient @inject IMexcSocketClient mexcSocketClient
@inject IOKXSocketClient okxSocketClient @inject IOKXSocketClient okxSocketClient
@inject IWhiteBitSocketClient whitebitSocketClient @inject IWhiteBitSocketClient whitebitSocketClient
@inject IXTSocketClient xtSocketClient
@using System.Collections.Concurrent @using System.Collections.Concurrent
@using CryptoExchange.Net.Objects @using CryptoExchange.Net.Objects
@using CryptoExchange.Net.Objects.Sockets; @using CryptoExchange.Net.Objects.Sockets;
@using CryptoExchange.Net.Sockets @using CryptoExchange.Net.Sockets
@using XT.Net.Interfaces.Clients
@implements IDisposable @implements IDisposable
<h3>ETH-BTC prices, live updates:</h3> <h3>ETH-BTC prices, live updates:</h3>
@ -43,7 +41,7 @@
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)),
bitgetSocketClient.SpotApiV2.SubscribeToTickerUpdatesAsync("ETHBTC", data => UpdateData("Bitget", data.Data.LastPrice)), bitgetSocketClient.SpotApi.SubscribeToTickerUpdatesAsync("ETHBTC", data => UpdateData("Bitget", data.Data.LastPrice)),
bitmartSocketClient.SpotApi.SubscribeToTickerUpdatesAsync("ETH_BTC", data => UpdateData("BitMart", data.Data.LastPrice)), bitmartSocketClient.SpotApi.SubscribeToTickerUpdatesAsync("ETH_BTC", data => UpdateData("BitMart", data.Data.LastPrice)),
bitmexSocketClient.ExchangeApi.SubscribeToSymbolUpdatesAsync("ETH_XBT", data => UpdateData("BitMEX", data.Data.LastPrice ?? 0)), bitmexSocketClient.ExchangeApi.SubscribeToSymbolUpdatesAsync("ETH_XBT", data => UpdateData("BitMEX", data.Data.LastPrice ?? 0)),
bybitSocketClient.V5SpotApi.SubscribeToTickerUpdatesAsync("ETHBTC", data => UpdateData("Bybit", data.Data.LastPrice)), bybitSocketClient.V5SpotApi.SubscribeToTickerUpdatesAsync("ETHBTC", data => UpdateData("Bybit", data.Data.LastPrice)),
@ -53,7 +51,6 @@
deepCoinSocketClient.ExchangeApi.SubscribeToSymbolUpdatesAsync("ETH-BTC", data => UpdateData("DeepCoin", data.Data.LastPrice ?? 0)), deepCoinSocketClient.ExchangeApi.SubscribeToSymbolUpdatesAsync("ETH-BTC", data => UpdateData("DeepCoin", data.Data.LastPrice ?? 0)),
gateioSocketClient.SpotApi.SubscribeToTickerUpdatesAsync("ETH_BTC", data => UpdateData("GateIo", data.Data.LastPrice)), gateioSocketClient.SpotApi.SubscribeToTickerUpdatesAsync("ETH_BTC", data => UpdateData("GateIo", data.Data.LastPrice)),
htxSocketClient.SpotApi.SubscribeToTickerUpdatesAsync("ethbtc", data => UpdateData("HTX", data.Data.ClosePrice ?? 0)), htxSocketClient.SpotApi.SubscribeToTickerUpdatesAsync("ethbtc", data => UpdateData("HTX", data.Data.ClosePrice ?? 0)),
xtSocketClient.SpotApi.SubscribeToTickerUpdatesAsync("eth_btc", data => UpdateData("XT", data.Data.LastPrice ?? 0)),
// HyperLiquid doesn't support the ETH/BTC pair // HyperLiquid doesn't support the ETH/BTC pair
//hyperLiquidSocketClient.SpotApi.SubscribeToSymbolUpdatesAsync("ETH", data => UpdateData("HyperLiquid", data.Data.MidPrice ?? 0)), //hyperLiquidSocketClient.SpotApi.SubscribeToSymbolUpdatesAsync("ETH", data => UpdateData("HyperLiquid", data.Data.MidPrice ?? 0)),
krakenSocketClient.SpotApi.SubscribeToTickerUpdatesAsync("ETH/BTC", data => UpdateData("Kraken", data.Data.LastPrice)), krakenSocketClient.SpotApi.SubscribeToTickerUpdatesAsync("ETH/BTC", data => UpdateData("Kraken", data.Data.LastPrice)),

View File

@ -10,7 +10,6 @@
@using Bybit.Net.Interfaces @using Bybit.Net.Interfaces
@using CoinEx.Net.Interfaces @using CoinEx.Net.Interfaces
@using Coinbase.Net.Interfaces @using Coinbase.Net.Interfaces
@using CryptoExchange.Net.Authentication
@using CryptoExchange.Net.Interfaces @using CryptoExchange.Net.Interfaces
@using CryptoCom.Net.Interfaces @using CryptoCom.Net.Interfaces
@using DeepCoin.Net.Interfaces @using DeepCoin.Net.Interfaces
@ -23,7 +22,6 @@
@using Mexc.Net.Interfaces @using Mexc.Net.Interfaces
@using OKX.Net.Interfaces; @using OKX.Net.Interfaces;
@using WhiteBit.Net.Interfaces @using WhiteBit.Net.Interfaces
@using XT.Net.Interfaces
@inject IBinanceOrderBookFactory binanceFactory @inject IBinanceOrderBookFactory binanceFactory
@inject IBingXOrderBookFactory bingXFactory @inject IBingXOrderBookFactory bingXFactory
@inject IBitfinexOrderBookFactory bitfinexFactory @inject IBitfinexOrderBookFactory bitfinexFactory
@ -43,7 +41,6 @@
@inject IMexcOrderBookFactory mexcFactory @inject IMexcOrderBookFactory mexcFactory
@inject IOKXOrderBookFactory okxFactory @inject IOKXOrderBookFactory okxFactory
@inject IWhiteBitOrderBookFactory whitebitFactory @inject IWhiteBitOrderBookFactory whitebitFactory
@inject IXTOrderBookFactory xtFactory
@implements IDisposable @implements IDisposable
<h3>ETH-BTC books, live updates:</h3> <h3>ETH-BTC books, live updates:</h3>
@ -72,7 +69,7 @@
// Since the Kucoin order book stream needs authentication we will need to provide API credentials beforehand // Since the Kucoin order book stream needs authentication we will need to provide API credentials beforehand
KucoinRestClient.SetDefaultOptions(options => KucoinRestClient.SetDefaultOptions(options =>
{ {
options.ApiCredentials = new ApiCredentials("KEY", "SECRET", "PASSPHRASE"); options.ApiCredentials = new Kucoin.Net.Objects.KucoinApiCredentials("KEY", "SECRET", "PASSPHRASE");
}); });
_books = new Dictionary<string, ISymbolOrderBook> _books = new Dictionary<string, ISymbolOrderBook>
@ -88,8 +85,7 @@
{ "CoinEx", coinExFactory.CreateSpot("ETHBTC") }, { "CoinEx", coinExFactory.CreateSpot("ETHBTC") },
{ "CryptoCom", cryptocomFactory.Create("ETH_BTC") }, { "CryptoCom", cryptocomFactory.Create("ETH_BTC") },
{ "GateIo", gateioFactory.CreateSpot("ETH_BTC") }, { "GateIo", gateioFactory.CreateSpot("ETH_BTC") },
// DeepCoin does not support the ETH/BTC pair { "DeepCoin", deepCoinFactory.Create("ETH-BTC") },
//{ "DeepCoin", deepCoinFactory.Create("ETH-BTC") },
{ "HTX", htxFactory.CreateSpot("ethbtc") }, { "HTX", htxFactory.CreateSpot("ethbtc") },
// HyperLiquid does not support the ETH/BTC pair // HyperLiquid does not support the ETH/BTC pair
//{ "HyperLiquid", hyperLiquidFactory.Create("ETH/BTC") }, //{ "HyperLiquid", hyperLiquidFactory.Create("ETH/BTC") },
@ -98,10 +94,9 @@
{ "Mexc", mexcFactory.CreateSpot("ETHBTC") }, { "Mexc", mexcFactory.CreateSpot("ETHBTC") },
{ "OKX", okxFactory.Create("ETH-BTC") }, { "OKX", okxFactory.Create("ETH-BTC") },
{ "WhiteBit", whitebitFactory.CreateV4("ETH_BTC") }, { "WhiteBit", whitebitFactory.CreateV4("ETH_BTC") },
{ "XT", xtFactory.CreateSpot("eth_btc") },
}; };
var result = await Task.WhenAll(_books.Select(b => b.Value.StartAsync())); await Task.WhenAll(_books.Select(b => b.Value.StartAsync()));
// Use a manual update timer so the page isn't refreshed too often // Use a manual update timer so the page isn't refreshed too often
_timer = new Timer(500); _timer = new Timer(500);

View File

@ -24,7 +24,6 @@
@using Mexc.Net.Interfaces @using Mexc.Net.Interfaces
@using OKX.Net.Interfaces; @using OKX.Net.Interfaces;
@using WhiteBit.Net.Interfaces @using WhiteBit.Net.Interfaces
@using XT.Net.Interfaces
@inject IBinanceTrackerFactory binanceFactory @inject IBinanceTrackerFactory binanceFactory
@inject IBingXTrackerFactory bingXFactory @inject IBingXTrackerFactory bingXFactory
@inject IBitfinexTrackerFactory bitfinexFactory @inject IBitfinexTrackerFactory bitfinexFactory
@ -44,7 +43,6 @@
@inject IMexcTrackerFactory mexcFactory @inject IMexcTrackerFactory mexcFactory
@inject IOKXTrackerFactory okxFactory @inject IOKXTrackerFactory okxFactory
@inject IWhiteBitTrackerFactory whitebitFactory @inject IWhiteBitTrackerFactory whitebitFactory
@inject IXTTrackerFactory xtFactory
@implements IDisposable @implements IDisposable
<h3>ETH-BTC trade Trackers, live updates:</h3> <h3>ETH-BTC trade Trackers, live updates:</h3>
@ -91,7 +89,6 @@
{ mexcFactory.CreateTradeTracker(usdtSymbol, period: TimeSpan.FromMinutes(5)) }, { mexcFactory.CreateTradeTracker(usdtSymbol, period: TimeSpan.FromMinutes(5)) },
{ okxFactory.CreateTradeTracker(usdtSymbol, period: TimeSpan.FromMinutes(5)) }, { okxFactory.CreateTradeTracker(usdtSymbol, period: TimeSpan.FromMinutes(5)) },
{ whitebitFactory.CreateTradeTracker(usdtSymbol, period: TimeSpan.FromMinutes(5)) }, { whitebitFactory.CreateTradeTracker(usdtSymbol, period: TimeSpan.FromMinutes(5)) },
{ xtFactory.CreateTradeTracker(usdtSymbol, period: TimeSpan.FromMinutes(5)) },
}; };
await Task.WhenAll(_trackers.Select(b => b.StartAsync())); await Task.WhenAll(_trackers.Select(b => b.StartAsync()));

View File

@ -31,6 +31,9 @@ namespace BlazorClient
services.AddBinance(restOptions => services.AddBinance(restOptions =>
{ {
restOptions.ApiCredentials = new ApiCredentials("KEY", "SECRET"); restOptions.ApiCredentials = new ApiCredentials("KEY", "SECRET");
}, socketOptions =>
{
socketOptions.ApiCredentials = new ApiCredentials("KEY", "SECRET");
}); });
services.AddBingX(); services.AddBingX();
@ -51,7 +54,6 @@ namespace BlazorClient
services.AddMexc(); services.AddMexc();
services.AddOKX(); services.AddOKX();
services.AddWhiteBit(); services.AddWhiteBit();
services.AddXT();
} }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.

View File

@ -27,5 +27,4 @@
@using Mexc.Net.Interfaces.Clients; @using Mexc.Net.Interfaces.Clients;
@using OKX.Net.Interfaces.Clients; @using OKX.Net.Interfaces.Clients;
@using WhiteBit.Net.Interfaces.Clients @using WhiteBit.Net.Interfaces.Clients
@using XT.Net.Interfaces.Clients
@using CryptoExchange.Net.Interfaces; @using CryptoExchange.Net.Interfaces;

View File

@ -6,20 +6,20 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Binance.Net" Version="11.0.0" /> <PackageReference Include="Binance.Net" Version="10.9.0" />
<PackageReference Include="Bitfinex.Net" Version="9.0.0" /> <PackageReference Include="Bitfinex.Net" Version="7.10.0" />
<PackageReference Include="BitMart.Net" Version="2.0.0" /> <PackageReference Include="BitMart.Net" Version="1.7.0" />
<PackageReference Include="Bybit.Net" Version="5.0.0" /> <PackageReference Include="Bybit.Net" Version="3.16.0" />
<PackageReference Include="CoinEx.Net" Version="9.0.0" /> <PackageReference Include="CoinEx.Net" Version="7.9.0" />
<PackageReference Include="CryptoCom.Net" Version="2.0.0" /> <PackageReference Include="CryptoCom.Net" Version="1.2.0" />
<PackageReference Include="GateIo.Net" Version="2.0.0" /> <PackageReference Include="GateIo.Net" Version="1.12.0" />
<PackageReference Include="JK.Bitget.Net" Version="2.0.0" /> <PackageReference Include="JK.Bitget.Net" Version="1.13.0" />
<PackageReference Include="JK.Mexc.Net" Version="3.0.0" /> <PackageReference Include="JK.Mexc.Net" Version="1.11.0" />
<PackageReference Include="JK.OKX.Net" Version="3.0.0" /> <PackageReference Include="JK.OKX.Net" Version="2.8.0" />
<PackageReference Include="JKorf.Coinbase.Net" Version="2.0.0" /> <PackageReference Include="JKorf.Coinbase.Net" Version="1.4.0" />
<PackageReference Include="JKorf.HTX.Net" Version="7.0.0" /> <PackageReference Include="JKorf.HTX.Net" Version="6.4.0" />
<PackageReference Include="KrakenExchange.Net" Version="6.0.0" /> <PackageReference Include="KrakenExchange.Net" Version="5.2.0" />
<PackageReference Include="Kucoin.Net" Version="7.0.0" /> <PackageReference Include="Kucoin.Net" Version="5.18.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -8,9 +8,9 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Binance.Net" Version="11.0.0" /> <PackageReference Include="Binance.Net" Version="10.9.0" />
<PackageReference Include="BitMart.Net" Version="2.0.0" /> <PackageReference Include="BitMart.Net" Version="1.7.0" />
<PackageReference Include="JK.OKX.Net" Version="3.0.0" /> <PackageReference Include="JK.OKX.Net" Version="2.8.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -5,34 +5,34 @@
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. 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.
Note that the CryptoExchange.Net package itself can not be used directly for accessing API's. Either install a client library from the list below or use [CryptoClients.Net](https://github.com/jkorf/CryptoClients.Net) which includes access to all exchange API's. Note that the CryptoExchange.Net package itself can not be used directly for accessing API's. Either install a client library from the list below or use [CryptoClients.Net](https://github.com/jkorf/CryptoClients.Net) which includes access to all exchange API's.
For more information on what CryptoExchange.Net and it's client libraries offers see the [Documentation](https://cryptoexchange.jkorf.dev/). For more information on what CryptoExchange.Net and it's client libraries offers see the [Documentation](https://jkorf.github.io/CryptoExchange.Net/).
### CryptoExchange.Net Ecosystem ### Current implementations
Full list of all libraries part of the CryptoExchange.Net ecosystem. Consider using a referral link to support development, as well as potentially get some trading fee discount! The following API's are directly supported. Note that there are 3rd party implementations going around, but only these are created and supported by me:
||Exchange|Type|Repository|Nuget|Referral Link|Referral Fee Discount| |Exchange|Repository|Nuget|
|--|--|--|--|--|--|--| |--|--|--|
|![Binance](https://raw.githubusercontent.com/JKorf/Binance.Net/refs/heads/master/Binance.Net/Icon/icon.png)|Binance|CEX|[JKorf/Binance.Net](https://github.com/JKorf/Binance.Net)|[![Nuget version](https://img.shields.io/nuget/v/Binance.net.svg?style=flat-square)](https://www.nuget.org/packages/Binance.Net)|[Link](https://accounts.binance.com/register?ref=X5K3F2ZG)|20%| |Binance|[JKorf/Binance.Net](https://github.com/JKorf/Binance.Net)|[![Nuget version](https://img.shields.io/nuget/v/Binance.net.svg?style=flat-square)](https://www.nuget.org/packages/Binance.Net)|
|![BingX](https://raw.githubusercontent.com/JKorf/BingX.Net/refs/heads/main/BingX.Net/Icon/BingX.png)|BingX|CEX|[JKorf/BingX.Net](https://github.com/JKorf/BingX.Net)|[![Nuget version](https://img.shields.io/nuget/v/JK.BingX.net.svg?style=flat-square)](https://www.nuget.org/packages/JK.BingX.Net)|[Link](https://bingx.com/invite/FFHRJKWG/)|20%| |BingX|[JKorf/BingX.Net](https://github.com/JKorf/BingX.Net)|[![Nuget version](https://img.shields.io/nuget/v/JK.BingX.net.svg?style=flat-square)](https://www.nuget.org/packages/JK.BingX.Net)|
|![Bitfinex](https://raw.githubusercontent.com/JKorf/Bitfinex.Net/refs/heads/master/Bitfinex.Net/Icon/icon.png)|Bitfinex|CEX|[JKorf/Bitfinex.Net](https://github.com/JKorf/Bitfinex.Net)|[![Nuget version](https://img.shields.io/nuget/v/Bitfinex.net.svg?style=flat-square)](https://www.nuget.org/packages/Bitfinex.Net)|-|-| |Bitfinex|[JKorf/Bitfinex.Net](https://github.com/JKorf/Bitfinex.Net)|[![Nuget version](https://img.shields.io/nuget/v/Bitfinex.net.svg?style=flat-square)](https://www.nuget.org/packages/Bitfinex.Net)|
|![Bitget](https://raw.githubusercontent.com/JKorf/Bitget.Net/refs/heads/main/Bitget.Net/Icon/icon.png)|Bitget|CEX|[JKorf/Bitget.Net](https://github.com/JKorf/Bitget.Net)|[![Nuget version](https://img.shields.io/nuget/v/JK.Bitget.net.svg?style=flat-square)](https://www.nuget.org/packages/JK.Bitget.Net)|[Link](https://partner.bitget.com/bg/1qlf6pj1)|20%| |Bitget|[JKorf/Bitget.Net](https://github.com/JKorf/Bitget.Net)|[![Nuget version](https://img.shields.io/nuget/v/JK.Bitget.net.svg?style=flat-square)](https://www.nuget.org/packages/JK.Bitget.Net)|
|![BitMart](https://raw.githubusercontent.com/JKorf/BitMart.Net/refs/heads/main/BitMart.Net/Icon/icon.png)|BitMart|CEX|[JKorf/BitMart.Net](https://github.com/JKorf/BitMart.Net)|[![Nuget version](https://img.shields.io/nuget/v/BitMart.net.svg?style=flat-square)](https://www.nuget.org/packages/BitMart.Net)|[Link](https://www.bitmart.com/invite/JKorfAPI/en-US)|30%| |BitMart|[JKorf/BitMart.Net](https://github.com/JKorf/BitMart.Net)|[![Nuget version](https://img.shields.io/nuget/v/BitMart.net.svg?style=flat-square)](https://www.nuget.org/packages/BitMart.Net)|
|![BitMEX](https://raw.githubusercontent.com/JKorf/BitMEX.Net/refs/heads/main/BitMEX.Net/Icon/icon.png)|BitMEX|CEX|[JKorf/BitMEX.Net](https://github.com/JKorf/BitMEX.Net)|[![Nuget version](https://img.shields.io/nuget/v/JKorf.BitMEX.net.svg?style=flat-square)](https://www.nuget.org/packages/JKorf.BitMEX.Net)|[Link](https://www.bitmex.com/app/register/94f98e)|30%| |BitMEX|[JKorf/BitMEX.Net](https://github.com/JKorf/BitMEX.Net)|[![Nuget version](https://img.shields.io/nuget/v/JKorf.BitMEX.net.svg?style=flat-square)](https://www.nuget.org/packages/JKorf.BitMEX.Net)|
|![Bybit](https://raw.githubusercontent.com/JKorf/Bybit.Net/refs/heads/main/ByBit.Net/Icon/icon.png)|Bybit|CEX|[JKorf/Bybit.Net](https://github.com/JKorf/Bybit.Net)|[![Nuget version](https://img.shields.io/nuget/v/Bybit.net.svg?style=flat-square)](https://www.nuget.org/packages/Bybit.Net)|[Link](https://partner.bybit.com/b/jkorf)|-| |Bybit|[JKorf/Bybit.Net](https://github.com/JKorf/Bybit.Net)|[![Nuget version](https://img.shields.io/nuget/v/Bybit.net.svg?style=flat-square)](https://www.nuget.org/packages/Bybit.Net)|
|![Coinbase](https://raw.githubusercontent.com/JKorf/Coinbase.Net/refs/heads/main/Coinbase.Net/Icon/icon.png)|Coinbase|CEX|[JKorf/Coinbase.Net](https://github.com/JKorf/Coinbase.Net)|[![Nuget version](https://img.shields.io/nuget/v/JKorf.Coinbase.Net.svg?style=flat-square)](https://www.nuget.org/packages/JKorf.Coinbase.Net)|[Link](https://advanced.coinbase.com/join/T6H54H8)|-| |Coinbase|[JKorf/Coinbase.Net](https://github.com/JKorf/Coinbase.Net)|[![Nuget version](https://img.shields.io/nuget/v/JKorf.Coinbase.Net.svg?style=flat-square)](https://www.nuget.org/packages/JKorf.Coinbase.Net)|
|![CoinEx](https://raw.githubusercontent.com/JKorf/CoinEx.Net/refs/heads/master/CoinEx.Net/Icon/icon.png)|CoinEx|CEX|[JKorf/CoinEx.Net](https://github.com/JKorf/CoinEx.Net)|[![Nuget version](https://img.shields.io/nuget/v/CoinEx.net.svg?style=flat-square)](https://www.nuget.org/packages/CoinEx.Net)|[Link](https://www.coinex.com/register?rc=rbtnp)|20%| |CoinEx|[JKorf/CoinEx.Net](https://github.com/JKorf/CoinEx.Net)|[![Nuget version](https://img.shields.io/nuget/v/CoinEx.net.svg?style=flat-square)](https://www.nuget.org/packages/CoinEx.Net)|
|![CoinGecko](https://raw.githubusercontent.com/JKorf/CoinGecko.Net/refs/heads/main/CoinGecko.Net/Icon/icon.png)|CoinGecko|-|[JKorf/CoinGecko.Net](https://github.com/JKorf/CoinGecko.Net)|[![Nuget version](https://img.shields.io/nuget/v/CoinGecko.net.svg?style=flat-square)](https://www.nuget.org/packages/CoinGecko.Net)|-|-| |CoinGecko|[JKorf/CoinGecko.Net](https://github.com/JKorf/CoinGecko.Net)|[![Nuget version](https://img.shields.io/nuget/v/CoinGecko.net.svg?style=flat-square)](https://www.nuget.org/packages/CoinGecko.Net)|
|![Crypto.com](https://raw.githubusercontent.com/JKorf/CryptoCom.Net/refs/heads/main/CryptoCom.Net/Icon/icon.png)|Crypto.com|CEX|[JKorf/CryptoCom.Net](https://github.com/JKorf/CryptoCom.Net)|[![Nuget version](https://img.shields.io/nuget/v/CryptoCom.net.svg?style=flat-square)](https://www.nuget.org/packages/CryptoCom.Net)|[Link](https://crypto.com/exch/26ge92xbkn)|-| |Crypto.com|[JKorf/CryptoCom.Net](https://github.com/JKorf/CryptoCom.Net)|[![Nuget version](https://img.shields.io/nuget/v/CryptoCom.net.svg?style=flat-square)](https://www.nuget.org/packages/CryptoCom.Net)|
|![DeepCoin](https://raw.githubusercontent.com/JKorf/DeepCoin.Net/refs/heads/main/DeepCoin.Net/Icon/icon.png)|DeepCoin|CEX|[JKorf/DeepCoin.Net](https://github.com/JKorf/DeepCoin.Net)|[![Nuget version](https://img.shields.io/nuget/v/DeepCoin.net.svg?style=flat-square)](https://www.nuget.org/packages/DeepCoin.Net)|[Link](https://s.deepcoin.com/jddhfca)|-| |DeepCoin|[JKorf/DeepCoin.Net](https://github.com/JKorf/DeepCoin.Net)|[![Nuget version](https://img.shields.io/nuget/v/DeepCoin.net.svg?style=flat-square)](https://www.nuget.org/packages/DeepCoin.Net)|
|![Gate.io](https://raw.githubusercontent.com/JKorf/GateIo.Net/refs/heads/main/GateIo.Net/Icon/icon.png)|Gate.io|CEX|[JKorf/GateIo.Net](https://github.com/JKorf/GateIo.Net)|[![Nuget version](https://img.shields.io/nuget/v/GateIo.net.svg?style=flat-square)](https://www.nuget.org/packages/GateIo.Net)|[Link](https://www.gate.io/share/JKorf)|20%| |Gate.io|[JKorf/GateIo.Net](https://github.com/JKorf/GateIo.Net)|[![Nuget version](https://img.shields.io/nuget/v/GateIo.net.svg?style=flat-square)](https://www.nuget.org/packages/GateIo.Net)|
|![HTX](https://raw.githubusercontent.com/JKorf/HTX.Net/refs/heads/master/HTX.Net/Icon/icon.png)|HTX|CEX|[JKorf/HTX.Net](https://github.com/JKorf/HTX.Net)|[![Nuget version](https://img.shields.io/nuget/v/JKorf.HTX.net.svg?style=flat-square)](https://www.nuget.org/packages/JKorf.HTX.Net)|[Link](https://www.htx.com/invite/en-us/1f?invite_code=ekek5223)|30%| |HTX|[JKorf/HTX.Net](https://github.com/JKorf/HTX.Net)|[![Nuget version](https://img.shields.io/nuget/v/JKorf.HTX.net.svg?style=flat-square)](https://www.nuget.org/packages/JKorf.HTX.Net)|
|![HyperLiquid](https://raw.githubusercontent.com/JKorf/HyperLiquid.Net/refs/heads/main/HyperLiquid.Net/Icon/icon.png)|HyperLiquid|DEX|[JKorf/HyperLiquid.Net](https://github.com/JKorf/HyperLiquid.Net)|[![Nuget version](https://img.shields.io/nuget/v/HyperLiquid.Net.svg?style=flat-square)](https://www.nuget.org/packages/HyperLiquid.Net)|[Link](https://app.hyperliquid.xyz/join/JKORF)|4%| |HyperLiquid|[JKorf/HyperLiquid.Net](https://github.com/JKorf/HyperLiquid.Net)|[![Nuget version](https://img.shields.io/nuget/v/HyperLiquid.Net.svg?style=flat-square)](https://www.nuget.org/packages/HyperLiquid.Net)|
|![Kraken](https://raw.githubusercontent.com/JKorf/Kraken.Net/refs/heads/master/Kraken.Net/Icon/icon.png)|Kraken|CEX|[JKorf/Kraken.Net](https://github.com/JKorf/Kraken.Net)|[![Nuget version](https://img.shields.io/nuget/v/KrakenExchange.net.svg?style=flat-square)](https://www.nuget.org/packages/KrakenExchange.Net)|-|-| |Kraken|[JKorf/Kraken.Net](https://github.com/JKorf/Kraken.Net)|[![Nuget version](https://img.shields.io/nuget/v/KrakenExchange.net.svg?style=flat-square)](https://www.nuget.org/packages/KrakenExchange.Net)|
|![Kucoin](https://raw.githubusercontent.com/JKorf/Kucoin.Net/refs/heads/master/Kucoin.Net/Icon/icon.png)|Kucoin|CEX|[JKorf/Kucoin.Net](https://github.com/JKorf/Kucoin.Net)|[![Nuget version](https://img.shields.io/nuget/v/Kucoin.net.svg?style=flat-square)](https://www.nuget.org/packages/Kucoin.Net)|[Link](https://www.kucoin.com/r/rf/QBS4FPED)|-| |Kucoin|[JKorf/Kucoin.Net](https://github.com/JKorf/Kucoin.Net)|[![Nuget version](https://img.shields.io/nuget/v/Kucoin.net.svg?style=flat-square)](https://www.nuget.org/packages/Kucoin.Net)|
|![Mexc](https://raw.githubusercontent.com/JKorf/Mexc.Net/refs/heads/main/Mexc.Net/Icon/icon.png)|Mexc|CEX|[JKorf/Mexc.Net](https://github.com/JKorf/Mexc.Net)|[![Nuget version](https://img.shields.io/nuget/v/JK.Mexc.net.svg?style=flat-square)](https://www.nuget.org/packages/JK.Mexc.Net)|-|-| |Mexc|[JKorf/Mexc.Net](https://github.com/JKorf/Mexc.Net)|[![Nuget version](https://img.shields.io/nuget/v/JK.Mexc.net.svg?style=flat-square)](https://www.nuget.org/packages/JK.Mexc.Net)|
|![OKX](https://raw.githubusercontent.com/JKorf/OKX.Net/refs/heads/main/OKX.Net/Icon/icon.png)|OKX|CEX|[JKorf/OKX.Net](https://github.com/JKorf/OKX.Net)|[![Nuget version](https://img.shields.io/nuget/v/JK.OKX.net.svg?style=flat-square)](https://www.nuget.org/packages/JK.OKX.Net)|[Link](https://www.okx.com/join/14592495)|20%| |OKX|[JKorf/OKX.Net](https://github.com/JKorf/OKX.Net)|[![Nuget version](https://img.shields.io/nuget/v/JK.OKX.net.svg?style=flat-square)](https://www.nuget.org/packages/JK.OKX.Net)|
|![WhiteBit](https://raw.githubusercontent.com/JKorf/WhiteBit.Net/refs/heads/main/WhiteBit.Net/Icon/icon.png)|WhiteBit|CEX|[JKorf/WhiteBit.Net](https://github.com/JKorf/WhiteBit.Net)|[![Nuget version](https://img.shields.io/nuget/v/WhiteBit.net.svg?style=flat-square)](https://www.nuget.org/packages/WhiteBit.Net)|[Link](https://whitebit.com/referral/a8e59b59-186c-4662-824c-3095248e0edf)|-| |WhiteBit|[JKorf/WhiteBit.Net](https://github.com/JKorf/WhiteBit.Net)|[![Nuget version](https://img.shields.io/nuget/v/WhiteBit.net.svg?style=flat-square)](https://www.nuget.org/packages/WhiteBit.Net)|
|![XT](https://raw.githubusercontent.com/JKorf/XT.Net/refs/heads/main/XT.Net/Icon/icon.png)|XT|CEX|[JKorf/XT.Net](https://github.com/JKorf/XT.Net)|[![Nuget version](https://img.shields.io/nuget/v/XT.net.svg?style=flat-square)](https://www.nuget.org/packages/XT.Net)|[Link](https://www.xt.com/ru/accounts/register?ref=CZG39C)|25%| |XT|[JKorf/XT.Net](https://github.com/JKorf/XT.Net)|[![Nuget version](https://img.shields.io/nuget/v/XT.net.svg?style=flat-square)](https://www.nuget.org/packages/XT.Net)|
Any of these can be installed independently or install [CryptoClients.Net](https://github.com/jkorf/CryptoClients.Net) which includes all exchange API's. Any of these can be installed independently or install [CryptoClients.Net](https://github.com/jkorf/CryptoClients.Net) which includes all exchange API's.
@ -43,8 +43,22 @@ A Discord server is available [here](https://discord.gg/MSpeEtSY8t). Feel free t
## Support the project ## Support the project
Any support is greatly appreciated. Any support is greatly appreciated.
### Referral ## Referral
When creating an account on new exchanges please consider using a referral link from above. When creating an account on new exchanges please consider using a referral link from below to support development
|Exchange|Link|
|--|--|
|Bybit|[https://partner.bybit.com/b/jkorf](https://partner.bybit.com/b/jkorf)|
|Coinbase|[https://advanced.coinbase.com/join/T6H54H8](https://advanced.coinbase.com/join/T6H54H8)|
|CoinEx|[https://www.coinex.com/register?refer_code=hd6gn](https://www.coinex.com/register?refer_code=hd6gn)|
|Crypto.com|[https://crypto.com/exch/26ge92xbkn](https://crypto.com/exch/26ge92xbkn)|
|DeepCoin|[https://s.deepcoin.com/jddhfca)|
|HTX|[https://www.htx.com/invite/en-us/1f?invite_code=fxp9](https://www.htx.com/invite/en-us/1f?invite_code=fxp9)|
|HyperLiquid|[https://app.hyperliquid.xyz/join/JKORF](https://app.hyperliquid.xyz/join/JKORF)|
|Kucoin|[https://www.kucoin.com/r/rf/QBS4FPED](https://www.kucoin.com/r/rf/QBS4FPED)|
|OKX|[https://okx.com/join/48046699](https://okx.com/join/48046699)|
|WhiteBit|[https://whitebit.com/referral/a8e59b59-186c-4662-824c-3095248e0edf](https://whitebit.com/referral/a8e59b59-186c-4662-824c-3095248e0edf)|
|XT|[https://www.xt.com/en/accounts/register?ref=1HRM5J](https://www.xt.com/en/accounts/register?ref=1HRM5J)|
### Donate ### Donate
Make a one time donation in a crypto currency of your choice. If you prefer to donate a currency not listed here please contact me. Make a one time donation in a crypto currency of your choice. If you prefer to donate a currency not listed here please contact me.
@ -57,17 +71,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.1.0 - 28 May 2025
* Added JsonConverter implementation for SharedQuantity and SharedSymbol types, making usage of the types easier
* Updated dotnet dependency packages from 9.0.0 to 9.0.5
* Replaced Microsoft.Extensions.Logging.Abstractions with Microsoft.Extensions.Logging
* Replaced Microsoft.Extensions.Options.ConfigurationExtensions with Microsoft.Extensions.Configuration.Binder, which includes a source generator for AOT publishing
* Removed redundant Microsoft.Extensions.DependencyInjection.Abstractions package reference
* Version 9.0.1 - 20 May 2025
* Improved response time on CancellationToken cancel during subscribing
* Added support for sending query without expecting a response
* Version 9.0.0 - 13 May 2025 * Version 9.0.0 - 13 May 2025
* Added support for Native AOT compilation * Added support for Native AOT compilation
* Updated all IEnumerable response types to array response types * Updated all IEnumerable response types to array response types