diff --git a/Kucoin.Net.UnitTests/Endpoints/Futures/Trading/PlaceTpSlOrder.txt b/Kucoin.Net.UnitTests/Endpoints/Futures/Trading/PlaceTpSlOrder.txt new file mode 100644 index 0000000..e2a7ead --- /dev/null +++ b/Kucoin.Net.UnitTests/Endpoints/Futures/Trading/PlaceTpSlOrder.txt @@ -0,0 +1,10 @@ +POST +/api/v1/st-orders +true +{ + "code": "200000", + "data": { + "orderId": "5bd6e9286d99522a52e458de", + "clientOid": "5c52e11203aa677f33e493fb" + } + } \ No newline at end of file diff --git a/Kucoin.Net.UnitTests/RestRequestTests.cs b/Kucoin.Net.UnitTests/RestRequestTests.cs index ba13b18..3aa20f4 100644 --- a/Kucoin.Net.UnitTests/RestRequestTests.cs +++ b/Kucoin.Net.UnitTests/RestRequestTests.cs @@ -225,6 +225,7 @@ public async Task ValidateFuturesTradingCalls() var tester = new RestRequestValidator(client, "Endpoints/Futures/Trading", "https://api-futures.kucoin.com", IsAuthenticated, "data", stjCompare: false); await tester.ValidateAsync(client => client.FuturesApi.Trading.PlaceOrderAsync("ETHUSDT", Enums.OrderSide.Buy, Enums.NewOrderType.Market, 1, 1), "PlaceOrder"); await tester.ValidateAsync(client => client.FuturesApi.Trading.PlaceTestOrderAsync("ETHUSDT", Enums.OrderSide.Buy, Enums.NewOrderType.Market, 1, 1), "PlaceTestOrder"); + await tester.ValidateAsync(client => client.FuturesApi.Trading.PlaceTpSlOrderAsync("ETHUSDT", Enums.OrderSide.Buy, Enums.NewOrderType.Market, 1, 1), "PlaceTpSlOrder"); await tester.ValidateAsync(client => client.FuturesApi.Trading.PlaceMultipleOrdersAsync(new[] { new KucoinFuturesOrderRequestEntry() }), "PlaceMultipleOrders"); await tester.ValidateAsync(client => client.FuturesApi.Trading.CancelOrderAsync("123"), "CancelOrder"); await tester.ValidateAsync(client => client.FuturesApi.Trading.CancelOrderByClientOrderIdAsync("ETHUSDT", "123"), "CancelOrderByClientOrderId"); diff --git a/Kucoin.Net/Clients/FuturesApi/KucoinRestClientFuturesApiTrading.cs b/Kucoin.Net/Clients/FuturesApi/KucoinRestClientFuturesApiTrading.cs index c384242..9b00a72 100644 --- a/Kucoin.Net/Clients/FuturesApi/KucoinRestClientFuturesApiTrading.cs +++ b/Kucoin.Net/Clients/FuturesApi/KucoinRestClientFuturesApiTrading.cs @@ -135,6 +135,58 @@ public async Task> PlaceTestOrderAsync( return await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); } + /// + public async Task> PlaceTpSlOrderAsync( + string symbol, + OrderSide side, + NewOrderType type, + decimal leverage, + int quantity, + + decimal? price = null, + TimeInForce? timeInForce = null, + bool? postOnly = null, + bool? hidden = null, + bool? iceberg = null, + decimal? visibleSize = null, + + string? remark = null, + decimal? takeProfitPrice = null, + decimal? stopLossPrice = null, + StopPriceType? stopPriceType = null, + bool? reduceOnly = null, + bool? closeOrder = null, + bool? forceHold = null, + string? clientOrderId = null, + SelfTradePrevention? selfTradePrevention = null, + CancellationToken ct = default) + { + var parameters = new ParameterCollection(); + parameters.AddParameter("symbol", symbol); + parameters.AddParameter("side", JsonConvert.SerializeObject(side, new OrderSideConverter(false))); + parameters.AddParameter("type", JsonConvert.SerializeObject(type, new NewOrderTypeConverter(false))); + parameters.AddParameter("leverage", leverage.ToString(CultureInfo.InvariantCulture)); + parameters.AddParameter("size", quantity.ToString(CultureInfo.InvariantCulture)); + parameters.AddParameter("clientOid", clientOrderId ?? Guid.NewGuid().ToString()); + parameters.AddOptionalParameter("remark", remark); + parameters.AddOptionalString("triggerStopUpPrice", takeProfitPrice); + parameters.AddOptionalParameter("stopPriceType", stopPriceType != null ? JsonConvert.SerializeObject(stopPriceType, new StopPriceTypeConverter(false)) : null); + parameters.AddOptionalString("triggerStopDownPrice", stopLossPrice); + parameters.AddOptionalParameter("reduceOnly", reduceOnly?.ToString()); + parameters.AddOptionalParameter("closeOrder", closeOrder?.ToString()); + parameters.AddOptionalParameter("forceHold", forceHold?.ToString()); + parameters.AddOptionalParameter("price", price?.ToString(CultureInfo.InvariantCulture)); + parameters.AddOptionalParameter("timeInForce", timeInForce != null ? JsonConvert.SerializeObject(timeInForce, new TimeInForceConverter(false)) : null); + parameters.AddOptionalParameter("postOnly", postOnly?.ToString()); + parameters.AddOptionalParameter("hidden", hidden?.ToString()); + parameters.AddOptionalParameter("iceberg", iceberg); + parameters.AddOptionalParameter("visibleSize", visibleSize?.ToString()); + parameters.AddOptionalEnum("stp", selfTradePrevention); + + var request = _definitions.GetOrCreate(HttpMethod.Post, $"api/v1/st-orders", KucoinExchange.RateLimiter.FuturesRest, 2, true); + return await _baseClient.SendAsync(request, parameters, ct).ConfigureAwait(false); + } + /// public async Task>> PlaceMultipleOrdersAsync(IEnumerable orders, CancellationToken ct = default) { diff --git a/Kucoin.Net/Interfaces/Clients/FuturesApi/IKucoinRestClientFuturesApiTrading.cs b/Kucoin.Net/Interfaces/Clients/FuturesApi/IKucoinRestClientFuturesApiTrading.cs index 5fdee56..5a04952 100644 --- a/Kucoin.Net/Interfaces/Clients/FuturesApi/IKucoinRestClientFuturesApiTrading.cs +++ b/Kucoin.Net/Interfaces/Clients/FuturesApi/IKucoinRestClientFuturesApiTrading.cs @@ -115,6 +115,58 @@ Task> PlaceTestOrderAsync( SelfTradePrevention? selfTradePrevention = null, CancellationToken ct = default); + + /// + /// Place a new take profit / stop loss order + /// + /// + /// The contract for the order, for example `XBTUSDM` + /// Side of the order + /// Type of order + /// Leverage of the order + /// Limit price, only for limit orders + /// Time in force, only for limit orders + /// Post only flag, invalid when timeInForce is IOC + /// Orders not displaying in order book. When hidden chose + /// Only visible portion of the order is displayed in the order book + /// The maximum visible size of an iceberg order + /// Quantity of contract to buy or sell + /// Remark for the order + /// Price type + /// Take profit price + /// Stop loss price + /// A mark to reduce the position size only. Set to false by default + /// A mark to close the position. Set to false by default. All the positions will be closed if true + /// A mark to forcely hold the funds for an order, even though it's an order to reduce the position size. This helps the order stay on the order book and not get canceled when the position size changes. Set to false by default + /// Self Trade Prevention mode + /// Client order id + /// Cancellation token + /// Order details + Task> PlaceTpSlOrderAsync( + string symbol, + OrderSide side, + NewOrderType type, + decimal leverage, + int quantity, + + decimal? price = null, + TimeInForce? timeInForce = null, + bool? postOnly = null, + bool? hidden = null, + bool? iceberg = null, + decimal? visibleSize = null, + + string? remark = null, + decimal? takeProfitPrice = null, + decimal? stopLossPrice = null, + StopPriceType? stopPriceType = null, + bool? reduceOnly = null, + bool? closeOrder = null, + bool? forceHold = null, + string? clientOrderId = null, + SelfTradePrevention? selfTradePrevention = null, + CancellationToken ct = default); + /// /// Place multiple orders /// diff --git a/Kucoin.Net/Kucoin.Net.xml b/Kucoin.Net/Kucoin.Net.xml index e9f7598..7055819 100644 --- a/Kucoin.Net/Kucoin.Net.xml +++ b/Kucoin.Net/Kucoin.Net.xml @@ -175,6 +175,9 @@ + + + @@ -2769,6 +2772,34 @@ Cancellation token Order details + + + Place a new take profit / stop loss order + + + The contract for the order, for example `XBTUSDM` + Side of the order + Type of order + Leverage of the order + Limit price, only for limit orders + Time in force, only for limit orders + Post only flag, invalid when timeInForce is IOC + Orders not displaying in order book. When hidden chose + Only visible portion of the order is displayed in the order book + The maximum visible size of an iceberg order + Quantity of contract to buy or sell + Remark for the order + Price type + Take profit price + Stop loss price + A mark to reduce the position size only. Set to false by default + A mark to close the position. Set to false by default. All the positions will be closed if true + A mark to forcely hold the funds for an order, even though it's an order to reduce the position size. This helps the order stay on the order book and not get canceled when the position size changes. Set to false by default + Self Trade Prevention mode + Client order id + Cancellation token + Order details + Place multiple orders @@ -10000,6 +10031,11 @@ The id of the order + + + The client order id + + Redemption record diff --git a/Kucoin.Net/Objects/Models/Spot/KucoinOrderId.cs b/Kucoin.Net/Objects/Models/Spot/KucoinOrderId.cs index 2e0f1eb..7abf6a7 100644 --- a/Kucoin.Net/Objects/Models/Spot/KucoinOrderId.cs +++ b/Kucoin.Net/Objects/Models/Spot/KucoinOrderId.cs @@ -12,5 +12,10 @@ public record KucoinOrderId /// [JsonProperty("orderId")] public string Id { get; set; } = string.Empty; + /// + /// The client order id + /// + [JsonProperty("clientOid")] + public string? ClientOrderId { get; set; } } }