Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added ability to GetOrderDetailsAsync() by ClientOrderId #647

Merged
merged 2 commits into from
Sep 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -194,12 +194,13 @@ protected override async Task<ExchangeOrderResult> OnPlaceOrderAsync(ExchangeOrd
return orderDetails;
}

protected override async Task<ExchangeOrderResult> OnGetOrderDetailsAsync(string orderId, string marketSymbol = null)
protected override async Task<ExchangeOrderResult> 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<JToken>($"/trades/v1/order?orderId={orderId}", null, payload, "GET");
bool isBuy = result["tradeSide"].ToStringInvariant() == "buy" ? true : false;
Expand Down
5 changes: 3 additions & 2 deletions src/ExchangeSharp/API/Exchanges/BL3P/ExchangeBL3PAPI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ protected override async Task<ExchangeOrderResult> OnPlaceOrderAsync(ExchangeOrd
var result = JsonConvert.DeserializeObject<BL3POrderAddResponse>(resultBody)
.Except();

var orderDetails = await GetOrderDetailsAsync(result.OrderId, order.MarketSymbol);
var orderDetails = await GetOrderDetailsAsync(result.OrderId, marketSymbol: order.MarketSymbol);

return orderDetails;
}
Expand Down Expand Up @@ -308,10 +308,11 @@ protected override async Task OnCancelOrderAsync(string orderId, string marketSy
.Except();
}

protected override async Task<ExchangeOrderResult> OnGetOrderDetailsAsync(string orderId, string marketSymbol = null)
protected override async Task<ExchangeOrderResult> 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<string, object>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -580,15 +580,20 @@ protected override async Task<ExchangeOrderResult> OnPlaceOrderAsync(ExchangeOrd
return ParseOrder(token);
}

protected override async Task<ExchangeOrderResult> OnGetOrderDetailsAsync(string orderId, string? marketSymbol = null)
protected override async Task<ExchangeOrderResult> OnGetOrderDetailsAsync(string orderId, string? marketSymbol = null, bool isClientOrderId = false)
{
Dictionary<string, object> payload = await GetNoncePayloadAsync();
if (string.IsNullOrWhiteSpace(marketSymbol))
{
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<JToken>("/order", BaseUrlPrivate, payload);
ExchangeOrderResult result = ParseOrder(token);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,9 @@ protected override async Task OnCancelOrderAsync(string orderId, string marketSy
await MakeJsonRequestAsync<JToken>("/user/spot/cancel_order", baseUrl: BaseUrlPrivate, payload: payload, requestMethod: "POST");
}

protected override async Task<ExchangeOrderResult> OnGetOrderDetailsAsync(string orderId, string marketSymbol = null)
protected override async Task<ExchangeOrderResult> 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)
Expand Down
4 changes: 2 additions & 2 deletions src/ExchangeSharp/API/Exchanges/BitMEX/ExchangeBitMEXAPI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -600,11 +600,11 @@ protected override async Task<IEnumerable<ExchangeOrderResult>> OnGetOpenOrderDe
return orders;
}

protected override async Task<ExchangeOrderResult> OnGetOrderDetailsAsync(string orderId, string marketSymbol = null)
protected override async Task<ExchangeOrderResult> OnGetOrderDetailsAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false)
{
List<ExchangeOrderResult> orders = new List<ExchangeOrderResult>();
Dictionary<string, object> payload = await GetNoncePayloadAsync();
string query = $"/order?filter={{\"orderID\": \"{orderId}\"}}";
string query = $"/order?filter={{\"{(isClientOrderId ? "clOrdID" : "orderID")}\": \"{orderId}\"}}";
JToken token = await MakeJsonRequestAsync<JToken>(query, BaseUrl, payload, "GET");
foreach (JToken order in token)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -493,8 +493,9 @@ protected override async Task<ExchangeOrderResult> OnPlaceOrderAsync(ExchangeOrd
return ParseOrder(obj);
}

protected override async Task<ExchangeOrderResult> OnGetOrderDetailsAsync(string orderId, string marketSymbol = null)
protected override async Task<ExchangeOrderResult> 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;
Expand Down
11 changes: 7 additions & 4 deletions src/ExchangeSharp/API/Exchanges/Bitstamp/ExchangeBitstampAPI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -219,8 +219,8 @@ protected override async Task<ExchangeOrderResult> OnPlaceOrderAsync(ExchangeOrd
};
}

