Skip to content

FEATURE: [dca2] UpdateProfitStatsUntilSuccess -> UpdateProfitStatsUnt… #2032

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pkg/strategy/dca2/profit_stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ func newProfitStats(market types.Market, quoteInvestment fixedpoint.Value) *Prof
}
}

// AddTrade adds a trade to the profit stats and updates the current round profit and total profit.
func (s *ProfitStats) AddTrade(trade types.Trade) {
if s.CurrentRoundFee == nil {
s.CurrentRoundFee = make(map[string]fixedpoint.Value)
Expand Down
9 changes: 7 additions & 2 deletions pkg/strategy/dca2/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ import (

type State int64

const (
MaxRetryDurationToUpdateProfitStats time.Duration = 30 * time.Minute
)

const (
None State = iota
IdleWaiting
Expand Down Expand Up @@ -243,8 +247,9 @@ func (s *Strategy) finishTakeProfitStage(ctx context.Context, next State) bool {
s.logger.Info("[State] finishTakeProfitStage - start resetting position and calculate quote investment for next round")

// update profit stats
if err := s.UpdateProfitStatsUntilSuccessful(ctx); err != nil {
s.logger.WithError(err).Warn("failed to calculate and emit profit")
// it will try to update profit stats for 30 minutes
if err := s.UpdateProfitStatsUntilDuration(ctx, MaxRetryDurationToUpdateProfitStats); err != nil {
s.logger.WithError(err).Error("failed to calculate and emit profit, please check it")
}

// reset position and open new round for profit stats before position opening
Expand Down
22 changes: 14 additions & 8 deletions pkg/strategy/dca2/strategy.go
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,7 @@ func (s *Strategy) Close(ctx context.Context) error {

var err error
if s.UseCancelAllOrdersApiWhenClose {
s.logger.Info("UseCancelAllOrdersApiWhenClose is set, will cancel all orders by cancel all orders API")
Copy link
Preview

Copilot AI May 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Consider rewording this log message for improved clarity. A suggestion is: 'UseCancelAllOrdersApiWhenClose is enabled; canceling all orders using the CancelAllOrders API'.

Copilot uses AI. Check for mistakes.

err = tradingutil.UniversalCancelAllOrders(ctx, s.ExchangeSession.Exchange, s.Symbol, nil)
} else {
err = s.OrderExecutor.GracefulCancel(ctx)
Expand Down Expand Up @@ -429,7 +430,10 @@ func (s *Strategy) ContinueNextRound() {
s.nextRoundPaused = false
}

func (s *Strategy) UpdateProfitStatsUntilSuccessful(ctx context.Context) error {
// UpdateProfitStatsUntilSuccessful will update the profit stats until duration (duration == 0 means no stop)
// it will retry for 30 minutes with exponential backoff
// if it is not successful, it will return an error and the ProfitStats will not be updated into persistence
func (s *Strategy) UpdateProfitStatsUntilDuration(ctx context.Context, duration time.Duration) error {
var op = func() error {
if updated, err := s.UpdateProfitStats(ctx); err != nil {
return errors.Wrapf(err, "failed to update profit stats, please check it")
Expand All @@ -443,8 +447,8 @@ func (s *Strategy) UpdateProfitStatsUntilSuccessful(ctx context.Context) error {
// exponential increased interval retry until success
bo := backoff.NewExponentialBackOff()
bo.InitialInterval = 5 * time.Second
bo.MaxInterval = 20 * time.Minute
bo.MaxElapsedTime = 0
bo.MaxInterval = 5 * time.Minute
bo.MaxElapsedTime = duration

return backoff.Retry(op, backoff.WithContext(bo, ctx))
}
Expand All @@ -460,6 +464,8 @@ func (s *Strategy) UpdateProfitStats(ctx context.Context) (bool, error) {
return false, errors.Wrapf(err, "failed to collect finish rounds from #%d", s.ProfitStats.FromOrderID)
}

s.logger.Infof("there are %d finished rounds from #%d", len(rounds), s.ProfitStats.FromOrderID)

var updated bool = false
for _, round := range rounds {
trades, err := s.collector.CollectRoundTrades(ctx, round)
Expand All @@ -472,6 +478,11 @@ func (s *Strategy) UpdateProfitStats(ctx context.Context) (bool, error) {
s.ProfitStats.AddTrade(trade)
}

s.logger.Infof("profit stats:\n%s", s.ProfitStats.String())

// emit profit
s.EmitProfit(s.ProfitStats)

// update profit stats FromOrderID to make sure we will not collect duplicated rounds
for _, order := range round.TakeProfitOrders {
if order.OrderID >= s.ProfitStats.FromOrderID {
Expand All @@ -486,11 +497,6 @@ func (s *Strategy) UpdateProfitStats(ctx context.Context) (bool, error) {
bbgo.Sync(ctx, s)
updated = true

s.logger.Infof("profit stats:\n%s", s.ProfitStats.String())

// emit profit
s.EmitProfit(s.ProfitStats)

// make profit stats forward to new round
s.ProfitStats.NewRound()
}
Expand Down
1 change: 1 addition & 0 deletions pkg/strategy/grid2/strategy.go
Original file line number Diff line number Diff line change
Expand Up @@ -980,6 +980,7 @@ func (s *Strategy) cancelAll(ctx context.Context) error {

var err error
if s.UseCancelAllOrdersApiWhenClose {
s.logger.Info("UseCancelAllOrdersApiWhenClose is set, will cancel all orders by cancel all orders API")
Copy link
Preview

Copilot AI May 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Consider rewording the logging message for clarity. For instance, 'UseCancelAllOrdersApiWhenClose is enabled; canceling all orders using the CancelAllOrders API' may be clearer.

Copilot uses AI. Check for mistakes.

err = tradingutil.UniversalCancelAllOrders(ctx, session.Exchange, s.Symbol, nil)
} else {
err = s.orderExecutor.GracefulCancel(ctx)
Expand Down
Loading