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

Compare commits

..

6 Commits

Author SHA1 Message Date
Jkorf
99a203933c Added missing release notes 2025-10-15 13:59:10 +02:00
Jkorf
b43d2a2040 Updated to version 9.10.0 2025-10-15 13:36:33 +02:00
Jkorf
ba9c406def Updated CryptoExchange.Net version 2025-10-15 13:34:50 +02:00
Jkorf
f5f4d50cc9 Updated to version 9.10.0 2025-10-15 13:24:25 +02:00
Jkorf
f87506b490 Added ITransferRestClient, updated Shared IBalanceRestClient to use SharedAccountType 2025-10-15 13:21:00 +02:00
Jkorf
f6f9a53ce5 Added ClientOrderId property to SharedUserTrade model 2025-10-13 15:42:27 +02:00
16 changed files with 360 additions and 16 deletions

View File

@ -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.10.0</PackageVersion>
<AssemblyVersion>9.9.0</AssemblyVersion> <AssemblyVersion>9.10.0</AssemblyVersion>
<FileVersion>9.9.0</FileVersion> <FileVersion>9.10.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.10.0" />
<PackageReference Include="protobuf-net" Version="3.2.56" /> <PackageReference Include="protobuf-net" Version="3.2.56" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -5,6 +5,9 @@
Protobuf support for CryptoExchange.Net. Protobuf support for CryptoExchange.Net.
## Release notes ## Release notes
* Version 9.10.0 - 15 Oct 2025
* Updated CryptoExchange.Net version to 9.10.0, see https://github.com/JKorf/CryptoExchange.Net/releases/
* Version 9.9.0 - 06 Oct 2025 * Version 9.9.0 - 06 Oct 2025
* Updated CryptoExchange.Net version to 9.9.0, see https://github.com/JKorf/CryptoExchange.Net/releases/ * Updated CryptoExchange.Net version to 9.9.0, see https://github.com/JKorf/CryptoExchange.Net/releases/

View File

