diff --git a/pkg/exchange/retry/order.go b/pkg/exchange/retry/order.go index 9a621e32c..3a61fd805 100644 --- a/pkg/exchange/retry/order.go +++ b/pkg/exchange/retry/order.go @@ -156,11 +156,17 @@ func QueryClosedOrdersUntilSuccessfulLite( return closedOrders, err } +// QueryOrderTradesUntilSuccessful query order's trades until success (include the trading fee is not processing) func QueryOrderTradesUntilSuccessful( ctx context.Context, ex types.ExchangeOrderQueryService, q types.OrderQuery, ) (trades []types.Trade, err error) { var op = func() (err2 error) { trades, err2 = ex.QueryOrderTrades(ctx, q) + for _, trade := range trades { + if trade.FeeProcessing { + return fmt.Errorf("there are some trades which trading fee is not ready") + } + } return err2 } @@ -168,11 +174,17 @@ func QueryOrderTradesUntilSuccessful( return trades, err } +// QueryOrderTradesUntilSuccessfulLite query order's trades until success (include the trading fee is not processing) func QueryOrderTradesUntilSuccessfulLite( ctx context.Context, ex types.ExchangeOrderQueryService, q types.OrderQuery, ) (trades []types.Trade, err error) { var op = func() (err2 error) { trades, err2 = ex.QueryOrderTrades(ctx, q) + for _, trade := range trades { + if trade.FeeProcessing { + return fmt.Errorf("there are some trades which trading fee is not ready") + } + } return err2 } diff --git a/pkg/strategy/dca2/collector.go b/pkg/strategy/dca2/collector.go index f68e75538..7743209a0 100644 --- a/pkg/strategy/dca2/collector.go +++ b/pkg/strategy/dca2/collector.go @@ -152,6 +152,7 @@ func (rc *Collector) CollectFinishRounds(ctx context.Context, fromOrderID uint64 return rounds, nil } +// CollectRoundTrades collect the trades of the orders in the given round. The trades' fee are processed (feeProcessing = false) func (rc *Collector) CollectRoundTrades(ctx context.Context, round Round) ([]types.Trade, error) { debugRoundOrders(rc.logger, "collect round trades", round) @@ -171,7 +172,8 @@ func (rc *Collector) CollectRoundTrades(ctx context.Context, round Round) ([]typ rc.logger.Info("collect trades from order ", order.String()) } - trades, err := retry.QueryOrderTradesUntilSuccessfulLite(ctx, rc.queryService, types.OrderQuery{ + // QueryOrderTradesUntilSuccessful will query trades and their feeProcessing = false + trades, err := retry.QueryOrderTradesUntilSuccessful(ctx, rc.queryService, types.OrderQuery{ Symbol: order.Symbol, OrderID: strconv.FormatUint(order.OrderID, 10), }) diff --git a/pkg/strategy/dca2/recover.go b/pkg/strategy/dca2/recover.go index bc0b43270..6c2a7ed3b 100644 --- a/pkg/strategy/dca2/recover.go +++ b/pkg/strategy/dca2/recover.go @@ -7,7 +7,9 @@ import ( "time" "github.com/c9s/bbgo/pkg/bbgo" + "github.com/c9s/bbgo/pkg/exchange/retry" "github.com/c9s/bbgo/pkg/types" + "github.com/pkg/errors" ) var recoverSinceLimit = time.Date(2024, time.January, 29, 12, 0, 0, 0, time.Local) @@ -139,9 +141,12 @@ func recoverPosition(ctx context.Context, position *types.Position, currentRound return fmt.Errorf("position is nil, please check it") } - var positionOrders []types.Order + // reset position to recover position.Reset() + + var positionOrders []types.Order if currentRound.TakeProfitOrder.OrderID != 0 { + // if the take-profit order is already filled, the position is 0 if !types.IsActiveOrder(currentRound.TakeProfitOrder) { return nil } @@ -159,15 +164,14 @@ func recoverPosition(ctx context.Context, position *types.Position, currentRound } for _, positionOrder := range positionOrders { - trades, err := queryService.QueryOrderTrades(ctx, types.OrderQuery{ + trades, err := retry.QueryOrderTradesUntilSuccessful(ctx, queryService, types.OrderQuery{ Symbol: position.Symbol, OrderID: strconv.FormatUint(positionOrder.OrderID, 10), }) if err != nil { - return fmt.Errorf("failed to get trades of order (%d)", positionOrder.OrderID) + return errors.Wrapf(err, "failed to get order (%d) trades", positionOrder.OrderID) } - position.AddTrades(trades) } diff --git a/pkg/strategy/dca2/strategy.go b/pkg/strategy/dca2/strategy.go index f107ddf25..9f8b53847 100644 --- a/pkg/strategy/dca2/strategy.go +++ b/pkg/strategy/dca2/strategy.go @@ -318,6 +318,9 @@ func (s *Strategy) Run(ctx context.Context, _ bbgo.OrderExecutor, session *bbgo. s.logger.Errorf("failed to recover after %d trying, please check it", maxTry) return } + + // sleep 10 second to retry the recovery + time.Sleep(10 * time.Second) } } @@ -337,14 +340,15 @@ func (s *Strategy) Run(ctx context.Context, _ bbgo.OrderExecutor, session *bbgo. // ready s.EmitReady() + // start to sync periodically + go s.syncPeriodically(ctx) + // start running state machine s.runState(ctx) } }) }) - go s.syncPeriodically(ctx) - bbgo.OnShutdown(ctx, func(ctx context.Context, wg *sync.WaitGroup) { defer wg.Done() @@ -456,6 +460,7 @@ func (s *Strategy) UpdateProfitStatsUntilSuccessful(ctx context.Context) error { // return false, nil -> there is no finished round! // return true, error -> At least one round update profit stats successfully but there is error when collecting other rounds func (s *Strategy) UpdateProfitStats(ctx context.Context) (bool, error) { + s.logger.Info("update profit stats") rounds, err := s.collector.CollectFinishRounds(ctx, s.ProfitStats.FromOrderID) if err != nil { return false, errors.Wrapf(err, "failed to collect finish rounds from #%d", s.ProfitStats.FromOrderID)