Skip to content

Commit

Permalink
FTX: order cancellation improvement (thrasher-corp#727)
Browse files Browse the repository at this point in the history
* exchanges/request: Requester.doRequest() now always parses returned response body into JSON even in the case of an artificial error after the request itself

* exchanges/ftx: consider order cancellation successful under two new conditions, reported by the exchange: (1) order is already closed or (2) order is already queued for cancellation

* exchanges/ftx: fix a typo in a comment

* exchanges/request: keep the same behavior of doRequest() when there is an unmarshaling error

* exchanges/ftx: FTX.DeleteOrderByClientID now also reports no errors when requesting the cancellation of orders that are already canceled on the exchange

* exchanges/ftx: order deletion methods are now unified

* exchanges/ftx: DeleteOrder* methods now check if the given ID is not empty
  • Loading branch information
ydm authored Jul 31, 2021
1 parent bf5a24b commit 3b1fe81
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 33 deletions.
51 changes: 22 additions & 29 deletions exchanges/ftx/ftx.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ const (
)

var (
errInvalidOrderID = errors.New("invalid order ID")
errStartTimeCannotBeAfterEndTime = errors.New("start timestamp cannot be after end timestamp")
errSubaccountNameMustBeSpecified = errors.New("a subaccount name must be specified")
errSubaccountUpdateNameInvalid = errors.New("invalid subaccount old/new name")
Expand Down Expand Up @@ -776,51 +777,43 @@ func (f *FTX) GetOrderStatusByClientID(clientOrderID string) (OrderData, error)
return resp.Data, f.SendAuthHTTPRequest(exchange.RestSpot, http.MethodGet, getOrderStatusByClientID+clientOrderID, nil, &resp)
}

// DeleteOrder deletes an order
func (f *FTX) DeleteOrder(orderID string) (string, error) {
func (f *FTX) deleteOrderByPath(path string) (string, error) {
resp := struct {
Result string `json:"result"`
Success bool `json:"success"`
Error string `json:"error"`
}{}
if err := f.SendAuthHTTPRequest(exchange.RestSpot, http.MethodDelete, deleteOrder+orderID, nil, &resp); err != nil {
return "", err
err := f.SendAuthHTTPRequest(exchange.RestSpot, http.MethodDelete, path, nil, &resp)
// If there is an error reported, but the resp struct reports one of a very few
// specific error causes, we still consider this a successful cancellation.
if err != nil && !resp.Success && (resp.Error == "Order already closed" || resp.Error == "Order already queued for cancellation") {
return resp.Error, nil
}
if !resp.Success {
return resp.Result, errors.New("delete order request by ID unsuccessful")
return resp.Result, err
}

// DeleteOrder deletes an order
func (f *FTX) DeleteOrder(orderID string) (string, error) {
if orderID == "" {
return "", errInvalidOrderID
}
return resp.Result, nil
return f.deleteOrderByPath(deleteOrder + orderID)
}

// DeleteOrderByClientID deletes an order
func (f *FTX) DeleteOrderByClientID(clientID string) (string, error) {
resp := struct {
Result string `json:"result"`
Success bool `json:"success"`
}{}

if err := f.SendAuthHTTPRequest(exchange.RestSpot, http.MethodDelete, deleteOrderByClientID+clientID, nil, &resp); err != nil {
return "", err
}
if !resp.Success {
return resp.Result, errors.New("delete order request by client ID unsuccessful")
if clientID == "" {
return "", errInvalidOrderID
}
return resp.Result, nil
return f.deleteOrderByPath(deleteOrderByClientID + clientID)
}

// DeleteTriggerOrder deletes an order
func (f *FTX) DeleteTriggerOrder(orderID string) (string, error) {
resp := struct {
Result string `json:"result"`
Success bool `json:"success"`
}{}

if err := f.SendAuthHTTPRequest(exchange.RestSpot, http.MethodDelete, cancelTriggerOrder+orderID, nil, &resp); err != nil {
return "", err
}
if !resp.Success {
return resp.Result, errors.New("delete trigger order request unsuccessful")
if orderID == "" {
return "", errInvalidOrderID
}
return resp.Result, nil
return f.deleteOrderByPath(cancelTriggerOrder + orderID)
}

// GetFills gets fills' data
Expand Down
11 changes: 7 additions & 4 deletions exchanges/request/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,12 @@ func (r *Requester) doRequest(req *http.Request, p *Item) error {
if err != nil {
return err
}
// Even in the case of an erroneous condition below, yield the parsed
// response to caller.
var unmarshallError error
if p.Result != nil {
unmarshallError = json.Unmarshal(contents, p.Result)
}

if p.HTTPRecording {
// This dumps http responses for future mocking implementations
Expand Down Expand Up @@ -242,10 +248,7 @@ func (r *Requester) doRequest(req *http.Request, p *Item) error {
string(contents))
}
}
if p.Result != nil {
return json.Unmarshal(contents, p.Result)
}
return nil
return unmarshallError
}
}

Expand Down

0 comments on commit 3b1fe81

Please sign in to comment.