@ -88,13 +88,13 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
} }
/// <summary> /// <summary>
/// Parse a long value to datetime /// Parse a double value to datetime
/// </summary> /// </summary>
public static DateTime ParseFromDouble(double value) public static DateTime ParseFromDouble(double value)
=> ParseFromDecimal((decimal)value); => ParseFromDecimal((decimal)value);
/// <summary> /// <summary>
/// Parse a long value to datetime /// Parse a decimal value to datetime
/// </summary> /// </summary>
public static DateTime ParseFromDecimal(decimal value) public static DateTime ParseFromDecimal(decimal value)
{ {

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.9.0</PackageVersion> <PackageVersion>9.10.0</PackageVersion>
<AssemblyVersion>9.9.0</AssemblyVersion> <AssemblyVersion>9.10.0</AssemblyVersion>
<FileVersion>9.9.0</FileVersion> <FileVersion>9.10.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>

View File

@ -399,7 +399,7 @@ namespace CryptoExchange.Net
/// <summary> /// <summary>
/// Whether the trading mode is linear /// Whether the trading mode is linear
/// </summary> /// </summary>
public static bool IsLinear(this TradingMode type) => type == TradingMode.PerpetualLinear || type == TradingMode.DeliveryLinear; public static bool IsLinear(this TradingMode type) => type == TradingMode.PerpetualLinear || type == TradingMode.DeliveryLinear;
/// <summary> /// <summary>
/// Whether the trading mode is inverse /// Whether the trading mode is inverse
@ -416,6 +416,36 @@ namespace CryptoExchange.Net
/// </summary> /// </summary>
public static bool IsDelivery(this TradingMode type) => type == TradingMode.DeliveryInverse || type == TradingMode.DeliveryLinear; public static bool IsDelivery(this TradingMode type) => type == TradingMode.DeliveryInverse || type == TradingMode.DeliveryLinear;
/// <summary>
/// Whether the account type is a futures account
/// </summary>
public static bool IsFuturesAccount(this SharedAccountType type) =>
type == SharedAccountType.PerpetualLinearFutures
|| type == SharedAccountType.DeliveryLinearFutures
|| type == SharedAccountType.PerpetualInverseFutures
|| type == SharedAccountType.DeliveryInverseFutures;
/// <summary>
/// Whether the account type is a margin account
/// </summary>
public static bool IsMarginAccount(this SharedAccountType type) =>
type == SharedAccountType.CrossMargin
|| type == SharedAccountType.IsolatedMargin;
/// <summary>
/// Map a TradingMode value to a SharedAccountType enum value
/// </summary>
public static SharedAccountType ToAccountType(this TradingMode mode)
{
if (mode == TradingMode.Spot) return SharedAccountType.Spot;
if (mode == TradingMode.PerpetualLinear) return SharedAccountType.PerpetualLinearFutures;
if (mode == TradingMode.PerpetualInverse) return SharedAccountType.PerpetualInverseFutures;
if (mode == TradingMode.DeliveryInverse) return SharedAccountType.DeliveryInverseFutures;
if (mode == TradingMode.DeliveryLinear) return SharedAccountType.DeliveryLinearFutures;
throw new ArgumentException(nameof(mode), "Unmapped trading mode");
}
/// <summary> /// <summary>
/// Register rest client interfaces /// Register rest client interfaces
/// </summary> /// </summary>
@ -445,6 +475,8 @@ namespace CryptoExchange.Net
services.AddTransient(x => (IFeeRestClient)client(x)!); services.AddTransient(x => (IFeeRestClient)client(x)!);
if (typeof(IBookTickerRestClient).IsAssignableFrom(typeof(T))) if (typeof(IBookTickerRestClient).IsAssignableFrom(typeof(T)))
services.AddTransient(x => (IBookTickerRestClient)client(x)!); services.AddTransient(x => (IBookTickerRestClient)client(x)!);
if (typeof(ITransferRestClient).IsAssignableFrom(typeof(T)))
services.AddTransient(x => (ITransferRestClient)client(x)!);
if (typeof(ISpotOrderRestClient).IsAssignableFrom(typeof(T))) if (typeof(ISpotOrderRestClient).IsAssignableFrom(typeof(T)))
services.AddTransient(x => (ISpotOrderRestClient)client(x)!); services.AddTransient(x => (ISpotOrderRestClient)client(x)!);

View File

@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Account type
/// </summary>
public enum SharedAccountType
{
/// <summary>
/// Unified account, combined account for multiple different types of trading
/// </summary>
Unified,
/// <summary>
/// Funding account, where withdrawals and deposits are made from and to
/// </summary>
Funding,
/// <summary>
/// Spot trading account
/// </summary>
Spot,
/// <summary>
/// Cross margin account
/// </summary>
CrossMargin,
/// <summary>
/// Isolated margin account
/// </summary>
IsolatedMargin,
/// <summary>
/// Perpetual linear futures account
/// </summary>
PerpetualLinearFutures,
/// <summary>
/// Delivery linear futures account
/// </summary>
DeliveryLinearFutures,
/// <summary>
/// Perpetual inverse futures account
/// </summary>
PerpetualInverseFutures,
/// <summary>
/// Delivery inverse futures account
/// </summary>
DeliveryInverseFutures,
/// <summary>
/// Option account
/// </summary>
Option,
/// <summary>
/// Other
/// </summary>
Other
}
}

View File

@ -12,7 +12,7 @@ namespace CryptoExchange.Net.SharedApis
/// <summary> /// <summary>
/// Balances request options /// Balances request options
/// </summary> /// </summary>
EndpointOptions<GetBalancesRequest> GetBalancesOptions { get; } GetBalancesOptions GetBalancesOptions { get; }
/// <summary> /// <summary>
/// Get balances for the user /// Get balances for the user

View File

@ -0,0 +1,25 @@
using CryptoExchange.Net.Objects;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Client for transferring funds between account types
/// </summary>
public interface ITransferRestClient : ISharedClient
{
/// <summary>
/// Transfer request options
/// </summary>
TransferOptions TransferOptions { get; }
/// <summary>
/// Transfer funds between account types
/// </summary>
/// <param name="request">Request info</param>
/// <param name="ct">Cancellation token</param>
Task<ExchangeWebResult<SharedId>> TransferAsync(TransferRequest request, CancellationToken ct = default);
}
}

View File

