diff --git a/src/ExchangeSharp/API/Exchanges/Aquanow/ExchangeAquanowAPI.cs b/src/ExchangeSharp/API/Exchanges/Aquanow/ExchangeAquanowAPI.cs index 68ac6430..ee3571a9 100644 --- a/src/ExchangeSharp/API/Exchanges/Aquanow/ExchangeAquanowAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/Aquanow/ExchangeAquanowAPI.cs @@ -233,8 +233,9 @@ protected override async Task OnGetOrderDetailsAsync(string return orderDetails; } - protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null) + protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) { + if (isClientOrderId) throw new NotSupportedException("Cancelling by client order ID is not supported in ExchangeSharp. Please submit a PR if you are interested in this feature"); var payload = await GetNoncePayloadAsync(); payload["orderId"] = orderId; JToken token = await MakeJsonRequestAsync("/trades/v1/order", null, payload, "DELETE"); diff --git a/src/ExchangeSharp/API/Exchanges/BL3P/ExchangeBL3PAPI.cs b/src/ExchangeSharp/API/Exchanges/BL3P/ExchangeBL3PAPI.cs index 3f87cfd2..ea54efd1 100644 --- a/src/ExchangeSharp/API/Exchanges/BL3P/ExchangeBL3PAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/BL3P/ExchangeBL3PAPI.cs @@ -292,10 +292,11 @@ protected override async Task OnGetOrderBookAsync(string mark return ConvertToExchangeOrderBook(maxCount, bl3pOrderBook); } - protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null) + protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) { if (string.IsNullOrWhiteSpace(marketSymbol)) throw new ArgumentException("Value cannot be null or whitespace.", nameof(marketSymbol)); + if (isClientOrderId) throw new NotSupportedException("Cancelling by client order ID is not supported in ExchangeSharp. Please submit a PR if you are interested in this feature"); var resultBody = await MakeRequestAsync( $"/{marketSymbol}/money/order/cancel", diff --git a/src/ExchangeSharp/API/Exchanges/BTSE/ExchangeBTSEAPI.cs b/src/ExchangeSharp/API/Exchanges/BTSE/ExchangeBTSEAPI.cs index 1c2c3c48..1374bc7b 100644 --- a/src/ExchangeSharp/API/Exchanges/BTSE/ExchangeBTSEAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/BTSE/ExchangeBTSEAPI.cs @@ -67,7 +67,7 @@ protected override async Task> OnGetCandlesAsync(strin this.ParseCandle(token, marketSymbol, periodSeconds, 1, 2, 3, 4, 0, TimestampType.UnixMilliseconds, 5)); } - protected override async Task OnCancelOrderAsync(string orderId, string? marketSymbol = null) + protected override async Task OnCancelOrderAsync(string orderId, string? marketSymbol = null, bool isClientOrderId = false) { var payload = await GetNoncePayloadAsync(); diff --git a/src/ExchangeSharp/API/Exchanges/BinanceGroup/BinanceGroupCommon.cs b/src/ExchangeSharp/API/Exchanges/BinanceGroup/BinanceGroupCommon.cs index 542d5dad..b3b6bfa9 100644 --- a/src/ExchangeSharp/API/Exchanges/BinanceGroup/BinanceGroupCommon.cs +++ b/src/ExchangeSharp/API/Exchanges/BinanceGroup/BinanceGroupCommon.cs @@ -733,7 +733,7 @@ private async Task> OnGetMyTradesAsync(string? return trades; } - protected override async Task OnCancelOrderAsync(string orderId, string? marketSymbol = null) + protected override async Task OnCancelOrderAsync(string orderId, string? marketSymbol = null, bool isClientOrderId = false) { Dictionary payload = await GetNoncePayloadAsync(); if (string.IsNullOrWhiteSpace(marketSymbol)) @@ -741,7 +741,10 @@ protected override async Task OnCancelOrderAsync(string orderId, string? marketS throw new ArgumentNullException("Binance cancel order request requires symbol"); } payload["symbol"] = marketSymbol!; - payload["orderId"] = orderId; + if (isClientOrderId) // Either orderId or origClientOrderId must be sent. + payload["origClientOrderId"] = orderId; + else + payload["orderId"] = orderId; var token = await MakeJsonRequestAsync("/order", BaseUrlApi, payload, "DELETE"); var cancelledOrder = ParseOrder(token); if (cancelledOrder.OrderId != orderId) diff --git a/src/ExchangeSharp/API/Exchanges/BitBank/ExchangeBitBankAPI.cs b/src/ExchangeSharp/API/Exchanges/BitBank/ExchangeBitBankAPI.cs index 83b8403a..bd0091c6 100644 --- a/src/ExchangeSharp/API/Exchanges/BitBank/ExchangeBitBankAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/BitBank/ExchangeBitBankAPI.cs @@ -141,8 +141,9 @@ protected override async Task OnPlaceOrderAsync(ExchangeOrd return ParseOrder(token); } - protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null) + protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) { + if (isClientOrderId) throw new NotSupportedException("Cancelling by client order ID is not supported in ExchangeSharp. Please submit a PR if you are interested in this feature"); Dictionary payload = await GetNoncePayloadAsync(); if (marketSymbol == null) throw new APIException("Bitbank requries market symbol when cancelling orders"); diff --git a/src/ExchangeSharp/API/Exchanges/BitMEX/ExchangeBitMEXAPI.cs b/src/ExchangeSharp/API/Exchanges/BitMEX/ExchangeBitMEXAPI.cs index 764ac681..02671740 100644 --- a/src/ExchangeSharp/API/Exchanges/BitMEX/ExchangeBitMEXAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/BitMEX/ExchangeBitMEXAPI.cs @@ -614,10 +614,10 @@ protected override async Task OnGetOrderDetailsAsync(string return orders[0]; } - protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null) + protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) { Dictionary payload = await GetNoncePayloadAsync(); - payload["orderID"] = orderId; + payload[isClientOrderId ? "clOrdID" : "orderID"] = orderId; JToken token = await MakeJsonRequestAsync("/order", BaseUrl, payload, "DELETE"); } diff --git a/src/ExchangeSharp/API/Exchanges/Bitfinex/ExchangeBitfinexAPI.cs b/src/ExchangeSharp/API/Exchanges/Bitfinex/ExchangeBitfinexAPI.cs index 4f7190a0..f81d6444 100644 --- a/src/ExchangeSharp/API/Exchanges/Bitfinex/ExchangeBitfinexAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/Bitfinex/ExchangeBitfinexAPI.cs @@ -569,8 +569,9 @@ protected override Task OnGetCompletedOrderDetailsWebSocketAsync(Act }); } - protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null) + protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) { + if (isClientOrderId) throw new NotSupportedException("Cancelling by client order ID is not supported in ExchangeSharp. Please submit a PR if you are interested in this feature"); Dictionary payload = await GetNoncePayloadAsync(); payload["order_id"] = orderId.ConvertInvariant(); var token = await MakeJsonRequestAsync("/order/cancel", BaseUrlV1, payload); diff --git a/src/ExchangeSharp/API/Exchanges/Bitstamp/ExchangeBitstampAPI.cs b/src/ExchangeSharp/API/Exchanges/Bitstamp/ExchangeBitstampAPI.cs index 9d385f7e..13ebd3a8 100644 --- a/src/ExchangeSharp/API/Exchanges/Bitstamp/ExchangeBitstampAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/Bitstamp/ExchangeBitstampAPI.cs @@ -487,9 +487,10 @@ protected override async Task> OnGetCompletedOr return orders2; } - protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null) - { - if (string.IsNullOrWhiteSpace(orderId)) + protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) + { + if (isClientOrderId) throw new NotSupportedException("Cancelling by client order ID is not supported in ExchangeSharp. Please submit a PR if you are interested in this feature"); + if (string.IsNullOrWhiteSpace(orderId)) { throw new APIException("OrderId is needed for canceling order"); } diff --git a/src/ExchangeSharp/API/Exchanges/Bittrex/ExchangeBittrexAPI.cs b/src/ExchangeSharp/API/Exchanges/Bittrex/ExchangeBittrexAPI.cs index 2c0b693d..9475254f 100644 --- a/src/ExchangeSharp/API/Exchanges/Bittrex/ExchangeBittrexAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/Bittrex/ExchangeBittrexAPI.cs @@ -456,8 +456,9 @@ protected override async Task> OnGetCompletedOr return orders; } - protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null) + protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) { + if (isClientOrderId) throw new NotSupportedException("Cancelling by client order ID is not supported in ExchangeSharp. Please submit a PR if you are interested in this feature"); await MakeJsonRequestAsync("/orders/" + orderId, null, await GetNoncePayloadAsync(), "DELETE"); } diff --git a/src/ExchangeSharp/API/Exchanges/Bybit/ExchangeBybitAPI.cs b/src/ExchangeSharp/API/Exchanges/Bybit/ExchangeBybitAPI.cs index 5ef30e21..d8bb36db 100644 --- a/src/ExchangeSharp/API/Exchanges/Bybit/ExchangeBybitAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/Bybit/ExchangeBybitAPI.cs @@ -778,10 +778,13 @@ protected override async Task OnGetOrderDetailsAsync(string } } - protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null) + protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) { var extraParams = new Dictionary(); - extraParams["order_id"] = orderId; + if (isClientOrderId) + extraParams["order_link_id"] = orderId; + else + extraParams["order_id"] = orderId; if (!string.IsNullOrWhiteSpace(marketSymbol)) { extraParams["symbol"] = marketSymbol; diff --git a/src/ExchangeSharp/API/Exchanges/Coinbase/ExchangeCoinbaseAPI.cs b/src/ExchangeSharp/API/Exchanges/Coinbase/ExchangeCoinbaseAPI.cs index 45ab4a61..4844a7f4 100644 --- a/src/ExchangeSharp/API/Exchanges/Coinbase/ExchangeCoinbaseAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/Coinbase/ExchangeCoinbaseAPI.cs @@ -807,9 +807,9 @@ private async Task MakeFillRequest(DateTime? afterDate, string productId, List("orders/" + orderId, null, await GetNoncePayloadAsync(), "DELETE"); + var jToken = await MakeJsonRequestAsync("orders/" + (isClientOrderId ? "client:" : "") + orderId, null, await GetNoncePayloadAsync(), "DELETE"); if (jToken.ToStringInvariant() != orderId) throw new APIException($"Cancelled {jToken.ToStringInvariant()} when trying to cancel {orderId}"); } diff --git a/src/ExchangeSharp/API/Exchanges/Coinmate/ExchangeCoinmateAPI.cs b/src/ExchangeSharp/API/Exchanges/Coinmate/ExchangeCoinmateAPI.cs index 0d571572..e7fe4591 100644 --- a/src/ExchangeSharp/API/Exchanges/Coinmate/ExchangeCoinmateAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/Coinmate/ExchangeCoinmateAPI.cs @@ -151,7 +151,7 @@ protected override async Task OnGetOrderDetailsAsync(string }; } - protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null) + protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) { var payload = await GetNoncePayloadAsync(); payload["orderId"] = orderId; diff --git a/src/ExchangeSharp/API/Exchanges/Digifinex/ExchangeDigifinexAPI.cs b/src/ExchangeSharp/API/Exchanges/Digifinex/ExchangeDigifinexAPI.cs index 71b7c0ef..2f3ecedf 100644 --- a/src/ExchangeSharp/API/Exchanges/Digifinex/ExchangeDigifinexAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/Digifinex/ExchangeDigifinexAPI.cs @@ -432,8 +432,9 @@ protected override async Task OnPlaceOrderAsync(ExchangeOrd return new ExchangeOrderResult { OrderId = token["order_id"].ToStringInvariant() }; } - protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null) + protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) { + if (isClientOrderId) throw new NotSupportedException("Cancelling by client order ID is not supported in ExchangeSharp. Please submit a PR if you are interested in this feature"); Dictionary payload = await GetNoncePayloadAsync(); payload["order_id"] = orderId; JToken token = await MakeJsonRequestAsync("/spot/order/cancel", payload: payload, requestMethod: "POST"); diff --git a/src/ExchangeSharp/API/Exchanges/FTX/FTXGroupCommon.cs b/src/ExchangeSharp/API/Exchanges/FTX/FTXGroupCommon.cs index 51407e8d..b76be1f8 100644 --- a/src/ExchangeSharp/API/Exchanges/FTX/FTXGroupCommon.cs +++ b/src/ExchangeSharp/API/Exchanges/FTX/FTXGroupCommon.cs @@ -23,9 +23,15 @@ public FTXGroupCommon() #region [ Implementation ] /// - protected async override Task OnCancelOrderAsync(string orderId, string marketSymbol = null) + protected async override Task OnCancelOrderAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) { - await MakeJsonRequestAsync($"/orders/{orderId}", null, await GetNoncePayloadAsync(), "DELETE"); + var url = "/orders/"; + if (isClientOrderId) + { + url += "by_client_id/"; + } + + await MakeJsonRequestAsync($"{url}{orderId}", null, await GetNoncePayloadAsync(), "DELETE"); } /// diff --git a/src/ExchangeSharp/API/Exchanges/GateIo/ExchangeGateIoAPI.cs b/src/ExchangeSharp/API/Exchanges/GateIo/ExchangeGateIoAPI.cs index 6dc67282..d6b45aac 100644 --- a/src/ExchangeSharp/API/Exchanges/GateIo/ExchangeGateIoAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/GateIo/ExchangeGateIoAPI.cs @@ -421,12 +421,13 @@ protected override async Task> OnGetCompletedOr return responseToken.Select(x => ParseOrder(x)).ToArray(); } - protected override async Task OnCancelOrderAsync(string orderId, string symbol = null) + protected override async Task OnCancelOrderAsync(string orderId, string symbol = null, bool isClientOrderId = false) { if (string.IsNullOrEmpty(symbol)) { throw new InvalidOperationException("MarketSymbol is required for cancelling order with Gate.io API"); } + if (isClientOrderId) throw new NotSupportedException("Cancelling by client order ID is not supported in ExchangeSharp. Please submit a PR if you are interested in this feature"); Dictionary payload = await GetNoncePayloadAsync(); await MakeJsonRequestAsync($"/spot/orders/{orderId}?currency_pair={symbol}", BaseUrl, payload, "DELETE"); diff --git a/src/ExchangeSharp/API/Exchanges/Gemini/ExchangeGeminiAPI.cs b/src/ExchangeSharp/API/Exchanges/Gemini/ExchangeGeminiAPI.cs index 37891ce2..8d0e04eb 100644 --- a/src/ExchangeSharp/API/Exchanges/Gemini/ExchangeGeminiAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/Gemini/ExchangeGeminiAPI.cs @@ -355,8 +355,9 @@ protected override async Task> OnGetOpenOrderDe return orders; } - protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null) + protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) { + if (isClientOrderId) throw new NotSupportedException("Cancelling by client order ID is not supported in ExchangeSharp. Please submit a PR if you are interested in this feature"); object nonce = await GenerateNonceAsync(); await MakeJsonRequestAsync("/order/cancel", null, new Dictionary { { "nonce", nonce }, { "order_id", orderId } }); } diff --git a/src/ExchangeSharp/API/Exchanges/Hitbtc/ExchangeHitbtcAPI.cs b/src/ExchangeSharp/API/Exchanges/Hitbtc/ExchangeHitbtcAPI.cs index 88763e6e..06ddf541 100644 --- a/src/ExchangeSharp/API/Exchanges/Hitbtc/ExchangeHitbtcAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/Hitbtc/ExchangeHitbtcAPI.cs @@ -353,10 +353,11 @@ protected override async Task OnPlaceOrderAsync(ExchangeOrd return result; } - protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null) - { - // this call returns info about the success of the cancel. Sure would be nice have a return type on this method. - JToken token = await MakeJsonRequestAsync("/order/" + orderId, null, await GetNoncePayloadAsync(), "DELETE"); + protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) + { + if (isClientOrderId) throw new NotSupportedException("Cancelling by client order ID is not supported in ExchangeSharp. Please submit a PR if you are interested in this feature"); + // this call returns info about the success of the cancel. Sure would be nice have a return type on this method. + JToken token = await MakeJsonRequestAsync("/order/" + orderId, null, await GetNoncePayloadAsync(), "DELETE"); } private void ParseAveragePriceAndFeesFromFills(ExchangeOrderResult result, JToken fillsToken) diff --git a/src/ExchangeSharp/API/Exchanges/Huobi/ExchangeHuobiAPI.cs b/src/ExchangeSharp/API/Exchanges/Huobi/ExchangeHuobiAPI.cs index 9cbb1b4f..26feae76 100644 --- a/src/ExchangeSharp/API/Exchanges/Huobi/ExchangeHuobiAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/Huobi/ExchangeHuobiAPI.cs @@ -717,10 +717,16 @@ protected override async Task OnPlaceOrderAsync(ExchangeOrd return ParsePlaceOrder(obj, order); } - protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null) - { + protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) + { var payload = await GetNoncePayloadAsync(); - await MakeJsonRequestAsync($"/order/orders/{orderId}/submitcancel", PrivateUrlV1, payload, "POST"); + JToken data; + if (isClientOrderId) + { + payload.Add("clientOrderId", orderId); + data = await MakeJsonRequestAsync($"/order/orders/submitCancelClientOrder", PrivateUrlV1, payload, "POST"); + } + else data = await MakeJsonRequestAsync($"/order/orders/{orderId}/submitcancel", PrivateUrlV1, payload, "POST"); } protected override async Task> OnGetDepositHistoryAsync(string currency) diff --git a/src/ExchangeSharp/API/Exchanges/Kraken/ExchangeKrakenAPI.cs b/src/ExchangeSharp/API/Exchanges/Kraken/ExchangeKrakenAPI.cs index db236753..bda98db3 100644 --- a/src/ExchangeSharp/API/Exchanges/Kraken/ExchangeKrakenAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/Kraken/ExchangeKrakenAPI.cs @@ -768,8 +768,9 @@ protected override async Task> OnGetCompletedOr // return token["trades"].Select(t => TradeHistoryToExchangeOrderResult(t)); //} - protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null) + protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) { + if (isClientOrderId) throw new NotSupportedException("Cancelling by client order ID is not supported in ExchangeSharp. Please submit a PR if you are interested in this feature"); object nonce = await GenerateNonceAsync(); Dictionary payload = new Dictionary(StringComparer.OrdinalIgnoreCase) { { "txid", orderId }, { "nonce", nonce } diff --git a/src/ExchangeSharp/API/Exchanges/KuCoin/ExchangeKuCoinAPI.cs b/src/ExchangeSharp/API/Exchanges/KuCoin/ExchangeKuCoinAPI.cs index 7f3bd5e0..30cc10c0 100644 --- a/src/ExchangeSharp/API/Exchanges/KuCoin/ExchangeKuCoinAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/KuCoin/ExchangeKuCoinAPI.cs @@ -422,20 +422,11 @@ protected override async Task OnPlaceOrderAsync(ExchangeOrd /// /// The Original Order Id return from Place Order /// - protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null) - { - // Find order detail - ExchangeOrderResult order = await GetOrderDetailsAsync(orderId, marketSymbol: marketSymbol); - - // There is no order to be cancelled - if (order == null) - { - return; - } - + protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) + { var payload = await GetNoncePayloadAsync(); - JToken token = await MakeJsonRequestAsync("/orders/" + orderId, null, payload, "DELETE"); + JToken token = await MakeJsonRequestAsync(isClientOrderId ? "/order/client-order/" : "/orders/" + orderId, null, payload, "DELETE"); } protected override async Task OnGetDepositAddressAsync(string currency, bool forceRegenerate = false) diff --git a/src/ExchangeSharp/API/Exchanges/LBank/ExchangeLBankAPI.cs b/src/ExchangeSharp/API/Exchanges/LBank/ExchangeLBankAPI.cs index 2afc1bc5..cb43bd7d 100644 --- a/src/ExchangeSharp/API/Exchanges/LBank/ExchangeLBankAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/LBank/ExchangeLBankAPI.cs @@ -345,8 +345,9 @@ protected override async Task> OnGetCompletedOr } //CancelOrder 12 - protected override async Task OnCancelOrderAsync(string orderId, string symbol = null) + protected override async Task OnCancelOrderAsync(string orderId, string symbol = null, bool isClientOrderId = false) { + if (isClientOrderId) throw new NotSupportedException("Cancelling by client order ID is not supported in ExchangeSharp. Please submit a PR if you are interested in this feature"); Dictionary payload = new Dictionary { { "api_key", PublicApiKey.ToUnsecureString() }, diff --git a/src/ExchangeSharp/API/Exchanges/Livecoin/ExchangeLivecoinAPI.cs b/src/ExchangeSharp/API/Exchanges/Livecoin/ExchangeLivecoinAPI.cs index 3ddeab9b..b176dec1 100644 --- a/src/ExchangeSharp/API/Exchanges/Livecoin/ExchangeLivecoinAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/Livecoin/ExchangeLivecoinAPI.cs @@ -286,10 +286,11 @@ protected override async Task OnPlaceOrderAsync(ExchangeOrd return new ExchangeOrderResult() { OrderId = token["orderId"].ToStringInvariant(), Result = ExchangeAPIOrderResult.Open }; } - protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null) - { - // can only cancel limit orders, which kinda makes sense, but we also need the currency pair, which requires a lookup - var order = await OnGetOrderDetailsAsync(orderId); + protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) + { + if (isClientOrderId) throw new NotSupportedException("Cancelling by client order ID is not supported in ExchangeSharp. Please submit a PR if you are interested in this feature"); + // can only cancel limit orders, which kinda makes sense, but we also need the currency pair, which requires a lookup + var order = await OnGetOrderDetailsAsync(orderId); if (order != null) { // { "success": true,"cancelled": true,"message": null,"quantity": 0.0005,"tradeQuantity": 0} diff --git a/src/ExchangeSharp/API/Exchanges/NDAX/ExchangeNDAXAPI.cs b/src/ExchangeSharp/API/Exchanges/NDAX/ExchangeNDAXAPI.cs index b6e7c0a7..5c2f1288 100644 --- a/src/ExchangeSharp/API/Exchanges/NDAX/ExchangeNDAXAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/NDAX/ExchangeNDAXAPI.cs @@ -226,9 +226,10 @@ protected override async Task> OnGetOpenOrderDe } - protected override async Task OnCancelOrderAsync(string orderId, string symbol = null) - { - var result = await MakeJsonRequestAsync("CancelOrder", null, + protected override async Task OnCancelOrderAsync(string orderId, string symbol = null, bool isClientOrderId = false) + { + if (isClientOrderId) throw new NotSupportedException("Cancelling by client order ID is not supported in ExchangeSharp. Please submit a PR if you are interested in this feature"); + var result = await MakeJsonRequestAsync("CancelOrder", null, new Dictionary() { {"OrderId", orderId}, diff --git a/src/ExchangeSharp/API/Exchanges/OKGroup/ExchangeOKExAPI.cs b/src/ExchangeSharp/API/Exchanges/OKGroup/ExchangeOKExAPI.cs index 371479bb..d5ca4773 100644 --- a/src/ExchangeSharp/API/Exchanges/OKGroup/ExchangeOKExAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/OKGroup/ExchangeOKExAPI.cs @@ -295,7 +295,7 @@ protected override async Task OnGetOrderDetailsAsync(string return ParseOrders(token).First(); } - protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol) + protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol, bool isClientOrderId = false) { if (string.IsNullOrEmpty(orderId)) { @@ -308,7 +308,10 @@ protected override async Task OnCancelOrderAsync(string orderId, string marketSy } var payload = await GetNoncePayloadAsync(); - payload["ordId"] = orderId; + if (isClientOrderId) + payload["client_oid "] = orderId; + else + payload["ordId"] = orderId; payload["instId"] = marketSymbol; await MakeJsonRequestAsync("/trade/cancel-order", BaseUrlV5, payload, "POST"); } diff --git a/src/ExchangeSharp/API/Exchanges/OKGroup/OKGroupCommon.cs b/src/ExchangeSharp/API/Exchanges/OKGroup/OKGroupCommon.cs index 9d5bea29..e7bb51f1 100644 --- a/src/ExchangeSharp/API/Exchanges/OKGroup/OKGroupCommon.cs +++ b/src/ExchangeSharp/API/Exchanges/OKGroup/OKGroupCommon.cs @@ -450,16 +450,16 @@ protected override async Task OnPlaceOrderAsync(ExchangeOrd return ParsePlaceOrder(obj, order); } - protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null) - { + protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) + { Dictionary payload = await GetNoncePayloadAsync(); if (marketSymbol.Length == 0) { - throw new InvalidOperationException("Okex cancel order request requires symbol"); + throw new ArgumentNullException("Okex cancel order request requires symbol"); } payload["symbol"] = marketSymbol; - payload["order_id"] = orderId; - await MakeJsonRequestAsync("/cancel_order.do", BaseUrl, payload, "POST"); + payload["order_id"] = orderId; // OKCoin can use either OID or ClientOID: POST /api/spot/v3/cancel_orders/ or + await MakeJsonRequestAsync("/cancel_order.do", BaseUrl, payload, "POST"); } protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) diff --git a/src/ExchangeSharp/API/Exchanges/Poloniex/ExchangePoloniexAPI.cs b/src/ExchangeSharp/API/Exchanges/Poloniex/ExchangePoloniexAPI.cs index 7806de56..c0c9e9fe 100644 --- a/src/ExchangeSharp/API/Exchanges/Poloniex/ExchangePoloniexAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/Poloniex/ExchangePoloniexAPI.cs @@ -887,9 +887,10 @@ protected override async Task> OnGetCompletedOr return orders; } - protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null) - { - await MakePrivateAPIRequestAsync("cancelOrder", new object[] { "orderNumber", orderId.ConvertInvariant() }); + protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) + { + if (isClientOrderId) throw new NotSupportedException("Cancelling by client order ID is not supported in ExchangeSharp. Please submit a PR if you are interested in this feature"); + await MakePrivateAPIRequestAsync("cancelOrder", new object[] { "orderNumber", orderId.ConvertInvariant() }); } protected override async Task OnWithdrawAsync(ExchangeWithdrawalRequest withdrawalRequest) diff --git a/src/ExchangeSharp/API/Exchanges/Yobit/ExchangeYobitAPI.cs b/src/ExchangeSharp/API/Exchanges/Yobit/ExchangeYobitAPI.cs index 710ac2e1..51e24433 100644 --- a/src/ExchangeSharp/API/Exchanges/Yobit/ExchangeYobitAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/Yobit/ExchangeYobitAPI.cs @@ -276,9 +276,10 @@ protected override async Task OnPlaceOrderAsync(ExchangeOrd return result; } - protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null) - { - var payload = await GetNoncePayloadAsync(); + protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) + { + if (isClientOrderId) throw new NotSupportedException("Cancelling by client order ID is not supported in ExchangeSharp. Please submit a PR if you are interested in this feature"); + var payload = await GetNoncePayloadAsync(); payload.Add("method", "CancelOrder"); payload.Add("order_id", orderId); await MakeJsonRequestAsync("/", PrivateURL, payload, "POST"); diff --git a/src/ExchangeSharp/API/Exchanges/_Base/ExchangeAPI.cs b/src/ExchangeSharp/API/Exchanges/_Base/ExchangeAPI.cs index 0dbfadf0..7c830ee2 100644 --- a/src/ExchangeSharp/API/Exchanges/_Base/ExchangeAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/_Base/ExchangeAPI.cs @@ -203,7 +203,7 @@ protected virtual Task> OnGetOpenOrderDetailsAs throw new NotImplementedException(); protected virtual Task> OnGetCompletedOrderDetailsAsync(string? marketSymbol = null, DateTime? afterDate = null) => throw new NotImplementedException(); - protected virtual Task OnCancelOrderAsync(string orderId, string? marketSymbol = null) => + protected virtual Task OnCancelOrderAsync(string orderId, string? marketSymbol = null, bool isClientOrderId = false) => throw new NotImplementedException(); protected virtual Task OnWithdrawAsync(ExchangeWithdrawalRequest withdrawalRequest) => throw new NotImplementedException(); @@ -1039,11 +1039,12 @@ public virtual async Task> GetCompletedOrderDet /// /// Order id of the order to cancel /// Symbol of order (most exchanges do not require this) - public virtual async Task CancelOrderAsync(string orderId, string? marketSymbol = null) + /// Whether the order id parameter is the server assigned id or client provided id + public virtual async Task CancelOrderAsync(string orderId, string? marketSymbol = null, bool isClientOrderId = false) { // *NOTE* do not wrap in CacheMethodCall await new SynchronizationContextRemover(); - await OnCancelOrderAsync(orderId, NormalizeMarketSymbol(marketSymbol)); + await OnCancelOrderAsync(orderId, NormalizeMarketSymbol(marketSymbol), isClientOrderId); } /// diff --git a/src/ExchangeSharp/API/Exchanges/_Base/IExchangeAPI.cs b/src/ExchangeSharp/API/Exchanges/_Base/IExchangeAPI.cs index 65f49040..38bb87c4 100644 --- a/src/ExchangeSharp/API/Exchanges/_Base/IExchangeAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/_Base/IExchangeAPI.cs @@ -231,7 +231,8 @@ public interface IExchangeAPI : IDisposable, IBaseAPI, IOrderBookProvider /// /// Order id of the order to cancel /// Market symbol of the order to cancel (not required for most exchanges) - Task CancelOrderAsync(string orderId, string? marketSymbol = null); + /// Whether the order id parameter is the server assigned id or client provided id + Task CancelOrderAsync(string orderId, string? marketSymbol = null, bool isClientOrderId = false); /// /// Asynchronous withdraws request.