diff --git a/CryptoExchange.Net/ExtensionMethods.cs b/CryptoExchange.Net/ExtensionMethods.cs index f1166de4..a3aa296d 100644 --- a/CryptoExchange.Net/ExtensionMethods.cs +++ b/CryptoExchange.Net/ExtensionMethods.cs @@ -461,11 +461,15 @@ namespace CryptoExchange.Net if (typeof(ISpotOrderSocketClient).IsAssignableFrom(typeof(T))) services.AddTransient(x => (ISpotOrderSocketClient)client(x)!); + if (typeof(ISpotOrderManagementSocketClient).IsAssignableFrom(typeof(T))) + services.AddTransient(x => (ISpotOrderManagementSocketClient)client(x)!); if (typeof(IFuturesOrderSocketClient).IsAssignableFrom(typeof(T))) services.AddTransient(x => (IFuturesOrderSocketClient)client(x)!); if (typeof(IPositionSocketClient).IsAssignableFrom(typeof(T))) services.AddTransient(x => (IPositionSocketClient)client(x)!); + if (typeof(IFuturesOrderManagementSocketClient).IsAssignableFrom(typeof(T))) + services.AddTransient(x => (IFuturesOrderManagementSocketClient)client(x)!); return services; } diff --git a/CryptoExchange.Net/SharedApis/Interfaces/Rest/Spot/ISpotOrderRestClient.cs b/CryptoExchange.Net/SharedApis/Interfaces/Rest/Spot/ISpotOrderRestClient.cs index 7f7c0d36..47af549b 100644 --- a/CryptoExchange.Net/SharedApis/Interfaces/Rest/Spot/ISpotOrderRestClient.cs +++ b/CryptoExchange.Net/SharedApis/Interfaces/Rest/Spot/ISpotOrderRestClient.cs @@ -44,7 +44,6 @@ namespace CryptoExchange.Net.SharedApis PlaceSpotOrderOptions PlaceSpotOrderOptions { get; } /// /// Place a new spot order, see for request options and exchange specific required/optional parameters.
- /// 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. ///
/// Request info /// Cancellation token diff --git a/CryptoExchange.Net/SharedApis/Interfaces/Socket/Futures/IFuturesOrderManagementSocketClient.cs b/CryptoExchange.Net/SharedApis/Interfaces/Socket/Futures/IFuturesOrderManagementSocketClient.cs new file mode 100644 index 00000000..50212b79 --- /dev/null +++ b/CryptoExchange.Net/SharedApis/Interfaces/Socket/Futures/IFuturesOrderManagementSocketClient.cs @@ -0,0 +1,66 @@ +using CryptoExchange.Net.Objects; +using System.Threading; +using System.Threading.Tasks; + +namespace CryptoExchange.Net.SharedApis +{ + /// + /// Client for placing and managing futures orders + /// + public interface IFuturesOrderManagementSocketClient : ISharedClient + { + /// + /// How the trading fee is deducted + /// + SharedFeeDeductionType FuturesFeeDeductionType { get; } + /// + /// How the asset is determined in which the trading fee is paid + /// + SharedFeeAssetType FuturesFeeAssetType { get; } + /// + /// Supported order types for futures orders + /// + SharedOrderType[] FuturesSupportedOrderTypes { get; } + /// + /// Supported time in force types for futures orders + /// + SharedTimeInForce[] FuturesSupportedTimeInForce { get; } + /// + /// Supported quantity types for futures orders + /// + SharedQuantitySupport FuturesSupportedOrderQuantity { get; } + + /// + /// Generate a new random client order id + /// + /// + string GenerateClientOrderId(); + + /// + /// Futures place order request options.
+ /// Use and to check for required and optional parameters for the request.
+ /// Exchange specific parameters can be added to the request via the `ExchangeParameters` property of the request object. + ///
+ PlaceFuturesOrderSocketOptions PlaceFuturesOrderOptions { get; } + + /// + /// Place a new futures order, see for request options and exchange specific required/optional parameters.
+ ///
+ /// Request info + /// Cancellation token + Task> PlaceFuturesOrderAsync(PlaceFuturesOrderRequest request, CancellationToken ct = default); + + /// + /// Futures cancel order request options.
+ /// Use and to check for required and optional parameters for the request.
+ /// Exchange specific parameters can be added to the request via the `ExchangeParameters` property of the request object. + ///
+ CancelFuturesOrderSocketOptions CancelFuturesOrderOptions { get; } + /// + /// Cancel a futures order, see for request options and exchange specific required/optional parameters.
+ ///
+ /// Request info + /// Cancellation token + Task> CancelFuturesOrderAsync(CancelOrderRequest request, CancellationToken ct = default); + } +} diff --git a/CryptoExchange.Net/SharedApis/Interfaces/Socket/Spot/ISpotOrderManagementSocketClient.cs b/CryptoExchange.Net/SharedApis/Interfaces/Socket/Spot/ISpotOrderManagementSocketClient.cs new file mode 100644 index 00000000..cfa34e94 --- /dev/null +++ b/CryptoExchange.Net/SharedApis/Interfaces/Socket/Spot/ISpotOrderManagementSocketClient.cs @@ -0,0 +1,66 @@ +using CryptoExchange.Net.Objects; +using System.Threading; +using System.Threading.Tasks; + +namespace CryptoExchange.Net.SharedApis +{ + /// + /// Client for placing and managing spot orders + /// + public interface ISpotOrderManagementSocketClient : ISharedClient + { + /// + /// How the trading fee is deducted + /// + SharedFeeDeductionType SpotFeeDeductionType { get; } + /// + /// How the asset is determined in which the trading fee is paid + /// + SharedFeeAssetType SpotFeeAssetType { get; } + /// + /// Supported order types for spot orders + /// + SharedOrderType[] SpotSupportedOrderTypes { get; } + /// + /// Supported time in force types for placing spot orders + /// + SharedTimeInForce[] SpotSupportedTimeInForce { get; } + /// + /// Supported quantity types for placing spot orders + /// + SharedQuantitySupport SpotSupportedOrderQuantity { get; } + + /// + /// Generate a new random client order id + /// + /// + string GenerateClientOrderId(); + + /// + /// Spot place order request options.
+ /// Use and to check for required and optional parameters for the request.
+ /// Exchange specific parameters can be added to the request via the `ExchangeParameters` property of the request object. + ///
+ PlaceSpotOrderSocketOptions PlaceSpotOrderOptions { get; } + /// + /// Place a new spot order, see for request options and exchange specific required/optional parameters.
+ ///
+ /// Request info + /// Cancellation token + Task> PlaceSpotOrderAsync(PlaceSpotOrderRequest request, CancellationToken ct = default); + + /// + /// Spot cancel order request options.
+ /// Use and to check for required and optional parameters for the request.
+ /// Exchange specific parameters can be added to the request via the `ExchangeParameters` property of the request object. + ///
+ CancelSpotOrderSocketOptions CancelSpotOrderOptions { get; } + /// + /// Cancel a spot order, see for request options and exchange specific required/optional parameters.
+ ///
+ /// Request info + /// Cancellation token + Task> CancelSpotOrderAsync(CancelOrderRequest request, CancellationToken ct = default); + + } +} diff --git a/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/CancelFuturesOrderSocketOptions.cs b/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/CancelFuturesOrderSocketOptions.cs new file mode 100644 index 00000000..8289f432 --- /dev/null +++ b/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/CancelFuturesOrderSocketOptions.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace CryptoExchange.Net.SharedApis +{ + /// + /// Options for canceling a futures order + /// + public class CancelFuturesOrderSocketOptions : EndpointOptions + { + /// + public override string Description => "Cancel a futures order over a socket connection"; + + /// + /// ctor + /// + public CancelFuturesOrderSocketOptions(string exchange, bool authenticated) : base(exchange, authenticated, nameof(IFuturesOrderManagementSocketClient.CancelFuturesOrderAsync)) + { + } + } +} diff --git a/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/CancelSpotOrderSocketOptions.cs b/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/CancelSpotOrderSocketOptions.cs new file mode 100644 index 00000000..4e0a4274 --- /dev/null +++ b/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/CancelSpotOrderSocketOptions.cs @@ -0,0 +1,32 @@ +using CryptoExchange.Net.Objects; +using System; +using System.Collections.Generic; +using System.Text; + +namespace CryptoExchange.Net.SharedApis +{ + /// + /// Options for canceling a spot order + /// + public class CancelSpotOrderSocketOptions : EndpointOptions + { + /// + public override string Description => "Cancel a spot order over a socket connection"; + + /// + /// ctor + /// + public CancelSpotOrderSocketOptions(string exchange, bool authenticated) : base(exchange, authenticated, nameof(ISpotOrderManagementSocketClient.CancelSpotOrderAsync)) + { + } + + /// + 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); + } + } +} diff --git a/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/PlaceFuturesOrderSocketOptions.cs b/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/PlaceFuturesOrderSocketOptions.cs new file mode 100644 index 00000000..0f249138 --- /dev/null +++ b/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/PlaceFuturesOrderSocketOptions.cs @@ -0,0 +1,56 @@ +using CryptoExchange.Net.Objects; +using System; +using System.Linq; + +namespace CryptoExchange.Net.SharedApis +{ + /// + /// Options for placing a new futures order + /// + public class PlaceFuturesOrderSocketOptions : EndpointOptions + { + /// + public override string Description => "Place a new futures order over a socket connection"; + + /// + /// Whether or not the API supports setting take profit / stop loss with the order + /// + public bool SupportsTpSl { get; set; } + + /// + /// ctor + /// + public PlaceFuturesOrderSocketOptions(string exchange, bool supportsTpSl) : base(exchange, true, nameof(IFuturesOrderManagementSocketClient.PlaceFuturesOrderAsync)) + { + SupportsTpSl = supportsTpSl; + } + + /// + /// Validate a request + /// + 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); + } + + } +} diff --git a/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/PlaceSpotOrderSocketOptions.cs b/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/PlaceSpotOrderSocketOptions.cs new file mode 100644 index 00000000..341482b5 --- /dev/null +++ b/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/PlaceSpotOrderSocketOptions.cs @@ -0,0 +1,49 @@ +using CryptoExchange.Net.Objects; +using System; +using System.Linq; + +namespace CryptoExchange.Net.SharedApis +{ + /// + /// Options for placing a new spot order + /// + public class PlaceSpotOrderSocketOptions : EndpointOptions + { + /// + public override string Description => "Place a new spot order over a socket connection"; + + + /// + /// ctor + /// + public PlaceSpotOrderSocketOptions(string exchange) : base(exchange, true, nameof(ISpotOrderManagementSocketClient.PlaceSpotOrderAsync)) + { + } + + /// + /// Validate a request + /// + 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); + } + } +} diff --git a/CryptoExchange.Net/SharedApis/SharedUtils.cs b/CryptoExchange.Net/SharedApis/SharedUtils.cs index a8719471..f716767c 100644 --- a/CryptoExchange.Net/SharedApis/SharedUtils.cs +++ b/CryptoExchange.Net/SharedApis/SharedUtils.cs @@ -169,13 +169,23 @@ namespace CryptoExchange.Net.SharedApis if (client is ISpotOrderSocketClient spotOrderSocketClient) result.Add(spotOrderSocketClient.SubscribeSpotOrderOptions); + if (client is ISpotOrderManagementSocketClient spotOrderManagementSocketClient) + { + result.Add(spotOrderManagementSocketClient.PlaceSpotOrderOptions); + result.Add(spotOrderManagementSocketClient.CancelSpotOrderOptions); + } if (client is IFuturesOrderSocketClient futuresOrderSocketClient) result.Add(futuresOrderSocketClient.SubscribeFuturesOrderOptions); if (client is IPositionSocketClient positionSocketClient) 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(); } ///