1
0
mirror of https://github.com/JKorf/CryptoExchange.Net.git synced 2026-10-04 02:11:11 +00:00

Added ISpotOrderManagementSocketClient and IFuturesOrderManagementSocketClient for placing/canceling orders via websocket

This commit is contained in:
Jkorf
2026-08-21 09:56:56 +02:00
parent ac1e9cf2ab
commit ecfe3cf392
9 changed files with 306 additions and 2 deletions
+4
View File
@@ -461,11 +461,15 @@ namespace CryptoExchange.Net
if (typeof(ISpotOrderSocketClient).IsAssignableFrom(typeof(T))) if (typeof(ISpotOrderSocketClient).IsAssignableFrom(typeof(T)))
services.AddTransient(x => (ISpotOrderSocketClient)client(x)!); services.AddTransient(x => (ISpotOrderSocketClient)client(x)!);
if (typeof(ISpotOrderManagementSocketClient).IsAssignableFrom(typeof(T)))
services.AddTransient(x => (ISpotOrderManagementSocketClient)client(x)!);
if (typeof(IFuturesOrderSocketClient).IsAssignableFrom(typeof(T))) if (typeof(IFuturesOrderSocketClient).IsAssignableFrom(typeof(T)))
services.AddTransient(x => (IFuturesOrderSocketClient)client(x)!); services.AddTransient(x => (IFuturesOrderSocketClient)client(x)!);
if (typeof(IPositionSocketClient).IsAssignableFrom(typeof(T))) if (typeof(IPositionSocketClient).IsAssignableFrom(typeof(T)))
services.AddTransient(x => (IPositionSocketClient)client(x)!); services.AddTransient(x => (IPositionSocketClient)client(x)!);
if (typeof(IFuturesOrderManagementSocketClient).IsAssignableFrom(typeof(T)))
services.AddTransient(x => (IFuturesOrderManagementSocketClient)client(x)!);
return services; return services;
} }
@@ -44,7 +44,6 @@ namespace CryptoExchange.Net.SharedApis
PlaceSpotOrderOptions PlaceSpotOrderOptions { get; } PlaceSpotOrderOptions PlaceSpotOrderOptions { get; }
/// <summary> /// <summary>
/// Place a new spot order, see <see cref="PlaceSpotOrderOptions"/> for request options and exchange specific required/optional parameters. <br /> /// Place a new spot order, see <see cref="PlaceSpotOrderOptions"/> for request options and exchange specific required/optional parameters. <br />
/// The result is paginated, if there are more results to be retrieved, the `NextPageRequest` property of the result will contain the pagination request to be used for the next request to continue pagination.
/// </summary> /// </summary>
/// <param name="request">Request info</param> /// <param name="request">Request info</param>
/// <param name="ct">Cancellation token</param> /// <param name="ct">Cancellation token</param>
@@ -0,0 +1,66 @@
using CryptoExchange.Net.Objects;
using System.Threading;
using System.Threading.Tasks;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Client for placing and managing futures orders
/// </summary>
public interface IFuturesOrderManagementSocketClient : ISharedClient
{
/// <summary>
/// How the trading fee is deducted
/// </summary>
SharedFeeDeductionType FuturesFeeDeductionType { get; }
/// <summary>
/// How the asset is determined in which the trading fee is paid
/// </summary>
SharedFeeAssetType FuturesFeeAssetType { get; }
/// <summary>
/// Supported order types for futures orders
/// </summary>
SharedOrderType[] FuturesSupportedOrderTypes { get; }
/// <summary>
/// Supported time in force types for futures orders
/// </summary>
SharedTimeInForce[] FuturesSupportedTimeInForce { get; }
/// <summary>
/// Supported quantity types for futures orders
/// </summary>
SharedQuantitySupport FuturesSupportedOrderQuantity { get; }
/// <summary>
/// Generate a new random client order id
/// </summary>
/// <returns></returns>
string GenerateClientOrderId();
/// <summary>
/// Futures place order request options.<br />
/// Use <see cref="EndpointOptions.RequiredExchangeParameters"/> and <see cref="EndpointOptions.OptionalExchangeParameters"/> to check for required and optional parameters for the request. <br />
/// Exchange specific parameters can be added to the request via the `ExchangeParameters` property of the request object.
/// </summary>
PlaceFuturesOrderSocketOptions PlaceFuturesOrderOptions { get; }
/// <summary>
/// Place a new futures order, see <see cref="PlaceFuturesOrderOptions"/> for request options and exchange specific required/optional parameters. <br />
/// </summary>
/// <param name="request">Request info</param>
/// <param name="ct">Cancellation token</param>
Task<QueryResult<SharedId>> PlaceFuturesOrderAsync(PlaceFuturesOrderRequest request, CancellationToken ct = default);
/// <summary>
/// Futures cancel order request options.<br />
/// Use <see cref="EndpointOptions.RequiredExchangeParameters"/> and <see cref="EndpointOptions.OptionalExchangeParameters"/> to check for required and optional parameters for the request. <br />
/// Exchange specific parameters can be added to the request via the `ExchangeParameters` property of the request object.
/// </summary>
CancelFuturesOrderSocketOptions CancelFuturesOrderOptions { get; }
/// <summary>
/// Cancel a futures order, see <see cref="CancelFuturesOrderOptions"/> for request options and exchange specific required/optional parameters. <br />
/// </summary>
/// <param name="request">Request info</param>
/// <param name="ct">Cancellation token</param>
Task<QueryResult<SharedId>> CancelFuturesOrderAsync(CancelOrderRequest request, CancellationToken ct = default);
}
}
@@ -0,0 +1,66 @@
using CryptoExchange.Net.Objects;
using System.Threading;
using System.Threading.Tasks;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Client for placing and managing spot orders
/// </summary>
public interface ISpotOrderManagementSocketClient : ISharedClient
{
/// <summary>
/// How the trading fee is deducted
/// </summary>
SharedFeeDeductionType SpotFeeDeductionType { get; }
/// <summary>
/// How the asset is determined in which the trading fee is paid
/// </summary>
SharedFeeAssetType SpotFeeAssetType { get; }
/// <summary>
/// Supported order types for spot orders
/// </summary>
SharedOrderType[] SpotSupportedOrderTypes { get; }
/// <summary>
/// Supported time in force types for placing spot orders
/// </summary>
SharedTimeInForce[] SpotSupportedTimeInForce { get; }
/// <summary>
/// Supported quantity types for placing spot orders
/// </summary>
SharedQuantitySupport SpotSupportedOrderQuantity { get; }
/// <summary>
/// Generate a new random client order id
/// </summary>
/// <returns></returns>
string GenerateClientOrderId();
/// <summary>
/// Spot place order request options.<br />
/// Use <see cref="EndpointOptions.RequiredExchangeParameters"/> and <see cref="EndpointOptions.OptionalExchangeParameters"/> to check for required and optional parameters for the request. <br />
/// Exchange specific parameters can be added to the request via the `ExchangeParameters` property of the request object.
/// </summary>
PlaceSpotOrderSocketOptions PlaceSpotOrderOptions { get; }
/// <summary>
/// Place a new spot order, see <see cref="PlaceSpotOrderOptions"/> for request options and exchange specific required/optional parameters. <br />
/// </summary>
/// <param name="request">Request info</param>
/// <param name="ct">Cancellation token</param>
Task<QueryResult<SharedId>> PlaceSpotOrderAsync(PlaceSpotOrderRequest request, CancellationToken ct = default);
/// <summary>
/// Spot cancel order request options.<br />
/// Use <see cref="EndpointOptions.RequiredExchangeParameters"/> and <see cref="EndpointOptions.OptionalExchangeParameters"/> to check for required and optional parameters for the request. <br />
/// Exchange specific parameters can be added to the request via the `ExchangeParameters` property of the request object.
/// </summary>
CancelSpotOrderSocketOptions CancelSpotOrderOptions { get; }
/// <summary>
/// Cancel a spot order, see <see cref="CancelSpotOrderOptions"/> for request options and exchange specific required/optional parameters. <br />
/// </summary>
/// <param name="request">Request info</param>
/// <param name="ct">Cancellation token</param>
Task<QueryResult<SharedId>> CancelSpotOrderAsync(CancelOrderRequest request, CancellationToken ct = default);
}
}
@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Options for canceling a futures order
/// </summary>
public class CancelFuturesOrderSocketOptions : EndpointOptions<CancelOrderRequest, IFuturesOrderManagementSocketClient>
{
/// <inheritdoc />
public override string Description => "Cancel a futures order over a socket connection";
/// <summary>
/// ctor
/// </summary>
public CancelFuturesOrderSocketOptions(string exchange, bool authenticated) : base(exchange, authenticated, nameof(IFuturesOrderManagementSocketClient.CancelFuturesOrderAsync))
{
}
}
}
@@ -0,0 +1,32 @@
using CryptoExchange.Net.Objects;
using System;
using System.Collections.Generic;
using System.Text;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Options for canceling a spot order
/// </summary>
public class CancelSpotOrderSocketOptions : EndpointOptions<CancelOrderRequest, ISpotOrderManagementSocketClient>
{
/// <inheritdoc />
public override string Description => "Cancel a spot order over a socket connection";
/// <summary>
/// ctor
/// </summary>
public CancelSpotOrderSocketOptions(string exchange, bool authenticated) : base(exchange, authenticated, nameof(ISpotOrderManagementSocketClient.CancelSpotOrderAsync))
{
}
/// <inheritdoc />
public override Error? ValidateRequest(CancelOrderRequest request, ISpotOrderManagementSocketClient client)
{
if (request.Symbol!.TradingMode != TradingMode.Spot)
return ArgumentError.Invalid("TradingMode", $"TradingMode.{request.Symbol!.TradingMode} is not supported, should be Spot");
return base.ValidateRequest(request, client);
}
}
}
@@ -0,0 +1,56 @@
using CryptoExchange.Net.Objects;
using System;
using System.Linq;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Options for placing a new futures order
/// </summary>
public class PlaceFuturesOrderSocketOptions : EndpointOptions<PlaceFuturesOrderRequest, IFuturesOrderManagementSocketClient>
{
/// <inheritdoc />
public override string Description => "Place a new futures order over a socket connection";
/// <summary>
/// Whether or not the API supports setting take profit / stop loss with the order
/// </summary>
public bool SupportsTpSl { get; set; }
/// <summary>
/// ctor
/// </summary>
public PlaceFuturesOrderSocketOptions(string exchange, bool supportsTpSl) : base(exchange, true, nameof(IFuturesOrderManagementSocketClient.PlaceFuturesOrderAsync))
{
SupportsTpSl = supportsTpSl;
}
/// <summary>
/// Validate a request
/// </summary>
public override Error? ValidateRequest(
PlaceFuturesOrderRequest request,
IFuturesOrderManagementSocketClient client
)
{
if (!SupportsTpSl && (request.StopLossPrice != null || request.TakeProfitPrice != null))
return ArgumentError.Invalid(nameof(PlaceFuturesOrderRequest.StopLossPrice) + " / " + nameof(PlaceFuturesOrderRequest.TakeProfitPrice), "Tp/Sl parameters not supported");
if (request.OrderType == SharedOrderType.Other)
throw new ArgumentException("OrderType can't be `Other`", nameof(request.OrderType));
if (!client.FuturesSupportedOrderTypes.Contains(request.OrderType))
return ArgumentError.Invalid(nameof(PlaceFuturesOrderRequest.OrderType), "Order type not supported");
if (request.TimeInForce != null && !client.FuturesSupportedTimeInForce.Contains(request.TimeInForce.Value))
return ArgumentError.Invalid(nameof(PlaceFuturesOrderRequest.TimeInForce), "Order time in force not supported");
var quantityError = client.FuturesSupportedOrderQuantity.Validate(request.Side, request.OrderType, request.Quantity);
if (quantityError != null)
return quantityError;
return base.ValidateRequest(request, client);
}
}
}
@@ -0,0 +1,49 @@
using CryptoExchange.Net.Objects;
using System;
using System.Linq;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Options for placing a new spot order
/// </summary>
public class PlaceSpotOrderSocketOptions : EndpointOptions<PlaceSpotOrderRequest, ISpotOrderManagementSocketClient>
{
/// <inheritdoc />
public override string Description => "Place a new spot order over a socket connection";
/// <summary>
/// ctor
/// </summary>
public PlaceSpotOrderSocketOptions(string exchange) : base(exchange, true, nameof(ISpotOrderManagementSocketClient.PlaceSpotOrderAsync))
{
}
/// <summary>
/// Validate a request
/// </summary>
public override Error? ValidateRequest(
PlaceSpotOrderRequest request,
ISpotOrderManagementSocketClient client)
{
if (request.Symbol!.TradingMode != TradingMode.Spot)
return ArgumentError.Invalid("TradingMode", $"TradingMode.{request.Symbol!.TradingMode} is not supported, should be Spot");
if (request.OrderType == SharedOrderType.Other)
throw new ArgumentException("OrderType can't be `Other`", nameof(request.OrderType));
if (!client.SpotSupportedOrderTypes.Contains(request.OrderType))
return ArgumentError.Invalid(nameof(PlaceSpotOrderRequest.OrderType), "Order type not supported");
if (request.TimeInForce != null && !client.SpotSupportedTimeInForce.Contains(request.TimeInForce.Value))
return ArgumentError.Invalid(nameof(PlaceSpotOrderRequest.TimeInForce), "Order time in force not supported");
var quantityError = client.SpotSupportedOrderQuantity.Validate(request.Side, request.OrderType, request.Quantity);
if (quantityError != null)
return quantityError;
return base.ValidateRequest(request, client);
}
}
}
+11 -1
View File
@@ -169,13 +169,23 @@ namespace CryptoExchange.Net.SharedApis
if (client is ISpotOrderSocketClient spotOrderSocketClient) if (client is ISpotOrderSocketClient spotOrderSocketClient)
result.Add(spotOrderSocketClient.SubscribeSpotOrderOptions); result.Add(spotOrderSocketClient.SubscribeSpotOrderOptions);
if (client is ISpotOrderManagementSocketClient spotOrderManagementSocketClient)
{
result.Add(spotOrderManagementSocketClient.PlaceSpotOrderOptions);
result.Add(spotOrderManagementSocketClient.CancelSpotOrderOptions);
}
if (client is IFuturesOrderSocketClient futuresOrderSocketClient) if (client is IFuturesOrderSocketClient futuresOrderSocketClient)
result.Add(futuresOrderSocketClient.SubscribeFuturesOrderOptions); result.Add(futuresOrderSocketClient.SubscribeFuturesOrderOptions);
if (client is IPositionSocketClient positionSocketClient) if (client is IPositionSocketClient positionSocketClient)
result.Add(positionSocketClient.SubscribePositionOptions); result.Add(positionSocketClient.SubscribePositionOptions);
if (client is IFuturesOrderManagementSocketClient futuresOrderManagementSocketClient)
{
result.Add(futuresOrderManagementSocketClient.PlaceFuturesOrderOptions);
result.Add(futuresOrderManagementSocketClient.CancelFuturesOrderOptions);
}
return result.ToArray(); return result.Where(x => x.Supported).ToArray();
} }
/// <summary> /// <summary>