Skip to content

Commit

Permalink
orders: Add method for creating cancel struct from order details (thr…
Browse files Browse the repository at this point in the history
…asher-corp#947)

* orders: Add method for creating cancel struct from order details

* orders: remove uneeded fields

* glorious: nit
  • Loading branch information
shazbert authored May 19, 2022
1 parent 14cde7b commit c492e66
Show file tree
Hide file tree
Showing 8 changed files with 81 additions and 35 deletions.
33 changes: 13 additions & 20 deletions engine/order_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,36 +116,29 @@ func (m *OrderManager) run() {
}

// CancelAllOrders iterates and cancels all orders for each exchange provided
func (m *OrderManager) CancelAllOrders(ctx context.Context, exchangeNames []exchange.IBotExchange) {
func (m *OrderManager) CancelAllOrders(ctx context.Context, exchanges []exchange.IBotExchange) {
if m == nil || atomic.LoadInt32(&m.started) == 0 {
return
}

orders := m.orderStore.get()
if orders == nil {
allOrders := m.orderStore.get()
if len(allOrders) == 0 {
return
}

for i := range exchangeNames {
exchangeOrders, ok := orders[strings.ToLower(exchangeNames[i].GetName())]
for i := range exchanges {
orders, ok := allOrders[strings.ToLower(exchanges[i].GetName())]
if !ok {
continue
}
for j := range exchangeOrders {
log.Debugf(log.OrderMgr,
"Order manager: Cancelling order(s) for exchange %s.",
exchangeNames[i].GetName())
err := m.Cancel(ctx, &order.Cancel{
Exchange: exchangeOrders[j].Exchange,
ID: exchangeOrders[j].ID,
AccountID: exchangeOrders[j].AccountID,
ClientID: exchangeOrders[j].ClientID,
WalletAddress: exchangeOrders[j].WalletAddress,
Type: exchangeOrders[j].Type,
Side: exchangeOrders[j].Side,
Pair: exchangeOrders[j].Pair,
AssetType: exchangeOrders[j].AssetType,
})
for j := range orders {
log.Debugf(log.OrderMgr, "Order manager: Cancelling order(s) for exchange %s.", exchanges[i].GetName())
cancel, err := orders[j].DeriveCancel()
if err != nil {
log.Error(log.OrderMgr, err)
continue
}
err = m.Cancel(ctx, cancel)
if err != nil {
log.Error(log.OrderMgr, err)
}
Expand Down
3 changes: 0 additions & 3 deletions engine/order_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ type omfExchange struct {
// CancelOrder overrides testExchange's cancel order function
// to do the bare minimum required with no API calls or credentials required
func (f omfExchange) CancelOrder(ctx context.Context, o *order.Cancel) error {
o.Status = order.Cancelled
return nil
}

Expand Down Expand Up @@ -414,9 +413,7 @@ func TestCancelOrder(t *testing.T) {
Exchange: testExchange,
ID: "1337",
Side: order.Sell,
Status: order.New,
AssetType: asset.Spot,
Date: time.Now(),
Pair: pair,
}
err = m.Cancel(context.Background(), cancel)
Expand Down
7 changes: 4 additions & 3 deletions exchanges/huobi/huobi_futures.go
Original file line number Diff line number Diff line change
Expand Up @@ -782,12 +782,13 @@ func (h *HUOBI) FPlaceBatchOrder(ctx context.Context, data []fBatchOrderData) (F
}

// FCancelOrder cancels a futures order
func (h *HUOBI) FCancelOrder(ctx context.Context, symbol, orderID, clientOrderID string) (FCancelOrderData, error) {
func (h *HUOBI) FCancelOrder(ctx context.Context, baseCurrency currency.Code, orderID, clientOrderID string) (FCancelOrderData, error) {
var resp FCancelOrderData
req := make(map[string]interface{})
if symbol != "" {
req["symbol"] = symbol
if baseCurrency.IsEmpty() {
return resp, fmt.Errorf("cannot cancel futures order %w", currency.ErrCurrencyCodeEmpty)
}
req["symbol"] = baseCurrency.String() // Upper and lower case are supported
if orderID != "" {
req["order_id"] = orderID
}
Expand Down
5 changes: 3 additions & 2 deletions exchanges/huobi/huobi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -505,11 +505,12 @@ func TestFPlaceBatchOrder(t *testing.T) {
}

func TestFCancelOrder(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() || !canManipulateRealOrders {
t.Skip("skipping test: api keys not set or canManipulateRealOrders set to false")
}
t.Parallel()
_, err := h.FCancelOrder(context.Background(), "BTC", "123", "")

_, err := h.FCancelOrder(context.Background(), currency.BTC, "123", "")
if err != nil {
t.Error(err)
}
Expand Down
2 changes: 1 addition & 1 deletion exchanges/huobi/huobi_wrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -1020,7 +1020,7 @@ func (h *HUOBI) CancelOrder(ctx context.Context, o *order.Cancel) error {
case asset.CoinMarginedFutures:
_, err = h.CancelSwapOrder(ctx, o.ID, o.ClientID, o.Pair)
case asset.Futures:
_, err = h.FCancelOrder(ctx, o.Symbol, o.ClientID, o.ClientOrderID)
_, err = h.FCancelOrder(ctx, o.Pair.Base, o.ClientID, o.ClientOrderID)
default:
return fmt.Errorf("%v assetType not supported", o.AssetType)
}
Expand Down
40 changes: 40 additions & 0 deletions exchanges/order/order_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1634,3 +1634,43 @@ func TestDetail_CopyPointerOrderSlice(t *testing.T) {
}
}
}

func TestDeriveCancel(t *testing.T) {
t.Parallel()
var o *Detail
if _, err := o.DeriveCancel(); !errors.Is(err, errOrderDetailIsNil) {
t.Fatalf("received: '%v' but expected: '%v'", err, errOrderDetailIsNil)
}

pair := currency.NewPair(currency.BTC, currency.AUD)

o = &Detail{
Exchange: "wow",
ID: "wow1",
AccountID: "wow2",
ClientID: "wow3",
ClientOrderID: "wow4",
WalletAddress: "wow5",
Type: Market,
Side: Long,
Pair: pair,
AssetType: asset.Futures,
}
cancel, err := o.DeriveCancel()
if !errors.Is(err, nil) {
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
}

if cancel.Exchange != "wow" ||
cancel.ID != "wow1" ||
cancel.AccountID != "wow2" ||
cancel.ClientID != "wow3" ||
cancel.ClientOrderID != "wow4" ||
cancel.WalletAddress != "wow5" ||
cancel.Type != Market ||
cancel.Side != Long ||
!cancel.Pair.Equal(pair) ||
cancel.AssetType != asset.Futures {
t.Fatal("unexpected values")
}
}
6 changes: 0 additions & 6 deletions exchanges/order/order_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,6 @@ type Filter struct {
// Each exchange has their own requirements, so not all fields
// are required to be populated
type Cancel struct {
Price float64
Amount float64
Exchange string
ID string
ClientOrderID string
Expand All @@ -191,12 +189,8 @@ type Cancel struct {
WalletAddress string
Type Type
Side Side
Status Status
AssetType asset.Item
Date time.Time
Pair currency.Pair
Symbol string
Trades []TradeHistory
}

// CancelAllResponse returns the status from attempting to
Expand Down
20 changes: 20 additions & 0 deletions exchanges/order/orders.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ var (
errUnrecognisedOrderSide = errors.New("unrecognised order side")
errUnrecognisedOrderType = errors.New("unrecognised order type")
errUnrecognisedOrderStatus = errors.New("unrecognised order status")
errOrderDetailIsNil = errors.New("order detail is nil")
)

// Validate checks the supplied data and returns whether or not it's valid
Expand Down Expand Up @@ -493,6 +494,25 @@ func CopyPointerOrderSlice(old []*Detail) []*Detail {
return copySlice
}

// DeriveCancel populates a cancel struct by the managed order details
func (d *Detail) DeriveCancel() (*Cancel, error) {
if d == nil {
return nil, errOrderDetailIsNil
}
return &Cancel{
Exchange: d.Exchange,
ID: d.ID,
AccountID: d.AccountID,
ClientID: d.ClientID,
ClientOrderID: d.ClientOrderID,
WalletAddress: d.WalletAddress,
Type: d.Type,
Side: d.Side,
Pair: d.Pair,
AssetType: d.AssetType,
}, nil
}

// String implements the stringer interface
func (t Type) String() string {
switch t {
Expand Down

0 comments on commit c492e66

Please sign in to comment.