Skip to content

Commit

Permalink
Merge pull request #1629 from c9s/kbearXD/dca2/refactor
Browse files Browse the repository at this point in the history
REFACTOR: [dca2] refactor dca2 strategy to make it can back testing
  • Loading branch information
kbearXD committed May 13, 2024
2 parents 1e41645 + e856727 commit e86dece
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 55 deletions.
7 changes: 0 additions & 7 deletions pkg/strategy/dca2/dev_mode.go

This file was deleted.

16 changes: 0 additions & 16 deletions pkg/strategy/dca2/open_position.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ 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"
Expand Down Expand Up @@ -33,21 +32,6 @@ func (s *Strategy) placeOpenPositionOrders(ctx context.Context) error {

s.debugOrders(createdOrders)

if s.DevMode != nil && s.DevMode.Enabled && s.DevMode.IsNewAccount {
if len(createdOrders) > 0 {
s.ProfitStats.FromOrderID = createdOrders[0].OrderID
}

for _, createdOrder := range createdOrders {
if s.ProfitStats.FromOrderID > createdOrder.OrderID {
s.ProfitStats.FromOrderID = createdOrder.OrderID
}
}

s.DevMode.IsNewAccount = false
bbgo.Sync(ctx, s)
}

return nil
}

Expand Down
12 changes: 4 additions & 8 deletions pkg/strategy/dca2/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func (s *Strategy) emitNextState(nextState State) {
// TakeProfitReady -> the takeProfit order filled ->
func (s *Strategy) runState(ctx context.Context) {
s.logger.Info("[DCA] runState")
stateTriggerTicker := time.NewTicker(5 * time.Second)
stateTriggerTicker := time.NewTicker(1 * time.Minute)
defer stateTriggerTicker.Stop()

for {
Expand All @@ -83,7 +83,7 @@ func (s *Strategy) runState(ctx context.Context) {
s.logger.Info("[DCA] runState DONE")
return
case <-stateTriggerTicker.C:
// s.logger.Infof("[DCA] triggerNextState current state: %d", s.state)
// move triggerNextState to the end of next state handler, this ticker is used to avoid the state is stopped unexpectedly
s.triggerNextState()
case nextState := <-s.nextStateC:
// next state == current state -> skip
Expand Down Expand Up @@ -120,6 +120,8 @@ func (s *Strategy) runState(ctx context.Context) {
case TakeProfitReady:
s.runTakeProfitReady(ctx, nextState)
}

s.triggerNextState()
}
}
}
Expand Down Expand Up @@ -178,9 +180,6 @@ func (s *Strategy) runOpenPositionReady(_ context.Context, next State) {
func (s *Strategy) runOpenPositionOrderFilled(_ context.Context, next State) {
s.updateState(OpenPositionOrdersCancelling)
s.logger.Info("[State] OpenPositionOrderFilled -> OpenPositionOrdersCancelling")

// after open position cancelling, immediately trigger open position cancelled to cancel the other orders
s.emitNextState(OpenPositionOrdersCancelled)
}

func (s *Strategy) runOpenPositionOrdersCancelling(ctx context.Context, next State) {
Expand All @@ -191,9 +190,6 @@ func (s *Strategy) runOpenPositionOrdersCancelling(ctx context.Context, next Sta
}
s.updateState(OpenPositionOrdersCancelled)
s.logger.Info("[State] OpenPositionOrdersCancelling -> OpenPositionOrdersCancelled")

// after open position cancelled, immediately trigger take profit ready to open take-profit order
s.emitNextState(TakeProfitReady)
}

func (s *Strategy) runOpenPositionOrdersCancelled(ctx context.Context, next State) {
Expand Down
44 changes: 20 additions & 24 deletions pkg/strategy/dca2/strategy.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,6 @@ type Strategy struct {
// UseCancelAllOrdersApiWhenClose uses a different API to cancel all the orders on the market when closing a grid
UseCancelAllOrdersApiWhenClose bool `json:"useCancelAllOrdersApiWhenClose"`

// dev mode
DevMode *DevMode `json:"devMode"`

// log
logger *logrus.Entry
LogFields logrus.Fields `json:"logFields"`
Expand Down Expand Up @@ -179,12 +176,6 @@ func (s *Strategy) Run(ctx context.Context, _ bbgo.OrderExecutor, session *bbgo.
s.Position = types.NewPositionFromMarket(s.Market)
}

// if dev mode is on and it's not a new strategy
if s.DevMode != nil && s.DevMode.Enabled && !s.DevMode.IsNewAccount {
s.ProfitStats = newProfitStats(s.Market, s.QuoteInvestment)
s.Position = types.NewPositionFromMarket(s.Market)
}

// set ttl for persistence
s.Position.SetTTL(s.PersistenceTTL.Duration())
s.ProfitStats.SetTTL(s.PersistenceTTL.Duration())
Expand Down Expand Up @@ -219,7 +210,7 @@ func (s *Strategy) Run(ctx context.Context, _ bbgo.OrderExecutor, session *bbgo.
}

s.OrderExecutor = bbgo.NewGeneralOrderExecutor(session, s.Symbol, ID, instanceID, s.Position)
s.OrderExecutor.SetMaxRetries(10)
s.OrderExecutor.SetMaxRetries(50)
s.OrderExecutor.BindEnvironment(s.Environment)
s.OrderExecutor.Bind()

Expand Down Expand Up @@ -271,23 +262,23 @@ func (s *Strategy) Run(ctx context.Context, _ bbgo.OrderExecutor, session *bbgo.
})

session.MarketDataStream.OnKLine(func(kline types.KLine) {
// check price here
if s.state != OpenPositionOrderFilled {
return
}
switch s.state {
case OpenPositionOrderFilled:
if s.takeProfitPrice.IsZero() {
s.logger.Warn("take profit price should not be 0 when there is at least one open-position order filled, please check it")
return
}

if s.takeProfitPrice.IsZero() {
s.logger.Warn("take profit price should not be 0 when there is at least one open-position order filled, please check it")
return
}
compRes := kline.Close.Compare(s.takeProfitPrice)
// price doesn't hit the take profit price
if compRes < 0 {
return
}

compRes := kline.Close.Compare(s.takeProfitPrice)
// price doesn't hit the take profit price
if compRes < 0 {
s.emitNextState(OpenPositionOrdersCancelling)
default:
return
}

s.emitNextState(OpenPositionOrdersCancelling)
})

session.UserDataStream.OnAuth(func() {
Expand All @@ -298,7 +289,7 @@ func (s *Strategy) Run(ctx context.Context, _ bbgo.OrderExecutor, session *bbgo.
// no need to recover when two situation
// 1. recoverWhenStart is false
// 2. dev mode is on and it's not new strategy
if !s.RecoverWhenStart || (s.DevMode != nil && s.DevMode.Enabled && !s.DevMode.IsNewAccount) {
if !s.RecoverWhenStart {
s.updateState(WaitToOpenPosition)
} else {
// recover
Expand Down Expand Up @@ -343,6 +334,11 @@ func (s *Strategy) Run(ctx context.Context, _ bbgo.OrderExecutor, session *bbgo.
// start to sync periodically
go s.syncPeriodically(ctx)

// try to trigger position opening immediately
if s.state == WaitToOpenPosition {
s.emitNextState(PositionOpening)
}

// start running state machine
s.runState(ctx)
}
Expand Down

0 comments on commit e86dece

Please sign in to comment.