From 6676e1e45268d73557b0f85492b7ae3d60041fa9 Mon Sep 17 00:00:00 2001 From: kbearXD Date: Mon, 20 May 2024 14:37:23 +0800 Subject: [PATCH 1/3] FEATURE: [dca2] store price quantity pairs of the open-position orders into persistence --- pkg/strategy/dca2/open_position.go | 11 +++++++++++ pkg/strategy/dca2/profit_stats.go | 8 ++++++++ 2 files changed, 19 insertions(+) diff --git a/pkg/strategy/dca2/open_position.go b/pkg/strategy/dca2/open_position.go index a16786423b..c156fb3a07 100644 --- a/pkg/strategy/dca2/open_position.go +++ b/pkg/strategy/dca2/open_position.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/c9s/bbgo/pkg/bbgo" "github.com/c9s/bbgo/pkg/exchange/retry" "github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/types" @@ -32,6 +33,16 @@ func (s *Strategy) placeOpenPositionOrders(ctx context.Context) error { s.debugOrders(createdOrders) + // store price quantity pairs into persistence + var pqs []PriceQuantity + for _, createdOrder := range createdOrders { + pqs = append(pqs, PriceQuantity{Price: createdOrder.Price, Quantity: createdOrder.Quantity}) + } + + s.ProfitStats.OpenPositionPQs = pqs + + bbgo.Sync(ctx, s) + return nil } diff --git a/pkg/strategy/dca2/profit_stats.go b/pkg/strategy/dca2/profit_stats.go index 6a56245231..d04157f1c7 100644 --- a/pkg/strategy/dca2/profit_stats.go +++ b/pkg/strategy/dca2/profit_stats.go @@ -8,6 +8,11 @@ import ( "github.com/c9s/bbgo/pkg/types" ) +type PriceQuantity struct { + Price fixedpoint.Value `json:"price,omitempty"` + Quantity fixedpoint.Value `json:"quantity,omitempty"` +} + type ProfitStats struct { Symbol string `json:"symbol"` Market types.Market `json:"market,omitempty"` @@ -21,6 +26,9 @@ type ProfitStats struct { TotalProfit fixedpoint.Value `json:"totalProfit,omitempty"` TotalFee map[string]fixedpoint.Value `json:"totalFee,omitempty"` + // used to flexible recovery + OpenPositionPQs []PriceQuantity `json:"openPositionPQs,omitempty"` + types.PersistenceTTL } From 0faef68fbfd115ad22db605773537cd21c049849 Mon Sep 17 00:00:00 2001 From: kbearXD Date: Tue, 21 May 2024 16:06:02 +0800 Subject: [PATCH 2/3] use types.PriceVolume --- pkg/strategy/dca2/collector.go | 5 ++++ pkg/strategy/dca2/open_position.go | 6 ++-- pkg/strategy/dca2/profit_stats.go | 7 +---- pkg/strategy/dca2/recover.go | 44 ------------------------------ 4 files changed, 9 insertions(+), 53 deletions(-) diff --git a/pkg/strategy/dca2/collector.go b/pkg/strategy/dca2/collector.go index 7743209a03..add007c93f 100644 --- a/pkg/strategy/dca2/collector.go +++ b/pkg/strategy/dca2/collector.go @@ -11,6 +11,11 @@ import ( "github.com/sirupsen/logrus" ) +type Round struct { + OpenPositionOrders []types.Order + TakeProfitOrder types.Order +} + type Collector struct { logger *logrus.Entry symbol string diff --git a/pkg/strategy/dca2/open_position.go b/pkg/strategy/dca2/open_position.go index c156fb3a07..c9b0460c46 100644 --- a/pkg/strategy/dca2/open_position.go +++ b/pkg/strategy/dca2/open_position.go @@ -34,12 +34,12 @@ func (s *Strategy) placeOpenPositionOrders(ctx context.Context) error { s.debugOrders(createdOrders) // store price quantity pairs into persistence - var pqs []PriceQuantity + var pvs []types.PriceVolume for _, createdOrder := range createdOrders { - pqs = append(pqs, PriceQuantity{Price: createdOrder.Price, Quantity: createdOrder.Quantity}) + pvs = append(pvs, types.PriceVolume{Price: createdOrder.Price, Volume: createdOrder.Quantity}) } - s.ProfitStats.OpenPositionPQs = pqs + s.ProfitStats.OpenPositionPVs = pvs bbgo.Sync(ctx, s) diff --git a/pkg/strategy/dca2/profit_stats.go b/pkg/strategy/dca2/profit_stats.go index d04157f1c7..54966393d1 100644 --- a/pkg/strategy/dca2/profit_stats.go +++ b/pkg/strategy/dca2/profit_stats.go @@ -8,11 +8,6 @@ import ( "github.com/c9s/bbgo/pkg/types" ) -type PriceQuantity struct { - Price fixedpoint.Value `json:"price,omitempty"` - Quantity fixedpoint.Value `json:"quantity,omitempty"` -} - type ProfitStats struct { Symbol string `json:"symbol"` Market types.Market `json:"market,omitempty"` @@ -27,7 +22,7 @@ type ProfitStats struct { TotalFee map[string]fixedpoint.Value `json:"totalFee,omitempty"` // used to flexible recovery - OpenPositionPQs []PriceQuantity `json:"openPositionPQs,omitempty"` + OpenPositionPVs []types.PriceVolume `json:"openPositionPVs,omitempty"` types.PersistenceTTL } diff --git a/pkg/strategy/dca2/recover.go b/pkg/strategy/dca2/recover.go index 6c2a7ed3b5..23f72c9b89 100644 --- a/pkg/strategy/dca2/recover.go +++ b/pkg/strategy/dca2/recover.go @@ -194,47 +194,3 @@ func recoverStartTimeOfNextRound(ctx context.Context, currentRound Round, coolDo return time.Time{} } - -type Round struct { - OpenPositionOrders []types.Order - TakeProfitOrder types.Order -} - -func getCurrentRoundOrders(openOrders, closedOrders []types.Order, groupID uint32) (Round, error) { - openPositionSide := types.SideTypeBuy - takeProfitSide := types.SideTypeSell - - var allOrders []types.Order - allOrders = append(allOrders, openOrders...) - allOrders = append(allOrders, closedOrders...) - - types.SortOrdersDescending(allOrders) - - var currentRound Round - lastSide := takeProfitSide - for _, order := range allOrders { - // group id filter is used for debug when local running - if order.GroupID != groupID { - continue - } - - if order.Side == takeProfitSide && lastSide == openPositionSide { - break - } - - switch order.Side { - case openPositionSide: - currentRound.OpenPositionOrders = append(currentRound.OpenPositionOrders, order) - case takeProfitSide: - if currentRound.TakeProfitOrder.OrderID != 0 { - return currentRound, fmt.Errorf("there are two take-profit orders in one round, please check it") - } - currentRound.TakeProfitOrder = order - default: - } - - lastSide = order.Side - } - - return currentRound, nil -} From 275286b9b9eff5d3eaaef4110578905b9e257039 Mon Sep 17 00:00:00 2001 From: kbearXD Date: Tue, 21 May 2024 17:00:02 +0800 Subject: [PATCH 3/3] remove test case --- pkg/strategy/dca2/recover_test.go | 56 ------------------------------- 1 file changed, 56 deletions(-) diff --git a/pkg/strategy/dca2/recover_test.go b/pkg/strategy/dca2/recover_test.go index ae3a41fa84..db9f9ea781 100644 --- a/pkg/strategy/dca2/recover_test.go +++ b/pkg/strategy/dca2/recover_test.go @@ -23,62 +23,6 @@ func generateTestOrder(side types.SideType, status types.OrderStatus, createdAt } -func Test_GetCurrenctRoundOrders(t *testing.T) { - t.Run("case 1", func(t *testing.T) { - now := time.Now() - openOrders := []types.Order{ - generateTestOrder(types.SideTypeSell, types.OrderStatusNew, now), - } - - closedOrders := []types.Order{ - generateTestOrder(types.SideTypeBuy, types.OrderStatusFilled, now.Add(-1*time.Second)), - generateTestOrder(types.SideTypeBuy, types.OrderStatusFilled, now.Add(-2*time.Second)), - generateTestOrder(types.SideTypeBuy, types.OrderStatusFilled, now.Add(-3*time.Second)), - generateTestOrder(types.SideTypeBuy, types.OrderStatusFilled, now.Add(-4*time.Second)), - generateTestOrder(types.SideTypeBuy, types.OrderStatusFilled, now.Add(-5*time.Second)), - } - - currentRound, err := getCurrentRoundOrders(openOrders, closedOrders, 0) - - assert.NoError(t, err) - assert.NotEqual(t, 0, currentRound.TakeProfitOrder.OrderID) - assert.Equal(t, 5, len(currentRound.OpenPositionOrders)) - }) - - t.Run("case 2", func(t *testing.T) { - now := time.Now() - openOrders := []types.Order{ - generateTestOrder(types.SideTypeSell, types.OrderStatusNew, now), - } - - closedOrders := []types.Order{ - generateTestOrder(types.SideTypeBuy, types.OrderStatusFilled, now.Add(-1*time.Second)), - generateTestOrder(types.SideTypeBuy, types.OrderStatusFilled, now.Add(-2*time.Second)), - generateTestOrder(types.SideTypeBuy, types.OrderStatusFilled, now.Add(-3*time.Second)), - generateTestOrder(types.SideTypeBuy, types.OrderStatusFilled, now.Add(-4*time.Second)), - generateTestOrder(types.SideTypeBuy, types.OrderStatusFilled, now.Add(-5*time.Second)), - generateTestOrder(types.SideTypeSell, types.OrderStatusFilled, now.Add(-6*time.Second)), - generateTestOrder(types.SideTypeBuy, types.OrderStatusFilled, now.Add(-7*time.Second)), - generateTestOrder(types.SideTypeBuy, types.OrderStatusFilled, now.Add(-8*time.Second)), - generateTestOrder(types.SideTypeBuy, types.OrderStatusFilled, now.Add(-9*time.Second)), - generateTestOrder(types.SideTypeBuy, types.OrderStatusFilled, now.Add(-10*time.Second)), - generateTestOrder(types.SideTypeBuy, types.OrderStatusFilled, now.Add(-11*time.Second)), - generateTestOrder(types.SideTypeSell, types.OrderStatusFilled, now.Add(-12*time.Second)), - generateTestOrder(types.SideTypeBuy, types.OrderStatusFilled, now.Add(-13*time.Second)), - generateTestOrder(types.SideTypeBuy, types.OrderStatusFilled, now.Add(-14*time.Second)), - generateTestOrder(types.SideTypeBuy, types.OrderStatusFilled, now.Add(-15*time.Second)), - generateTestOrder(types.SideTypeBuy, types.OrderStatusFilled, now.Add(-16*time.Second)), - generateTestOrder(types.SideTypeBuy, types.OrderStatusFilled, now.Add(-17*time.Second)), - } - - currentRound, err := getCurrentRoundOrders(openOrders, closedOrders, 0) - - assert.NoError(t, err) - assert.NotEqual(t, 0, currentRound.TakeProfitOrder.OrderID) - assert.Equal(t, 5, len(currentRound.OpenPositionOrders)) - }) -} - type MockQueryOrders struct { OpenOrders []types.Order ClosedOrders []types.Order