Skip to content
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

refactor: persistence singleton and improve backtest cancel performance #750

Merged
merged 2 commits into from
Jun 21, 2022
Merged
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
7 changes: 6 additions & 1 deletion pkg/bbgo/activeorderbook.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,14 @@ func (b *ActiveOrderBook) waitAllClear(ctx context.Context, waitTime, timeout ti

// GracefulCancel cancels the active orders gracefully
func (b *ActiveOrderBook) GracefulCancel(ctx context.Context, ex types.Exchange) error {
waitTime := CancelOrderWaitTime
// optimize order cancel for back-testing
if IsBackTesting {
orders := b.Orders()
return ex.CancelOrders(context.Background(), orders...)
}

log.Debugf("[ActiveOrderBook] gracefully cancelling %s orders...", b.Symbol)
waitTime := CancelOrderWaitTime

startTime := time.Now()
// ensure every order is cancelled
Expand Down
46 changes: 27 additions & 19 deletions pkg/bbgo/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@ func init() {
rand.Seed(time.Now().UnixNano())
}

// IsBackTesting is a global variable that indicates the current environment is back-test or not.
var IsBackTesting = false

var BackTestService *service.BacktestService

func SetBackTesting(s *service.BacktestService) {
BackTestService = s
IsBackTesting = true
}

var LoadedExchangeStrategies = make(map[string]SingleExchangeStrategy)
var LoadedCrossExchangeStrategies = make(map[string]CrossExchangeStrategy)

Expand Down Expand Up @@ -69,19 +79,18 @@ const (

// Environment presents the real exchange data layer
type Environment struct {
PersistenceServiceFacade *service.PersistenceServiceFacade
DatabaseService *service.DatabaseService
OrderService *service.OrderService
TradeService *service.TradeService
ProfitService *service.ProfitService
PositionService *service.PositionService
BacktestService *service.BacktestService
RewardService *service.RewardService
MarginService *service.MarginService
SyncService *service.SyncService
AccountService *service.AccountService
WithdrawService *service.WithdrawService
DepositService *service.DepositService
DatabaseService *service.DatabaseService
OrderService *service.OrderService
TradeService *service.TradeService
ProfitService *service.ProfitService
PositionService *service.PositionService
BacktestService *service.BacktestService
RewardService *service.RewardService
MarginService *service.MarginService
SyncService *service.SyncService
AccountService *service.AccountService
WithdrawService *service.WithdrawService
DepositService *service.DepositService

// startTime is the time of start point (which is used in the backtest)
startTime time.Time
Expand All @@ -107,9 +116,6 @@ func NewEnvironment() *Environment {
startTime: now,

syncStatus: SyncNotStarted,
PersistenceServiceFacade: &service.PersistenceServiceFacade{
Memory: service.NewMemoryService(),
},
}
}

Expand Down Expand Up @@ -276,7 +282,8 @@ func (environ *Environment) ConfigurePersistence(conf *PersistenceConfig) error
return err
}

environ.PersistenceServiceFacade.Redis = service.NewRedisPersistenceService(conf.Redis)
redisPersistence := service.NewRedisPersistenceService(conf.Redis)
PersistenceServiceFacade.Redis = redisPersistence
}

if conf.Json != nil {
Expand All @@ -287,7 +294,8 @@ func (environ *Environment) ConfigurePersistence(conf *PersistenceConfig) error
}
}

environ.PersistenceServiceFacade.Json = &service.JsonPersistenceService{Directory: conf.Json.Directory}
jsonPersistence := &service.JsonPersistenceService{Directory: conf.Json.Directory}
PersistenceServiceFacade.Json = jsonPersistence
}

return nil
Expand Down Expand Up @@ -772,7 +780,7 @@ func (environ *Environment) ConfigureNotificationSystem(userConfig *Config) erro
}
}

var persistence = environ.PersistenceServiceFacade.Get()
var persistence = PersistenceServiceFacade.Get()

err := environ.setupInteraction(persistence)
if err != nil {
Expand Down
6 changes: 6 additions & 0 deletions pkg/bbgo/persistence.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ type PersistenceSelector struct {
Type string `json:"type" yaml:"type"`
}

var DefaultPersistenceServiceFacade = &service.PersistenceServiceFacade{
Memory: service.NewMemoryService(),
}

var PersistenceServiceFacade = DefaultPersistenceServiceFacade

// Persistence is used for strategy to inject the persistence.
type Persistence struct {
PersistenceSelector *PersistenceSelector `json:"persistence,omitempty" yaml:"persistence,omitempty"`
Expand Down
15 changes: 7 additions & 8 deletions pkg/bbgo/trader.go
Original file line number Diff line number Diff line change
Expand Up @@ -327,11 +327,11 @@ func (trader *Trader) LoadState() error {
return nil
}

if trader.environment.PersistenceServiceFacade == nil {
if PersistenceServiceFacade == nil {
return nil
}

ps := trader.environment.PersistenceServiceFacade.Get()
ps := PersistenceServiceFacade.Get()

log.Infof("loading strategies states...")

Expand Down Expand Up @@ -364,11 +364,11 @@ func (trader *Trader) SaveState() error {
return nil
}

if trader.environment.PersistenceServiceFacade == nil {
if PersistenceServiceFacade == nil {
return nil
}

ps := trader.environment.PersistenceServiceFacade.Get()
ps := PersistenceServiceFacade.Get()

log.Infof("saving strategies states...")
return trader.IterateStrategies(func(strategy StrategyID) error {
Expand All @@ -387,10 +387,9 @@ var defaultPersistenceSelector = &PersistenceSelector{
}

func (trader *Trader) injectCommonServices(s interface{}) error {
persistenceFacade := trader.environment.PersistenceServiceFacade
persistence := &Persistence{
PersistenceSelector: defaultPersistenceSelector,
Facade: persistenceFacade,
Facade: PersistenceServiceFacade,
}

// a special injection for persistence selector:
Expand All @@ -404,7 +403,7 @@ func (trader *Trader) injectCommonServices(s interface{}) error {
return fmt.Errorf("field Persistence is not a struct element, %s given", field)
}

if err := injectField(elem, "Facade", persistenceFacade, true); err != nil {
if err := injectField(elem, "Facade", PersistenceServiceFacade, true); err != nil {
return err
}

Expand All @@ -426,6 +425,6 @@ func (trader *Trader) injectCommonServices(s interface{}) error {
trader.environment.AccountService,
trader.environment,
persistence,
persistenceFacade, // if the strategy use persistence facade separately
PersistenceServiceFacade, // if the strategy use persistence facade separately
)
}
1 change: 1 addition & 0 deletions pkg/cmd/backtest.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ var BacktestCmd = &cobra.Command{

backtestService := &service.BacktestService{DB: environ.DatabaseService.DB}
environ.BacktestService = backtestService
bbgo.SetBackTesting(backtestService)

if len(sessionName) > 0 {
userConfig.Backtest.Sessions = []string{sessionName}
Expand Down