@ -0,0 +1,96 @@
using CryptoExchange.Net.Objects;
using System.Linq;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Options for requesting a transfer
/// </summary>
public class GetBalancesOptions : EndpointOptions<GetBalancesRequest>
{
/// <summary>
/// Supported account types
/// </summary>
public AccountTypeFilter[] SupportedAccountTypes { get; set; }
/// <summary>
/// ctor
/// </summary>
public GetBalancesOptions(params AccountTypeFilter[] accountTypes) : base(true)
{
SupportedAccountTypes = accountTypes;
}
/// <summary>
/// Validate a request
/// </summary>
public Error? ValidateRequest(
string exchange,
GetBalancesRequest request,
TradingMode[] supportedApiTypes)
{
if (request.AccountType != null && !IsValid(request.AccountType.Value))
return ArgumentError.Invalid(nameof(request.AccountType), "Invalid AccountType");
return base.ValidateRequest(exchange, request, null, supportedApiTypes);
}
/// <summary>
/// Is the account type valid for this client
/// </summary>
/// <param name="accountType"></param>
/// <returns></returns>
public bool IsValid(SharedAccountType accountType)
{
if (accountType == SharedAccountType.Funding)
return SupportedAccountTypes.Contains(AccountTypeFilter.Funding);
if (accountType == SharedAccountType.Spot)
return SupportedAccountTypes.Contains(AccountTypeFilter.Spot);
if (accountType == SharedAccountType.PerpetualLinearFutures
|| accountType == SharedAccountType.PerpetualInverseFutures
|| accountType == SharedAccountType.DeliveryLinearFutures
|| accountType == SharedAccountType.DeliveryInverseFutures)
{
return SupportedAccountTypes.Contains(AccountTypeFilter.Futures);
}
if (accountType == SharedAccountType.CrossMargin
|| accountType == SharedAccountType.IsolatedMargin)
{
return SupportedAccountTypes.Contains(AccountTypeFilter.Margin);
}
return SupportedAccountTypes.Contains(AccountTypeFilter.Option);
}
}
/// <summary>
/// Account type filter
/// </summary>
public enum AccountTypeFilter
{
/// <summary>
/// Funding account
/// </summary>
Funding,
/// <summary>
/// Spot account
/// </summary>
Spot,
/// <summary>
/// Futures account
/// </summary>
Futures,
/// <summary>
/// Margin account
/// </summary>
Margin,
/// <summary>
/// Option account
/// </summary>
Option
}
}

View File

@ -0,0 +1,42 @@
using CryptoExchange.Net.Objects;
using System.Linq;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Options for requesting a transfer
/// </summary>
public class TransferOptions : EndpointOptions<TransferRequest>
{
/// <summary>
/// Supported account types
/// </summary>
public SharedAccountType[] SupportedAccountTypes { get; set; }
/// <summary>
/// ctor
/// </summary>
public TransferOptions(SharedAccountType[] accountTypes) : base(true)
{
SupportedAccountTypes = accountTypes;
}
/// <summary>
/// Validate a request
/// </summary>
public new Error? ValidateRequest(
string exchange,
TransferRequest request,
TradingMode? tradingMode,
TradingMode[] supportedApiTypes)
{
if (!SupportedAccountTypes.Contains(request.FromAccountType))
return ArgumentError.Invalid(nameof(request.FromAccountType), "Invalid FromAccountType");
if (!SupportedAccountTypes.Contains(request.ToAccountType))
return ArgumentError.Invalid(nameof(request.FromAccountType), "Invalid ToAccountType");
return base.ValidateRequest(exchange, request, tradingMode, supportedApiTypes);
}
}
}

View File

@ -8,18 +8,28 @@ namespace CryptoExchange.Net.SharedApis
public record GetBalancesRequest : SharedRequest public record GetBalancesRequest : SharedRequest
{ {
/// <summary> /// <summary>
/// Trading mode /// Account type
/// </summary> /// </summary>
public TradingMode? TradingMode { get; set; } public SharedAccountType? AccountType { get; set; }
/// <summary> /// <summary>
/// ctor /// ctor
/// </summary> /// </summary>
/// <param name="tradingMode">Trading mode</param> /// <param name="tradingMode">Trading mode</param>
/// <param name="exchangeParameters">Exchange specific parameters</param> /// <param name="exchangeParameters">Exchange specific parameters</param>
public GetBalancesRequest(TradingMode? tradingMode = null, ExchangeParameters? exchangeParameters = null) : base(exchangeParameters) public GetBalancesRequest(TradingMode tradingMode, ExchangeParameters? exchangeParameters = null) : base(exchangeParameters)
{ {
TradingMode = tradingMode; AccountType = tradingMode.ToAccountType();
}
/// <summary>
/// ctor
/// </summary>
/// <param name="accountType">Account type</param>
/// <param name="exchangeParameters">Exchange specific parameters</param>
public GetBalancesRequest(SharedAccountType? accountType = null, ExchangeParameters? exchangeParameters = null) : base(exchangeParameters)
{
AccountType = accountType;
} }
} }
} }

