bbgo: add types.ExchangeOrderQueryService support for checking canceled orders

This commit is contained in:
c9s 2024-09-25 14:13:23 +08:00
parent 768428a7eb
commit b3d58a9e05
No known key found for this signature in database
GPG Key ID: 7385E7E464CB0A54

View File

@ -3,17 +3,21 @@ package bbgo
import (
"context"
"encoding/json"
"fmt"
"strconv"
"sync"
"time"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
"github.com/c9s/bbgo/pkg/exchange/retry"
"github.com/c9s/bbgo/pkg/sigchan"
"github.com/c9s/bbgo/pkg/types"
)
const DefaultCancelOrderWaitTime = 20 * time.Millisecond
const DefaultOrderCancelTimeout = 5 * time.Second
// ActiveOrderBook manages the local active order books.
//
@ -35,6 +39,7 @@ type ActiveOrderBook struct {
mu sync.Mutex
cancelOrderWaitTime time.Duration
cancelOrderTimeout time.Duration
}
func NewActiveOrderBook(symbol string) *ActiveOrderBook {
@ -44,6 +49,7 @@ func NewActiveOrderBook(symbol string) *ActiveOrderBook {
pendingOrderUpdates: types.NewSyncOrderMap(),
C: sigchan.New(1),
cancelOrderWaitTime: DefaultCancelOrderWaitTime,
cancelOrderTimeout: DefaultOrderCancelTimeout,
}
}
@ -174,7 +180,7 @@ func (b *ActiveOrderBook) GracefulCancel(ctx context.Context, ex types.Exchange,
hasSymbol := b.Symbol != ""
for _, o := range orders {
if hasSymbol && o.Symbol != b.Symbol {
return errors.New("[ActiveOrderBook] cancel " + b.Symbol + " orderbook with different symbol: " + o.Symbol)
return fmt.Errorf("[ActiveOrderBook] canceling %s orderbook with different symbol: %s", b.Symbol, o.Symbol)
}
}
}
@ -186,7 +192,6 @@ func (b *ActiveOrderBook) GracefulCancel(ctx context.Context, ex types.Exchange,
log.Debugf("[ActiveOrderBook] gracefully cancelling %s orders...", b.Symbol)
waitTime := b.cancelOrderWaitTime
orderCancelTimeout := 5 * time.Second
startTime := time.Now()
// ensure every order is canceled
@ -204,7 +209,7 @@ func (b *ActiveOrderBook) GracefulCancel(ctx context.Context, ex types.Exchange,
log.Debugf("[ActiveOrderBook] waiting %s for %d %s orders to be cancelled...", waitTime, len(orders), b.Symbol)
if cancelAll {
clear, err := b.waitAllClear(ctx, waitTime, orderCancelTimeout)
clear, err := b.waitAllClear(ctx, waitTime, b.cancelOrderTimeout)
if err != nil {
if !errors.Is(err, context.Canceled) {
log.WithError(err).Errorf("order cancel error")
@ -230,6 +235,31 @@ func (b *ActiveOrderBook) GracefulCancel(ctx context.Context, ex types.Exchange,
}
// verify the current open orders via the RESTful API
if orderQueryService, ok := ex.(types.ExchangeOrderQueryService); ok {
for idx, o := range orders {
retOrder, err := retry.QueryOrderUntilSuccessful(ctx, orderQueryService, types.OrderQuery{
Symbol: o.Symbol,
OrderID: strconv.FormatUint(o.OrderID, 10),
})
if err != nil {
log.WithError(err).Errorf("unable to update order #%d", o.OrderID)
continue
} else if retOrder != nil {
b.Update(*retOrder)
orders[idx] = *retOrder
}
}
if cancelAll {
orders = b.Orders()
} else {
// partial cancel
orders = filterCanceledOrders(orders)
}
} else {
log.Warnf("[ActiveOrderBook] using open orders API to verify the active orders...")
var symbolOrdersMap = categorizeOrderBySymbol(orders)
@ -260,6 +290,9 @@ func (b *ActiveOrderBook) GracefulCancel(ctx context.Context, ex types.Exchange,
// update order slice for the next try
orders = leftOrders
}
}
}
log.Debugf("[ActiveOrderBook] all %s orders are cancelled successfully in %s", b.Symbol, time.Since(startTime))
@ -489,3 +522,15 @@ func categorizeOrderBySymbol(orders types.OrderSlice) map[string]types.OrderSlic
return orderMap
}
func filterCanceledOrders(orders types.OrderSlice) (ret types.OrderSlice) {
for _, o := range orders {
if o.Status == types.OrderStatusCanceled {
continue
}
ret = append(ret, o)
}
return ret
}