Merge pull request #1640 from c9s/kbearXD/dca2/flexible-recovery

FEATURE: [dca2] change state recovery logic
This commit is contained in:
kbearXD 2024-05-24 15:54:23 +08:00 committed by GitHub
commit c42c52d549
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 70 additions and 21 deletions

View File

@ -0,0 +1,43 @@
package retry
import (
"context"
"github.com/c9s/bbgo/pkg/types"
)
func QueryAccountUntilSuccessful(
ctx context.Context, ex types.ExchangeAccountService,
) (account *types.Account, err error) {
var op = func() (err2 error) {
account, err2 = ex.QueryAccount(ctx)
return err2
}
err = GeneralBackoff(ctx, op)
return account, err
}
func QueryAccountBalancesUntilSuccessful(
ctx context.Context, ex types.ExchangeAccountService,
) (bals types.BalanceMap, err error) {
var op = func() (err2 error) {
bals, err2 = ex.QueryAccountBalances(ctx)
return err2
}
err = GeneralBackoff(ctx, op)
return bals, err
}
func QueryAccountBalancesUntilSuccessfulLite(
ctx context.Context, ex types.ExchangeAccountService,
) (bals types.BalanceMap, err error) {
var op = func() (err2 error) {
bals, err2 = ex.QueryAccountBalances(ctx)
return err2
}
err = GeneralLiteBackoff(ctx, op)
return bals, err
}

View File

@ -180,18 +180,6 @@ func QueryOrderTradesUntilSuccessfulLite(
return trades, err
}
func QueryAccountUntilSuccessful(
ctx context.Context, ex types.ExchangeAccountService,
) (account *types.Account, err error) {
var op = func() (err2 error) {
account, err2 = ex.QueryAccount(ctx)
return err2
}
err = GeneralBackoff(ctx, op)
return account, err
}
func QueryOrderUntilSuccessful(
ctx context.Context, query types.ExchangeOrderQueryService, opts types.OrderQuery,
) (order *types.Order, err error) {

View File

@ -113,13 +113,13 @@ func recoverState(ctx context.Context, maxOrderCount int, currentRound Round, or
}
}
// all open-position orders are still not filled -> OpenPositionReady
if filledCnt == 0 && cancelledCnt == 0 {
// no order is filled -> OpenPositionReady
if filledCnt == 0 {
return OpenPositionReady, nil
}
// there are at least one open-position orders filled
if filledCnt > 0 && cancelledCnt == 0 {
if cancelledCnt == 0 {
if openedCnt > 0 {
return OpenPositionOrderFilled, nil
} else {
@ -128,12 +128,8 @@ func recoverState(ctx context.Context, maxOrderCount int, currentRound Round, or
}
}
// there are at last one open-position orders cancelled ->
if cancelledCnt > 0 {
return OpenPositionOrdersCancelling, nil
}
return None, fmt.Errorf("unexpected order status combination (opened, filled, cancelled) = (%d, %d, %d)", openedCnt, filledCnt, cancelledCnt)
// there are at last one open-position orders cancelled and at least one filled order -> open position order cancelling
return OpenPositionOrdersCancelling, nil
}
func recoverPosition(ctx context.Context, position *types.Position, currentRound Round, queryService types.ExchangeOrderQueryService) error {

View File

@ -4,6 +4,7 @@ import (
"context"
"fmt"
"github.com/c9s/bbgo/pkg/exchange/retry"
"github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/types"
"github.com/pkg/errors"
@ -39,6 +40,27 @@ func (s *Strategy) placeTakeProfitOrders(ctx context.Context) error {
s.logger.Infof("position of this round before place the take-profit order: %s", roundPosition.String())
order := generateTakeProfitOrder(s.Market, s.TakeProfitRatio, roundPosition, s.OrderGroupID)
// verify the volume of order
bals, err := retry.QueryAccountBalancesUntilSuccessfulLite(ctx, s.ExchangeSession.Exchange)
if err != nil {
return errors.Wrapf(err, "failed to query balance to verify")
}
bal, exist := bals[s.Market.BaseCurrency]
if !exist {
return fmt.Errorf("there is no %s in the balances %+v", s.Market.BaseCurrency, bals)
}
quantityDiff := bal.Available.Sub(order.Quantity)
if quantityDiff.Sign() < 0 {
return fmt.Errorf("the balance (%s) is not enough for the order (%s)", bal.String(), order.Quantity.String())
}
if quantityDiff.Compare(s.Market.MinQuantity) > 0 {
s.logger.Warnf("the diff between balance (%s) and the take-profit order (%s) is larger than min quantity %s", bal.String(), order.Quantity.String(), s.Market.MinQuantity.String())
}
createdOrders, err := s.OrderExecutor.SubmitOrders(ctx, order)
if err != nil {
return err