View File

@ -0,0 +1,61 @@
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Request to transfer funds between account types
/// </summary>
public record TransferRequest : SharedRequest
{
/// <summary>
/// Asset
/// </summary>
public string Asset { get; set; }
/// <summary>
/// Quantity
/// </summary>
public decimal Quantity { get; set; }
/// <summary>
/// From symbol
/// </summary>
public string? FromSymbol { get; set; }
/// <summary>
/// To symbol
/// </summary>
public string? ToSymbol { get; set; }
/// <summary>
/// From account type
/// </summary>
public SharedAccountType FromAccountType { get; set; }
/// <summary>
/// To account type
/// </summary>
public SharedAccountType ToAccountType { get; set; }
/// <summary>
/// ctor
/// </summary>
/// <param name="asset">The asset to transfer</param>
/// <param name="quantity">Quantity to transfer</param>
/// <param name="fromAccount">From account type</param>
/// <param name="toAccount">To account type</param>
/// <param name="fromSymbol">From symbol</param>
/// <param name="toSymbol">To symbol</param>
/// <param name="exchangeParameters">Exchange specific parameters</param>
public TransferRequest(
string asset,
decimal quantity,
SharedAccountType fromAccount,
SharedAccountType toAccount,
string? fromSymbol = null,
string? toSymbol = null,
ExchangeParameters? exchangeParameters = null) : base(exchangeParameters)
{
Asset = asset;
Quantity = quantity;
FromAccountType = fromAccount;
ToAccountType = toAccount;
FromSymbol = fromSymbol;
ToSymbol = toSymbol;
}
}
}

View File

@ -17,6 +17,7 @@
/// Total quantity /// Total quantity
/// </summary> /// </summary>
public decimal Total { get; set; } public decimal Total { get; set; }
/// <summary> /// <summary>
/// Isolated margin symbol, only applicable for isolated margin futures /// Isolated margin symbol, only applicable for isolated margin futures
/// </summary> /// </summary>

View File

@ -28,6 +28,10 @@ namespace CryptoExchange.Net.SharedApis
/// </summary> /// </summary>
public string OrderId { get; set; } public string OrderId { get; set; }
/// <summary> /// <summary>
/// The client order id
/// </summary>
public string? ClientOrderId { get; set; }
/// <summary>
/// Side of the trade /// Side of the trade
/// </summary> /// </summary>
public SharedOrderSide? Side { get; set; } public SharedOrderSide? Side { get; set; }

View File

@ -415,7 +415,7 @@ namespace CryptoExchange.Net.Testing.Comparers
var value = jsonValue.GetDecimal(); var value = jsonValue.GetDecimal();
if (objectValue is DateTime time) if (objectValue is DateTime time)
{ {
if (time != DateTimeConverter.ParseFromDouble((double)value)) if (time != DateTimeConverter.ParseFromDecimal(value))
throw new Exception($"{method}: {property} not equal: {DateTimeConverter.ParseFromDouble((double)value!)} vs {time}"); throw new Exception($"{method}: {property} not equal: {DateTimeConverter.ParseFromDouble((double)value!)} vs {time}");
} }
else if (propertyType.IsEnum || Nullable.GetUnderlyingType(propertyType)?.IsEnum == true) else if (propertyType.IsEnum || Nullable.GetUnderlyingType(propertyType)?.IsEnum == true)

View File

@ -65,6 +65,13 @@ 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.10.0 - 15 Oct 2025
* Added ITransferRestClient Shared interface
* Added ClientOrderId property to SharedUserTrade model
* Updated IBalanceRestClient, GetBalancesRequest now mainly works with SharedAccountType type, allowing more options
* Updated IBalanceRestClient, GetBalanceOptions now specifies supported account types
* Updated DateTimeConverter to work primarily with decimal instead of double to prevent some floating point issues
* Version 9.9.0 - 06 Oct 2025 * Version 9.9.0 - 06 Oct 2025
* Updated socket Subscription status handling * Updated socket Subscription status handling
* Added SubscriptionStatusChanged event to UpdateSubscription (SubscribeAsync methods reponse) * Added SubscriptionStatusChanged event to UpdateSubscription (SubscribeAsync methods reponse)