-
-
Notifications
You must be signed in to change notification settings - Fork 303
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
sync active orders and send metrics of order nums
- Loading branch information
Showing
11 changed files
with
261 additions
and
166 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
package common | ||
|
||
import ( | ||
"context" | ||
"strconv" | ||
"time" | ||
|
||
"github.com/c9s/bbgo/pkg/bbgo" | ||
"github.com/c9s/bbgo/pkg/exchange" | ||
maxapi "github.com/c9s/bbgo/pkg/exchange/max/maxapi" | ||
"github.com/c9s/bbgo/pkg/exchange/retry" | ||
"github.com/c9s/bbgo/pkg/types" | ||
"github.com/sirupsen/logrus" | ||
"go.uber.org/multierr" | ||
) | ||
|
||
func SyncActiveOrder(ctx context.Context, ex types.Exchange, orderQueryService types.ExchangeOrderQueryService, activeOrderBook *bbgo.ActiveOrderBook, orderID uint64, syncBefore time.Time) (isOrderUpdated bool, err error) { | ||
isMax := exchange.IsMaxExchange(ex) | ||
|
||
updatedOrder, err := retry.QueryOrderUntilSuccessful(ctx, orderQueryService, types.OrderQuery{ | ||
Symbol: activeOrderBook.Symbol, | ||
OrderID: strconv.FormatUint(orderID, 10), | ||
}) | ||
|
||
if err != nil { | ||
return isOrderUpdated, err | ||
} | ||
|
||
// maxapi.OrderStateFinalizing does not mean the fee is calculated | ||
// we should only consider order state done for MAX | ||
if isMax && updatedOrder.OriginalStatus != string(maxapi.OrderStateDone) { | ||
return isOrderUpdated, nil | ||
} | ||
|
||
// should only trigger order update when the updated time is old enough | ||
isOrderUpdated = updatedOrder.UpdateTime.Before(syncBefore) | ||
if isOrderUpdated { | ||
activeOrderBook.Update(*updatedOrder) | ||
} | ||
|
||
return isOrderUpdated, nil | ||
} | ||
|
||
type SyncActiveOrdersOpts struct { | ||
Logger *logrus.Entry | ||
Exchange types.Exchange | ||
OrderQueryService types.ExchangeOrderQueryService | ||
ActiveOrderBook *bbgo.ActiveOrderBook | ||
OpenOrders []types.Order | ||
} | ||
|
||
func SyncActiveOrders(ctx context.Context, opts SyncActiveOrdersOpts) error { | ||
opts.Logger.Infof("[ActiveOrderRecover] syncActiveOrders") | ||
|
||
// only sync orders which is updated over 3 min, because we may receive from websocket and handle it twice | ||
syncBefore := time.Now().Add(-3 * time.Minute) | ||
|
||
activeOrders := opts.ActiveOrderBook.Orders() | ||
|
||
openOrdersMap := make(map[uint64]types.Order) | ||
for _, openOrder := range opts.OpenOrders { | ||
openOrdersMap[openOrder.OrderID] = openOrder | ||
} | ||
|
||
var errs error | ||
// update active orders not in open orders | ||
for _, activeOrder := range activeOrders { | ||
if _, exist := openOrdersMap[activeOrder.OrderID]; exist { | ||
// no need to sync active order already in active orderbook, because we only need to know if it filled or not. | ||
delete(openOrdersMap, activeOrder.OrderID) | ||
} else { | ||
opts.Logger.Infof("[ActiveOrderRecover] found active order #%d is not in the open orders, updating...", activeOrder.OrderID) | ||
|
||
isActiveOrderBookUpdated, err := SyncActiveOrder(ctx, opts.Exchange, opts.OrderQueryService, opts.ActiveOrderBook, activeOrder.OrderID, syncBefore) | ||
if err != nil { | ||
opts.Logger.WithError(err).Errorf("[ActiveOrderRecover] unable to query order #%d", activeOrder.OrderID) | ||
errs = multierr.Append(errs, err) | ||
continue | ||
} | ||
|
||
if !isActiveOrderBookUpdated { | ||
opts.Logger.Infof("[ActiveOrderRecover] active order #%d is updated in 3 min, skip updating...", activeOrder.OrderID) | ||
} | ||
} | ||
} | ||
|
||
// update open orders not in active orders | ||
for _, openOrder := range openOrdersMap { | ||
opts.Logger.Infof("found open order #%d is not in active orderbook, updating...", openOrder.OrderID) | ||
// we don't add open orders into active orderbook if updated in 3 min, because we may receive message from websocket and add it twice. | ||
if openOrder.UpdateTime.After(syncBefore) { | ||
opts.Logger.Infof("open order #%d is updated in 3 min, skip updating...", openOrder.OrderID) | ||
continue | ||
} | ||
|
||
opts.ActiveOrderBook.Add(openOrder) | ||
} | ||
|
||
return errs | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package dca2 | ||
|
||
import ( | ||
"context" | ||
"time" | ||
|
||
"github.com/c9s/bbgo/pkg/exchange/retry" | ||
"github.com/c9s/bbgo/pkg/strategy/common" | ||
"github.com/c9s/bbgo/pkg/util" | ||
) | ||
|
||
func (s *Strategy) recoverPeriodically(ctx context.Context) { | ||
s.logger.Info("[DCA] monitor and recover periodically") | ||
interval := util.MillisecondsJitter(10*time.Minute, 5*60*1000) | ||
ticker := time.NewTicker(interval) | ||
defer ticker.Stop() | ||
|
||
for { | ||
select { | ||
case <-ctx.Done(): | ||
return | ||
case <-ticker.C: | ||
if err := s.recoverActiveOrders(ctx); err != nil { | ||
s.logger.WithError(err).Warn(err, "failed to recover active orders") | ||
} | ||
} | ||
} | ||
} | ||
|
||
func (s *Strategy) recoverActiveOrders(ctx context.Context) error { | ||
openOrders, err := retry.QueryOpenOrdersUntilSuccessfulLite(ctx, s.ExchangeSession.Exchange, s.Symbol) | ||
if err != nil { | ||
s.logger.WithError(err).Warn("failed to query open orders") | ||
return err | ||
} | ||
|
||
activeOrders := s.OrderExecutor.ActiveMakerOrders().Orders() | ||
|
||
// update num of open orders metrics | ||
if metricsNumOfOpenOrders != nil { | ||
metricsNumOfOpenOrders.With(baseLabels).Set(float64(len(openOrders))) | ||
} | ||
|
||
// update num of active orders metrics | ||
if metricsNumOfActiveOrders != nil { | ||
metricsNumOfActiveOrders.With(baseLabels).Set(float64(len(activeOrders))) | ||
} | ||
|
||
opts := common.SyncActiveOrdersOpts{ | ||
Logger: s.logger, | ||
Exchange: s.ExchangeSession.Exchange, | ||
ActiveOrderBook: s.OrderExecutor.ActiveMakerOrders(), | ||
OpenOrders: openOrders, | ||
} | ||
|
||
return common.SyncActiveOrders(ctx, opts) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.