diff --git a/src/ExchangeSharp/API/Exchanges/Aquanow/ExchangeAquanowAPI.cs b/src/ExchangeSharp/API/Exchanges/Aquanow/ExchangeAquanowAPI.cs index 792cf002..517b7097 100644 --- a/src/ExchangeSharp/API/Exchanges/Aquanow/ExchangeAquanowAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/Aquanow/ExchangeAquanowAPI.cs @@ -194,12 +194,13 @@ protected override async Task OnPlaceOrderAsync(ExchangeOrd return orderDetails; } - protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null) + protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) { if (string.IsNullOrWhiteSpace(orderId)) { return null; } + if (isClientOrderId) throw new NotImplementedException("Querying by client order ID is not implemented in ExchangeSharp. Please submit a PR if you are interested in this feature"); var payload = await GetNoncePayloadAsync(); JToken result = await MakeJsonRequestAsync($"/trades/v1/order?orderId={orderId}", null, payload, "GET"); bool isBuy = result["tradeSide"].ToStringInvariant() == "buy" ? true : false; diff --git a/src/ExchangeSharp/API/Exchanges/BL3P/ExchangeBL3PAPI.cs b/src/ExchangeSharp/API/Exchanges/BL3P/ExchangeBL3PAPI.cs index d5ab5bdd..ddef36e2 100644 --- a/src/ExchangeSharp/API/Exchanges/BL3P/ExchangeBL3PAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/BL3P/ExchangeBL3PAPI.cs @@ -271,7 +271,7 @@ protected override async Task OnPlaceOrderAsync(ExchangeOrd var result = JsonConvert.DeserializeObject(resultBody) .Except(); - var orderDetails = await GetOrderDetailsAsync(result.OrderId, order.MarketSymbol); + var orderDetails = await GetOrderDetailsAsync(result.OrderId, marketSymbol: order.MarketSymbol); return orderDetails; } @@ -308,10 +308,11 @@ protected override async Task OnCancelOrderAsync(string orderId, string marketSy .Except(); } - protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null) + protected override async Task OnGetOrderDetailsAsync(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 NotImplementedException("Querying by client order ID is not implemented in ExchangeSharp. Please submit a PR if you are interested in this feature"); var data = new Dictionary { diff --git a/src/ExchangeSharp/API/Exchanges/BinanceGroup/BinanceGroupCommon.cs b/src/ExchangeSharp/API/Exchanges/BinanceGroup/BinanceGroupCommon.cs index 843a96ee..21024b50 100644 --- a/src/ExchangeSharp/API/Exchanges/BinanceGroup/BinanceGroupCommon.cs +++ b/src/ExchangeSharp/API/Exchanges/BinanceGroup/BinanceGroupCommon.cs @@ -580,7 +580,7 @@ protected override async Task OnPlaceOrderAsync(ExchangeOrd return ParseOrder(token); } - protected override async Task OnGetOrderDetailsAsync(string orderId, string? marketSymbol = null) + protected override async Task OnGetOrderDetailsAsync(string orderId, string? marketSymbol = null, bool isClientOrderId = false) { Dictionary payload = await GetNoncePayloadAsync(); if (string.IsNullOrWhiteSpace(marketSymbol)) @@ -588,7 +588,12 @@ protected override async Task OnGetOrderDetailsAsync(string throw new InvalidOperationException("Binance single order details 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; + JToken token = await MakeJsonRequestAsync("/order", BaseUrlPrivate, payload); ExchangeOrderResult result = ParseOrder(token); diff --git a/src/ExchangeSharp/API/Exchanges/BitBank/ExchangeBitBankAPI.cs b/src/ExchangeSharp/API/Exchanges/BitBank/ExchangeBitBankAPI.cs index b36cf62e..e6b15bb9 100644 --- a/src/ExchangeSharp/API/Exchanges/BitBank/ExchangeBitBankAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/BitBank/ExchangeBitBankAPI.cs @@ -148,8 +148,9 @@ protected override async Task OnCancelOrderAsync(string orderId, string marketSy await MakeJsonRequestAsync("/user/spot/cancel_order", baseUrl: BaseUrlPrivate, payload: payload, requestMethod: "POST"); } - protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null) + protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) { + if (isClientOrderId) throw new NotImplementedException("Querying by client order ID is not implemented in ExchangeSharp. Please submit a PR if you are interested in this feature"); var payload = await GetNoncePayloadAsync(); payload.Add("order_id", orderId); if (marketSymbol == null) diff --git a/src/ExchangeSharp/API/Exchanges/BitMEX/ExchangeBitMEXAPI.cs b/src/ExchangeSharp/API/Exchanges/BitMEX/ExchangeBitMEXAPI.cs index 8a549532..17e473d5 100644 --- a/src/ExchangeSharp/API/Exchanges/BitMEX/ExchangeBitMEXAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/BitMEX/ExchangeBitMEXAPI.cs @@ -600,11 +600,11 @@ protected override async Task> OnGetOpenOrderDe return orders; } - protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null) + protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) { List orders = new List(); Dictionary payload = await GetNoncePayloadAsync(); - string query = $"/order?filter={{\"orderID\": \"{orderId}\"}}"; + string query = $"/order?filter={{\"{(isClientOrderId ? "clOrdID" : "orderID")}\": \"{orderId}\"}}"; JToken token = await MakeJsonRequestAsync(query, BaseUrl, payload, "GET"); foreach (JToken order in token) { diff --git a/src/ExchangeSharp/API/Exchanges/Bitfinex/ExchangeBitfinexAPI.cs b/src/ExchangeSharp/API/Exchanges/Bitfinex/ExchangeBitfinexAPI.cs index f74c8c12..fab3250b 100644 --- a/src/ExchangeSharp/API/Exchanges/Bitfinex/ExchangeBitfinexAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/Bitfinex/ExchangeBitfinexAPI.cs @@ -493,8 +493,9 @@ protected override async Task OnPlaceOrderAsync(ExchangeOrd return ParseOrder(obj); } - protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null) + protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) { + if (isClientOrderId) throw new NotImplementedException("Querying by client order ID is not implemented in ExchangeSharp. Please submit a PR if you are interested in this feature"); if (string.IsNullOrWhiteSpace(orderId)) { return null; diff --git a/src/ExchangeSharp/API/Exchanges/Bitstamp/ExchangeBitstampAPI.cs b/src/ExchangeSharp/API/Exchanges/Bitstamp/ExchangeBitstampAPI.cs index e88b8674..9bb89a1e 100644 --- a/src/ExchangeSharp/API/Exchanges/Bitstamp/ExchangeBitstampAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/Bitstamp/ExchangeBitstampAPI.cs @@ -219,8 +219,8 @@ protected override async Task OnPlaceOrderAsync(ExchangeOrd }; } - protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null) - { + protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) + { //{ // "status": "Finished", // "id": 1022694747, @@ -241,8 +241,11 @@ protected override async Task OnGetOrderDetailsAsync(string } string url = "/order_status/"; Dictionary payload = await GetNoncePayloadAsync(); - payload["id"] = orderId; - JObject result = await MakeJsonRequestAsync(url, null, payload, "POST"); + if (isClientOrderId) // Order can be fetched by using either id or client_order_id parameter. + payload["client_order_id"] = orderId; + else + payload["id"] = orderId; + JObject result = await MakeJsonRequestAsync(url, null, payload, "POST"); var transactions = result["transactions"] as JArray; var anyTransaction = transactions.Any(); diff --git a/src/ExchangeSharp/API/Exchanges/Bittrex/ExchangeBittrexAPI.cs b/src/ExchangeSharp/API/Exchanges/Bittrex/ExchangeBittrexAPI.cs index ef268f4b..781c5a6d 100644 --- a/src/ExchangeSharp/API/Exchanges/Bittrex/ExchangeBittrexAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/Bittrex/ExchangeBittrexAPI.cs @@ -412,8 +412,9 @@ protected override async Task OnPlaceOrderAsync(ExchangeOrd } - protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null) + protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) { + if (isClientOrderId) throw new NotImplementedException("Querying by client order ID is not implemented in ExchangeSharp. Please submit a PR if you are interested in this feature"); if (string.IsNullOrWhiteSpace(orderId)) { return null; diff --git a/src/ExchangeSharp/API/Exchanges/Bybit/ExchangeBybitAPI.cs b/src/ExchangeSharp/API/Exchanges/Bybit/ExchangeBybitAPI.cs index 108131e3..0d93d122 100644 --- a/src/ExchangeSharp/API/Exchanges/Bybit/ExchangeBybitAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/Bybit/ExchangeBybitAPI.cs @@ -718,13 +718,16 @@ public async Task GetPredictedFundingRateAsync(string marketSym return funding; } - private async Task> DoGetOrderDetailsAsync(string orderId, string marketSymbol = null) + private async Task> DoGetOrderDetailsAsync(string orderId, bool isClientOrderId = false, string marketSymbol = null) { var extraParams = new Dictionary(); if (orderId != null) { - extraParams["order_id"] = orderId; + if (isClientOrderId) + extraParams["order_link_id"] = orderId; + else + extraParams["order_id"] = orderId; } if (!string.IsNullOrWhiteSpace(marketSymbol)) @@ -758,13 +761,13 @@ private async Task> DoGetOrderDetailsAsync(stri //Note, Bybit is not recommending the use of "/v2/private/order/list" now that "/v2/private/order" is capable of returning multiple results protected override async Task> OnGetOpenOrderDetailsAsync(string marketSymbol = null) { - var orders = await DoGetOrderDetailsAsync(null, marketSymbol); + var orders = await DoGetOrderDetailsAsync(null, isClientOrderId: false, marketSymbol: marketSymbol); return orders; } - protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null) + protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) { - var orders = await DoGetOrderDetailsAsync(orderId, marketSymbol); + var orders = await DoGetOrderDetailsAsync(orderId, isClientOrderId: isClientOrderId, marketSymbol: marketSymbol); if (orders.Count() > 0) { return orders.First(); diff --git a/src/ExchangeSharp/API/Exchanges/Coinbase/ExchangeCoinbaseAPI.cs b/src/ExchangeSharp/API/Exchanges/Coinbase/ExchangeCoinbaseAPI.cs index aa408265..d0ce1a9c 100644 --- a/src/ExchangeSharp/API/Exchanges/Coinbase/ExchangeCoinbaseAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/Coinbase/ExchangeCoinbaseAPI.cs @@ -594,9 +594,10 @@ protected override async Task OnPlaceOrderAsync(ExchangeOrd return ParseOrder(result); } - protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null) - { - JToken obj = await MakeJsonRequestAsync("/orders/" + orderId, null, await GetNoncePayloadAsync(), "GET"); + protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) + { // Orders may be queried using either the exchange assigned id or the client assigned client_oid. When using client_oid it must be preceded by the client: namespace. + JToken obj = await MakeJsonRequestAsync("/orders/" + (isClientOrderId ? "client:" : "") + orderId, + null, await GetNoncePayloadAsync(), "GET"); return ParseOrder(obj); } diff --git a/src/ExchangeSharp/API/Exchanges/Digifinex/ExchangeDigifinexAPI.cs b/src/ExchangeSharp/API/Exchanges/Digifinex/ExchangeDigifinexAPI.cs index 6206ab1d..6efa71ec 100644 --- a/src/ExchangeSharp/API/Exchanges/Digifinex/ExchangeDigifinexAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/Digifinex/ExchangeDigifinexAPI.cs @@ -361,8 +361,9 @@ protected override async Task> OnGetCompletedOr }); } - protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null) + protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) { + if (isClientOrderId) throw new NotImplementedException("Querying by client order ID is not implemented in ExchangeSharp. Please submit a PR if you are interested in this feature"); Dictionary payload = await GetNoncePayloadAsync(); JToken token = await MakeJsonRequestAsync($"/spot/order?order_id={orderId}", payload: payload); var x = token["data"]; diff --git a/src/ExchangeSharp/API/Exchanges/GateIo/ExchangeGateIoAPI.cs b/src/ExchangeSharp/API/Exchanges/GateIo/ExchangeGateIoAPI.cs index 73051df0..c1c7c4c3 100644 --- a/src/ExchangeSharp/API/Exchanges/GateIo/ExchangeGateIoAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/GateIo/ExchangeGateIoAPI.cs @@ -376,12 +376,13 @@ private static ExchangeAPIOrderResult ParseExchangeAPIOrderResult(string status, } } - protected override async Task OnGetOrderDetailsAsync(string orderId, string symbol = null) + protected override async Task OnGetOrderDetailsAsync(string orderId, string symbol = null, bool isClientOrderId = false) { if (string.IsNullOrEmpty(symbol)) { throw new InvalidOperationException("MarketSymbol is required for querying order details with Gate.io API"); } + if (isClientOrderId) throw new NotImplementedException("Querying by client order ID is not implemented in ExchangeSharp. Please submit a PR if you are interested in this feature"); var payload = await GetNoncePayloadAsync(); var responseToken = await MakeJsonRequestAsync($"/spot/orders/{orderId}?currency_pair={symbol}", payload: payload); diff --git a/src/ExchangeSharp/API/Exchanges/Gemini/ExchangeGeminiAPI.cs b/src/ExchangeSharp/API/Exchanges/Gemini/ExchangeGeminiAPI.cs index b814caa8..fc681270 100644 --- a/src/ExchangeSharp/API/Exchanges/Gemini/ExchangeGeminiAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/Gemini/ExchangeGeminiAPI.cs @@ -320,7 +320,7 @@ protected override async Task OnPlaceOrderAsync(ExchangeOrd return ParseOrder(obj); } - protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null) + protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) { if (string.IsNullOrWhiteSpace(orderId)) { @@ -328,7 +328,9 @@ protected override async Task OnGetOrderDetailsAsync(string } object nonce = await GenerateNonceAsync(); - JToken result = await MakeJsonRequestAsync("/order/status", null, new Dictionary { { "nonce", nonce }, { "order_id", orderId } }); + var payload = new Dictionary { { "nonce", nonce }, + { isClientOrderId ? "client_order_id" : "order_id", orderId } }; // client_order_id cannot be used in combination with order_id + JToken result = await MakeJsonRequestAsync("/order/status", null, payload: payload); return ParseOrder(result); } diff --git a/src/ExchangeSharp/API/Exchanges/Hitbtc/ExchangeHitbtcAPI.cs b/src/ExchangeSharp/API/Exchanges/Hitbtc/ExchangeHitbtcAPI.cs index 43e69284..2887ddc6 100644 --- a/src/ExchangeSharp/API/Exchanges/Hitbtc/ExchangeHitbtcAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/Hitbtc/ExchangeHitbtcAPI.cs @@ -257,9 +257,10 @@ protected override async Task> OnGetAmountsAvailable /// /// /// - protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null) - { - JToken obj = await MakeJsonRequestAsync("/history/order/" + orderId + "/trades", null, await GetNoncePayloadAsync()); + protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) + { + if (isClientOrderId) throw new NotImplementedException("Querying by client order ID is not implemented in ExchangeSharp. Please submit a PR if you are interested in this feature"); + JToken obj = await MakeJsonRequestAsync("/history/order/" + orderId + "/trades", null, await GetNoncePayloadAsync()); if (obj != null && obj.HasValues) return ParseCompletedOrder(obj); return null; } diff --git a/src/ExchangeSharp/API/Exchanges/Huobi/ExchangeHuobiAPI.cs b/src/ExchangeSharp/API/Exchanges/Huobi/ExchangeHuobiAPI.cs index 8063429a..74a10dc1 100644 --- a/src/ExchangeSharp/API/Exchanges/Huobi/ExchangeHuobiAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/Huobi/ExchangeHuobiAPI.cs @@ -607,8 +607,8 @@ protected override async Task> OnGetAmountsAvailable return amounts; } - protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null) - { + protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) + { /* {{ "status": "ok", @@ -631,8 +631,14 @@ protected override async Task OnGetOrderDetailsAsync(string }} */ var payload = await GetNoncePayloadAsync(); - JToken data = await MakeJsonRequestAsync($"/order/orders/{orderId}", PrivateUrlV1, payload); - return ParseOrder(data); + JToken data; + if (isClientOrderId) + { + payload.Add("clientOrderId", orderId); + data = await MakeJsonRequestAsync($"/order/orders/getClientOrder", PrivateUrlV1, payload); + } + else data = await MakeJsonRequestAsync($"/order/orders/{orderId}", PrivateUrlV1, payload); + return ParseOrder(data); } protected override async Task> OnGetCompletedOrderDetailsAsync(string marketSymbol = null, DateTime? afterDate = null) @@ -644,8 +650,10 @@ protected override async Task> OnGetCompletedOr payload.Add("symbol", marketSymbol); payload.Add("states", "partial-canceled,filled,canceled"); if (afterDate != null) - { - payload.Add("start-date", afterDate.Value.ToString("yyyy-MM-dd")); + { // This endpoint returns the detail of one order by specified client order id (within 8 hours). + // The order created via API will no longer be queryable after being cancelled for more than 2 hours. + // It is suggested to cancel orders via GET /v1/order/orders/{order-id}, which is faster and more stable. + payload.Add("start-date", afterDate.Value.ToString("yyyy-MM-dd")); } JToken data = await MakeJsonRequestAsync("/order/orders", PrivateUrlV1, payload); foreach (var prop in data) diff --git a/src/ExchangeSharp/API/Exchanges/Kraken/ExchangeKrakenAPI.cs b/src/ExchangeSharp/API/Exchanges/Kraken/ExchangeKrakenAPI.cs index 022c53b2..d3c45ca6 100644 --- a/src/ExchangeSharp/API/Exchanges/Kraken/ExchangeKrakenAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/Kraken/ExchangeKrakenAPI.cs @@ -790,13 +790,13 @@ protected override async Task OnPlaceOrderAsync(ExchangeOrd return result; } - protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null) + protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) { if (string.IsNullOrWhiteSpace(orderId)) { return null; } - + if (isClientOrderId) throw new NotImplementedException("Querying by client order ID is not implemented 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 df74c8bb..ff6877c8 100644 --- a/src/ExchangeSharp/API/Exchanges/KuCoin/ExchangeKuCoinAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/KuCoin/ExchangeKuCoinAPI.cs @@ -374,18 +374,24 @@ protected override async Task> OnGetOpenOrderDe } /// - /// Kucoin does not support retrieving Orders by ID. This uses the GetCompletedOrderDetails and GetOpenOrderDetails filtered by orderId + /// Get Order by ID or ClientOrderId /// /// /// - protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null) - { - var orders = await GetCompletedOrderDetailsAsync(marketSymbol); - orders = orders.Concat(await GetOpenOrderDetailsAsync(marketSymbol)).ToList(); - - var ordertmp = orders?.Where(o => o.OrderId == orderId).FirstOrDefault(); - return ordertmp; - } + protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) + { + var payload = await GetNoncePayloadAsync(); + if (isClientOrderId) + payload["clientOid"] = Guid.NewGuid(); + else + payload["clientOid"] = Guid.NewGuid(); + + JToken token = await MakeJsonRequestAsync("/orders?&" + CryptoUtility.GetFormForPayload(payload, false), null, payload); + var isActive = token["id"].ToObject(); + if (isActive) + return ParseOpenOrder(token); + else return ParseCompletedOrder(token); + } protected override async Task OnPlaceOrderAsync(ExchangeOrderRequest order) { @@ -418,7 +424,7 @@ protected override async Task OnPlaceOrderAsync(ExchangeOrd protected override async Task OnCancelOrderAsync(string orderId, string marketSymbol = null) { // Find order detail - ExchangeOrderResult order = await GetOrderDetailsAsync(orderId, marketSymbol); + ExchangeOrderResult order = await GetOrderDetailsAsync(orderId, marketSymbol: marketSymbol); // There is no order to be cancelled if (order == null) diff --git a/src/ExchangeSharp/API/Exchanges/LBank/ExchangeLBankAPI.cs b/src/ExchangeSharp/API/Exchanges/LBank/ExchangeLBankAPI.cs index c0f3b70f..361a46f3 100644 --- a/src/ExchangeSharp/API/Exchanges/LBank/ExchangeLBankAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/LBank/ExchangeLBankAPI.cs @@ -356,8 +356,9 @@ protected override async Task OnCancelOrderAsync(string orderId, string symbol = } //GetOrderDetails 13 - protected override async Task OnGetOrderDetailsAsync(string orderId, string symbol = null) + protected override async Task OnGetOrderDetailsAsync(string orderId, string symbol = null, bool isClientOrderId = false) { + if (isClientOrderId) throw new NotImplementedException("Querying by client order ID is not implemented 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 b8d349b4..e8709eb2 100644 --- a/src/ExchangeSharp/API/Exchanges/Livecoin/ExchangeLivecoinAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/Livecoin/ExchangeLivecoinAPI.cs @@ -219,8 +219,9 @@ protected override async Task> OnGetAmountsAvailable return amounts; } - protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null) - { + protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) + { + if (isClientOrderId) throw new NotImplementedException("Querying by client order ID is not implemented in ExchangeSharp. Please submit a PR if you are interested in this feature"); JToken token = await MakeJsonRequestAsync("/exchange/order?orderId=" + orderId, null, await GetNoncePayloadAsync()); return ParseOrder(token); } diff --git a/src/ExchangeSharp/API/Exchanges/NDAX/ExchangeNDAXAPI.cs b/src/ExchangeSharp/API/Exchanges/NDAX/ExchangeNDAXAPI.cs index 37afaa42..c0fc332d 100644 --- a/src/ExchangeSharp/API/Exchanges/NDAX/ExchangeNDAXAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/NDAX/ExchangeNDAXAPI.cs @@ -197,9 +197,10 @@ protected override async Task OnPlaceOrdersAsync(params E return resp.ToArray(); } - protected override async Task OnGetOrderDetailsAsync(string orderId, string symbol = null) - { - await EnsureInstrumentIdsAvailable(); + protected override async Task OnGetOrderDetailsAsync(string orderId, string symbol = null, bool isClientOrderId = false) + { + if (isClientOrderId) throw new NotImplementedException("Querying by client order ID is not implemented in ExchangeSharp. Please submit a PR if you are interested in this feature"); + await EnsureInstrumentIdsAvailable(); var result = await MakeJsonRequestAsync("GetOrderStatus", null, new Dictionary() { diff --git a/src/ExchangeSharp/API/Exchanges/OKGroup/OKGroupCommon.cs b/src/ExchangeSharp/API/Exchanges/OKGroup/OKGroupCommon.cs index af900f42..7046586f 100644 --- a/src/ExchangeSharp/API/Exchanges/OKGroup/OKGroupCommon.cs +++ b/src/ExchangeSharp/API/Exchanges/OKGroup/OKGroupCommon.cs @@ -461,8 +461,8 @@ protected override async Task OnCancelOrderAsync(string orderId, string marketSy await MakeJsonRequestAsync("/cancel_order.do", BaseUrl, payload, "POST"); } - protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null) - { + protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) + { List orders = new List(); Dictionary payload = await GetNoncePayloadAsync(); if (marketSymbol.Length == 0) @@ -470,8 +470,13 @@ protected override async Task OnGetOrderDetailsAsync(string throw new InvalidOperationException("Okex single order details request requires symbol"); } payload["symbol"] = marketSymbol; - payload["order_id"] = orderId; - JToken token = await MakeJsonRequestAsync("/order_info.do", BaseUrl, payload, "POST"); + + if (isClientOrderId) // Either client_oid or order_id must be present. + payload["client_oid"] = orderId; + else + payload["order_id"] = orderId; + + JToken token = await MakeJsonRequestAsync("/order_info.do", BaseUrl, payload, "POST"); foreach (JToken order in token["orders"]) { orders.Add(ParseOrder(order)); diff --git a/src/ExchangeSharp/API/Exchanges/Poloniex/ExchangePoloniexAPI.cs b/src/ExchangeSharp/API/Exchanges/Poloniex/ExchangePoloniexAPI.cs index a7e1178b..14fbfbf6 100644 --- a/src/ExchangeSharp/API/Exchanges/Poloniex/ExchangePoloniexAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/Poloniex/ExchangePoloniexAPI.cs @@ -840,9 +840,10 @@ protected override async Task> OnGetOpenOrderDe return orders; } - protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null) - { - JToken resultArray = await MakePrivateAPIRequestAsync("returnOrderTrades", new object[] { "orderNumber", orderId }); + protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) + { + if (isClientOrderId) throw new NotImplementedException("Querying by client order ID is not implemented in ExchangeSharp. Please submit a PR if you are interested in this feature"); + JToken resultArray = await MakePrivateAPIRequestAsync("returnOrderTrades", new object[] { "orderNumber", orderId }); string tickerSymbol = resultArray[0]["currencyPair"].ToStringInvariant(); List orders = new List(); ParseCompletedOrderDetails(orders, resultArray, tickerSymbol); diff --git a/src/ExchangeSharp/API/Exchanges/Yobit/ExchangeYobitAPI.cs b/src/ExchangeSharp/API/Exchanges/Yobit/ExchangeYobitAPI.cs index 1c7c87b0..fe467e03 100644 --- a/src/ExchangeSharp/API/Exchanges/Yobit/ExchangeYobitAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/Yobit/ExchangeYobitAPI.cs @@ -202,9 +202,10 @@ protected override async Task> OnGetAmountsAvailable return amounts; } - protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null) - { - var payload = await GetNoncePayloadAsync(); + protected override async Task OnGetOrderDetailsAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false) + { + if (isClientOrderId) throw new NotImplementedException("Querying by client order ID is not implemented in ExchangeSharp. Please submit a PR if you are interested in this feature"); + var payload = await GetNoncePayloadAsync(); payload.Add("method", "getInfo"); payload.Add("order_id", orderId); JToken token = await MakeJsonRequestAsync("/", PrivateURL, payload, "POST"); diff --git a/src/ExchangeSharp/API/Exchanges/_Base/ExchangeAPI.cs b/src/ExchangeSharp/API/Exchanges/_Base/ExchangeAPI.cs index 0ef9d84b..c58d11d3 100644 --- a/src/ExchangeSharp/API/Exchanges/_Base/ExchangeAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/_Base/ExchangeAPI.cs @@ -203,7 +203,7 @@ protected virtual Task OnPlaceOrderAsync(ExchangeOrderReque throw new NotImplementedException(); protected virtual Task OnPlaceOrdersAsync(params ExchangeOrderRequest[] order) => throw new NotImplementedException(); - protected virtual Task OnGetOrderDetailsAsync(string orderId, string? marketSymbol = null) => + protected virtual Task OnGetOrderDetailsAsync(string orderId, string? marketSymbol = null, bool isClientOrderId = false) => throw new NotImplementedException(); protected virtual Task> OnGetOpenOrderDetailsAsync(string? marketSymbol = null) => throw new NotImplementedException(); @@ -936,11 +936,12 @@ public virtual async Task PlaceOrdersAsync(params Exchang /// /// Order id to get details for /// Symbol of order (most exchanges do not require this) + /// /// Order details - public virtual async Task GetOrderDetailsAsync(string orderId, string? marketSymbol = null) + public virtual async Task GetOrderDetailsAsync(string orderId, string? marketSymbol = null, bool isClientOrderId = false) { marketSymbol = NormalizeMarketSymbol(marketSymbol); - return await Cache.CacheMethod(MethodCachePolicy, async() => await OnGetOrderDetailsAsync(orderId, marketSymbol), nameof(GetOrderDetailsAsync), nameof(orderId), orderId, nameof(marketSymbol), marketSymbol); + return await Cache.CacheMethod(MethodCachePolicy, async() => await OnGetOrderDetailsAsync(orderId, marketSymbol: marketSymbol, isClientOrderId: isClientOrderId), nameof(GetOrderDetailsAsync), nameof(orderId), orderId, nameof(isClientOrderId), isClientOrderId, nameof(marketSymbol), marketSymbol); } /// diff --git a/src/ExchangeSharp/API/Exchanges/_Base/ExchangeAPIExtensions.cs b/src/ExchangeSharp/API/Exchanges/_Base/ExchangeAPIExtensions.cs index e9f37155..07b9fd80 100644 --- a/src/ExchangeSharp/API/Exchanges/_Base/ExchangeAPIExtensions.cs +++ b/src/ExchangeSharp/API/Exchanges/_Base/ExchangeAPIExtensions.cs @@ -327,7 +327,7 @@ public static async Task PlaceSafeMarketOrderAsync(this Exc for (; i < maxTries; i++) { await System.Threading.Tasks.Task.Delay(500); - result = await api.GetOrderDetailsAsync(result.OrderId, symbol); + result = await api.GetOrderDetailsAsync(result.OrderId, marketSymbol: symbol); switch (result.Result) { case ExchangeAPIOrderResult.Filled: diff --git a/src/ExchangeSharp/API/Exchanges/_Base/IExchangeAPI.cs b/src/ExchangeSharp/API/Exchanges/_Base/IExchangeAPI.cs index 58cb7f5f..3931cddf 100644 --- a/src/ExchangeSharp/API/Exchanges/_Base/IExchangeAPI.cs +++ b/src/ExchangeSharp/API/Exchanges/_Base/IExchangeAPI.cs @@ -207,8 +207,9 @@ public interface IExchangeAPI : IDisposable, IBaseAPI, IOrderBookProvider /// /// order id /// Market Symbol + /// /// Order details - Task GetOrderDetailsAsync(string orderId, string? marketSymbol = null); + Task GetOrderDetailsAsync(string orderId, string? marketSymbol = null, bool isClientOrderId = false); /// /// Get the details of all open orders diff --git a/src/ExchangeSharpConsole/Options/BuyOption.cs b/src/ExchangeSharpConsole/Options/BuyOption.cs index 7de49919..08f54a04 100644 --- a/src/ExchangeSharpConsole/Options/BuyOption.cs +++ b/src/ExchangeSharpConsole/Options/BuyOption.cs @@ -54,7 +54,7 @@ private async Task WaitForOrder(ExchangeOrderResult order, IExchangeAPI api) await Task.Delay(IntervalMs) .ConfigureAwait(false); - order = await api.GetOrderDetailsAsync(order.OrderId, order.MarketSymbol); + order = await api.GetOrderDetailsAsync(order.OrderId, marketSymbol: order.MarketSymbol); } Console.Clear(); diff --git a/src/ExchangeSharpConsole/Options/OrderDetailsOption.cs b/src/ExchangeSharpConsole/Options/OrderDetailsOption.cs index 86963f69..e4ffb611 100644 --- a/src/ExchangeSharpConsole/Options/OrderDetailsOption.cs +++ b/src/ExchangeSharpConsole/Options/OrderDetailsOption.cs @@ -14,7 +14,7 @@ public override async Task RunCommand() Authenticate(api); - var orderDetails = await api.GetOrderDetailsAsync(OrderId, MarketSymbol); + var orderDetails = await api.GetOrderDetailsAsync(OrderId, marketSymbol: MarketSymbol); Console.WriteLine(orderDetails); WaitInteractively(); diff --git a/tests/ExchangeSharpTests/ExchangeBitBankTests.cs b/tests/ExchangeSharpTests/ExchangeBitBankTests.cs index 49798f87..2b51ae7d 100644 --- a/tests/ExchangeSharpTests/ExchangeBitBankTests.cs +++ b/tests/ExchangeSharpTests/ExchangeBitBankTests.cs @@ -189,7 +189,7 @@ public async Task ShouldGetOrderDetail() "; var api = MakeMockRequestMaker(data); // Throws error when no Market Symbol - var resp = await api.GetOrderDetailsAsync("558167000", "BTC-JPY"); + var resp = await api.GetOrderDetailsAsync("558167000", marketSymbol: "BTC-JPY"); ExchangeOrderResult resp2 = await api.GetOrderDetailsAsync("58037954"); resp.Should().BeEquivalentTo(resp2); }