Skip to content

Commit

Permalink
dca2: must calculate and emit profit at the end of the round
Browse files Browse the repository at this point in the history
  • Loading branch information
kbearXD committed Mar 14, 2024
1 parent 747b75f commit f19eceb
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 8 deletions.
14 changes: 10 additions & 4 deletions pkg/strategy/dca2/recover.go
Expand Up @@ -45,11 +45,14 @@ func (s *Strategy) recover(ctx context.Context) error {
}
debugRoundOrders(s.logger, "current", currentRound)

// TODO: use flag
// recover profit stats
if err := recoverProfitStats(ctx, s); err != nil {
return err
}
s.logger.Info("recover profit stats DONE")
/*
if err := recoverProfitStats(ctx, s); err != nil {
return err
}
s.logger.Info("recover profit stats DONE")
*/

// recover position
if err := recoverPosition(ctx, s.Position, queryService, currentRound); err != nil {
Expand Down Expand Up @@ -202,13 +205,16 @@ func recoverPosition(ctx context.Context, position *types.Position, queryService
return nil
}

// TODO: use flag to decide which to recover
/*
func recoverProfitStats(ctx context.Context, strategy *Strategy) error {
if strategy.ProfitStats == nil {
return fmt.Errorf("profit stats is nil, please check it")
}
return strategy.CalculateAndEmitProfit(ctx)
}
*/

func recoverStartTimeOfNextRound(ctx context.Context, currentRound Round, coolDownInterval types.Duration) time.Time {
if currentRound.TakeProfitOrder.OrderID != 0 && currentRound.TakeProfitOrder.Status == types.OrderStatusFilled {
Expand Down
2 changes: 1 addition & 1 deletion pkg/strategy/dca2/state.go
Expand Up @@ -201,7 +201,7 @@ func (s *Strategy) runTakeProfitReady(ctx context.Context, next State) {
// reset position

// calculate profit stats
if err := s.CalculateAndEmitProfit(ctx); err != nil {
if err := s.mustCalculateAndEmitProfit(ctx); err != nil {
s.logger.WithError(err).Warn("failed to calculate and emit profit")
}

Expand Down
46 changes: 43 additions & 3 deletions pkg/strategy/dca2/strategy.go
Expand Up @@ -13,6 +13,8 @@ import (
"go.uber.org/multierr"

"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/fixedpoint"
"github.com/c9s/bbgo/pkg/strategy/common"
Expand Down Expand Up @@ -370,7 +372,9 @@ func (s *Strategy) CleanUp(ctx context.Context) error {
return werr
}

func (s *Strategy) CalculateAndEmitProfit(ctx context.Context) error {
func (s *Strategy) mustCalculateAndEmitProfit(ctx context.Context) error {
fromOrderID := s.ProfitStats.FromOrderID

historyService, ok := s.ExchangeSession.Exchange.(types.ExchangeTradeHistoryService)
if !ok {
return fmt.Errorf("exchange %s doesn't support ExchangeTradeHistoryService", s.ExchangeSession.Exchange.Name())
Expand All @@ -381,6 +385,26 @@ func (s *Strategy) CalculateAndEmitProfit(ctx context.Context) error {
return fmt.Errorf("exchange %s doesn't support ExchangeOrderQueryService", s.ExchangeSession.Exchange.Name())
}

maxTry := 10
for try := 1; try < maxTry; try++ {
if err := s.CalculateAndEmitProfit(ctx, historyService, queryService); err != nil {
s.logger.WithError(err).Warnf("failed to calculate and emit profit at #%d try, please check it", try)
continue
}

if s.ProfitStats.FromOrderID > fromOrderID {
break
}
}

if s.ProfitStats.FromOrderID == fromOrderID {
return fmt.Errorf("after trying %d times, we still can't calculate and emit profit, please check it", maxTry)
}

return nil
}

func (s *Strategy) CalculateAndEmitProfit(ctx context.Context, historyService types.ExchangeTradeHistoryService, queryService types.ExchangeOrderQueryService) error {
// TODO: pagination for it
// query the orders
s.logger.Infof("query %s closed orders from order id #%d", s.Symbol, s.ProfitStats.FromOrderID)
Expand All @@ -390,6 +414,8 @@ func (s *Strategy) CalculateAndEmitProfit(ctx context.Context) error {
}
s.logger.Infof("there are %d closed orders from order id #%d", len(orders), s.ProfitStats.FromOrderID)

isMax := exchange.IsMaxExchange(s.ExchangeSession.Exchange)

var rounds []Round
var round Round
for _, order := range orders {
Expand All @@ -402,9 +428,23 @@ func (s *Strategy) CalculateAndEmitProfit(ctx context.Context) error {
case types.SideTypeBuy:
round.OpenPositionOrders = append(round.OpenPositionOrders, order)
case types.SideTypeSell:
if order.Status != types.OrderStatusFilled {
continue
if !isMax {
if order.Status != types.OrderStatusFilled {
s.logger.Infof("take-profit order is %s not filled, so this round is not finished. Skip it", order.Status)
continue
}
} else {
switch maxapi.OrderState(order.OriginalStatus) {
case maxapi.OrderStateDone:
// the same as filled
case maxapi.OrderStateFinalizing:
// the same as filled
default:
s.logger.Infof("isMax and take-profit order is %s not done or finalizing, so this round is not finished. Skip it", order.OriginalStatus)
continue
}
}

round.TakeProfitOrder = order
rounds = append(rounds, round)
round = Round{}
Expand Down

0 comments on commit f19eceb

Please sign in to comment.