orders: Add method for creating cancel struct from order details (#947)

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

* orders: remove uneeded fields

* glorious: nit
This commit is contained in:
Ryan O'Hara-Reid
2022-05-19 17:53:58 +10:00
committed by GitHub
parent 14cde7b786
commit c492e6600e
8 changed files with 81 additions and 35 deletions

View File

@@ -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)
}

View File

@@ -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
}
@@ -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)

View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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")
}
}

View File

@@ -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
@@ -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

View File

@@ -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
@@ -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 {