protected override async Task<ExchangeOrderResult> OnGetOrderDetailsAsync(string orderId, string marketSymbol = null)
{
protected override async Task<ExchangeOrderResult> OnGetOrderDetailsAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false)
{
//{
// "status": "Finished",
// "id": 1022694747,
Expand All @@ -241,8 +241,11 @@ protected override async Task<ExchangeOrderResult> OnGetOrderDetailsAsync(string
}
string url = "/order_status/";
Dictionary<string, object> payload = await GetNoncePayloadAsync();
payload["id"] = orderId;
JObject result = await MakeJsonRequestAsync<JObject>(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<JObject>(url, null, payload, "POST");

var transactions = result["transactions"] as JArray;
var anyTransaction = transactions.Any();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -412,8 +412,9 @@ protected override async Task<ExchangeOrderResult> OnPlaceOrderAsync(ExchangeOrd
}


protected override async Task<ExchangeOrderResult> OnGetOrderDetailsAsync(string orderId, string marketSymbol = null)
protected override async Task<ExchangeOrderResult> 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;
Expand Down
13 changes: 8 additions & 5 deletions src/ExchangeSharp/API/Exchanges/Bybit/ExchangeBybitAPI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -718,13 +718,16 @@ public async Task<ExchangeFunding> GetPredictedFundingRateAsync(string marketSym
return funding;
}

private async Task<IEnumerable<ExchangeOrderResult>> DoGetOrderDetailsAsync(string orderId, string marketSymbol = null)
private async Task<IEnumerable<ExchangeOrderResult>> DoGetOrderDetailsAsync(string orderId, bool isClientOrderId = false, string marketSymbol = null)
{
var extraParams = new Dictionary<string, object>();

if (orderId != null)
{
extraParams["order_id"] = orderId;
if (isClientOrderId)
extraParams["order_link_id"] = orderId;
else
extraParams["order_id"] = orderId;
}

if (!string.IsNullOrWhiteSpace(marketSymbol))
Expand Down Expand Up @@ -758,13 +761,13 @@ private async Task<IEnumerable<ExchangeOrderResult>> 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<IEnumerable<ExchangeOrderResult>> 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<ExchangeOrderResult> OnGetOrderDetailsAsync(string orderId, string marketSymbol = null)
protected override async Task<ExchangeOrderResult> 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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -594,9 +594,10 @@ protected override async Task<ExchangeOrderResult> OnPlaceOrderAsync(ExchangeOrd
return ParseOrder(result);
}

protected override async Task<ExchangeOrderResult> OnGetOrderDetailsAsync(string orderId, string marketSymbol = null)
{
JToken obj = await MakeJsonRequestAsync<JToken>("/orders/" + orderId, null, await GetNoncePayloadAsync(), "GET");
protected override async Task<ExchangeOrderResult> 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<JToken>("/orders/" + (isClientOrderId ? "client:" : "") + orderId,
null, await GetNoncePayloadAsync(), "GET");
return ParseOrder(obj);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -361,8 +361,9 @@ protected override async Task<IEnumerable<ExchangeOrderResult>> OnGetCompletedOr
});
}

protected override async Task<ExchangeOrderResult> OnGetOrderDetailsAsync(string orderId, string marketSymbol = null)
protected override async Task<ExchangeOrderResult> 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<string, object> payload = await GetNoncePayloadAsync();
JToken token = await MakeJsonRequestAsync<JToken>($"/spot/order?order_id={orderId}", payload: payload);
var x = token["data"];
Expand Down
3 changes: 2 additions & 1 deletion src/ExchangeSharp/API/Exchanges/GateIo/ExchangeGateIoAPI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -376,12 +376,13 @@ private static ExchangeAPIOrderResult ParseExchangeAPIOrderResult(string status,
}
}

protected override async Task<ExchangeOrderResult> OnGetOrderDetailsAsync(string orderId, string symbol = null)
protected override async Task<ExchangeOrderResult> 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<JToken>($"/spot/orders/{orderId}?currency_pair={symbol}", payload: payload);
Expand Down
6 changes: 4 additions & 2 deletions src/ExchangeSharp/API/Exchanges/Gemini/ExchangeGeminiAPI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -320,15 +320,17 @@ protected override async Task<ExchangeOrderResult> OnPlaceOrderAsync(ExchangeOrd
return ParseOrder(obj);
}

protected override async Task<ExchangeOrderResult> OnGetOrderDetailsAsync(string orderId, string marketSymbol = null)
protected override async Task<ExchangeOrderResult> OnGetOrderDetailsAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false)
{
if (string.IsNullOrWhiteSpace(orderId))
{
return null;
}

object nonce = await GenerateNonceAsync();
JToken result = await MakeJsonRequestAsync<JToken>("/order/status", null, new Dictionary<string, object> { { "nonce", nonce }, { "order_id", orderId } });
var payload = new Dictionary<string, object> { { "nonce", nonce },
{ isClientOrderId ? "client_order_id" : "order_id", orderId } }; // client_order_id cannot be used in combination with order_id
JToken result = await MakeJsonRequestAsync<JToken>("/order/status", null, payload: payload);
return ParseOrder(result);
}

Expand Down
7 changes: 4 additions & 3 deletions src/ExchangeSharp/API/Exchanges/Hitbtc/ExchangeHitbtcAPI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -257,9 +257,10 @@ protected override async Task<Dictionary<string, decimal>> OnGetAmountsAvailable
/// </summary>
/// <param name="orderId"></param>
/// <returns></returns>
protected override async Task<ExchangeOrderResult> OnGetOrderDetailsAsync(string orderId, string marketSymbol = null)
{
JToken obj = await MakeJsonRequestAsync<JToken>("/history/order/" + orderId + "/trades", null, await GetNoncePayloadAsync());
protected override async Task<ExchangeOrderResult> 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<JToken>("/history/order/" + orderId + "/trades", null, await GetNoncePayloadAsync());
if (obj != null && obj.HasValues) return ParseCompletedOrder(obj);
return null;
}
Expand Down
20 changes: 14 additions & 6 deletions src/ExchangeSharp/API/Exchanges/Huobi/ExchangeHuobiAPI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -607,8 +607,8 @@ protected override async Task<Dictionary<string, decimal>> OnGetAmountsAvailable
return amounts;
}

protected override async Task<ExchangeOrderResult> OnGetOrderDetailsAsync(string orderId, string marketSymbol = null)
{
protected override async Task<ExchangeOrderResult> OnGetOrderDetailsAsync(string orderId, string marketSymbol = null, bool isClientOrderId = false)
{
/*
{{
"status": "ok",
Expand All @@ -631,8 +631,14 @@ protected override async Task<ExchangeOrderResult> OnGetOrderDetailsAsync(string
}}
*/
var payload = await GetNoncePayloadAsync();
JToken data = await MakeJsonRequestAsync<JToken>($"/order/orders/{orderId}", PrivateUrlV1, payload);
return ParseOrder(data);
JToken data;
if (isClientOrderId)
{
payload.Add("clientOrderId", orderId);
data = await MakeJsonRequestAsync<JToken>($"/order/orders/getClientOrder", PrivateUrlV1, payload);
}
else data = await MakeJsonRequestAsync<JToken>($"/order/orders/{orderId}", PrivateUrlV1, payload);
return ParseOrder(data);
}

protected override async Task<IEnumerable<ExchangeOrderResult>> OnGetCompletedOrderDetailsAsync(string marketSymbol = null, DateTime? afterDate = null)
Expand All @@ -644,8 +650,10 @@ protected override async Task<IEnumerable<ExchangeOrderResult>> 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<JToken>("/order/orders", PrivateUrlV1, payload);
foreach (var prop in data)
Expand Down
4 changes: 2 additions & 2 deletions src/ExchangeSharp/API/Exchanges/Kraken/ExchangeKrakenAPI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -790,13 +790,13 @@ protected override async Task<ExchangeOrderResult> OnPlaceOrderAsync(ExchangeOrd
return result;
}

protected override async Task<ExchangeOrderResult> OnGetOrderDetailsAsync(string orderId, string marketSymbol = null)
protected override async Task<ExchangeOrderResult> 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<string, object> payload = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase)
{ { "txid", orderId }, { "nonce", nonce }
Expand Down
26 changes: 16 additions & 10 deletions src/ExchangeSharp/API/Exchanges/KuCoin/ExchangeKuCoinAPI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -374,18 +374,24 @@ protected override async Task<IEnumerable<ExchangeOrderResult>> OnGetOpenOrderDe
}

/// <summary>
/// Kucoin does not support retrieving Orders by ID. This uses the GetCompletedOrderDetails and GetOpenOrderDetails filtered by orderId
/// Get Order by ID or ClientOrderId
/// </summary>
/// <param name="orderId"></param>
/// <returns></returns>
protected override async Task<ExchangeOrderResult> 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<ExchangeOrderResult> 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<JToken>("/orders?&" + CryptoUtility.GetFormForPayload(payload, false), null, payload);
var isActive = token["id"].ToObject<bool>();
if (isActive)
return ParseOpenOrder(token);
else return ParseCompletedOrder(token);
}

protected override async Task<ExchangeOrderResult> OnPlaceOrderAsync(ExchangeOrderRequest order)
{
Expand Down Expand Up @@ -418,7 +424,7 @@ protected override async Task<ExchangeOrderResult> 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)
Expand Down
3 changes: 2 additions & 1 deletion src/ExchangeSharp/API/Exchanges/LBank/ExchangeLBankAPI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -356,8 +356,9 @@ protected override async Task OnCancelOrderAsync(string orderId, string symbol =
}

//GetOrderDetails 13
protected override async Task<ExchangeOrderResult> OnGetOrderDetailsAsync(string orderId, string symbol = null)
protected override async Task<ExchangeOrderResult> 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<string, object> payload = new Dictionary<string, object>
{
{ "api_key", PublicApiKey.ToUnsecureString() },
Expand Down
Loading