Skip to content

Commit 612df45

Browse files
authored
Merge pull request #750 from c9s/refactor/persistence-singleton
refactor: persistence singleton and improve backtest cancel performance
2 parents 9b82de5 + 19d8013 commit 612df45

File tree

5 files changed

+47
-28
lines changed

5 files changed

+47
-28
lines changed

pkg/bbgo/activeorderbook.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,14 @@ func (b *ActiveOrderBook) waitAllClear(ctx context.Context, waitTime, timeout ti
6969

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

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

7681
startTime := time.Now()
7782
// ensure every order is cancelled

pkg/bbgo/environment.go

+27-19
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,16 @@ func init() {
3737
rand.Seed(time.Now().UnixNano())
3838
}
3939

40+
// IsBackTesting is a global variable that indicates the current environment is back-test or not.
41+
var IsBackTesting = false
42+
43+
var BackTestService *service.BacktestService
44+
45+
func SetBackTesting(s *service.BacktestService) {
46+
BackTestService = s
47+
IsBackTesting = true
48+
}
49+
4050
var LoadedExchangeStrategies = make(map[string]SingleExchangeStrategy)
4151
var LoadedCrossExchangeStrategies = make(map[string]CrossExchangeStrategy)
4252

@@ -69,19 +79,18 @@ const (
6979

7080
// Environment presents the real exchange data layer
7181
type Environment struct {
72-
PersistenceServiceFacade *service.PersistenceServiceFacade
73-
DatabaseService *service.DatabaseService
74-
OrderService *service.OrderService
75-
TradeService *service.TradeService
76-
ProfitService *service.ProfitService
77-
PositionService *service.PositionService
78-
BacktestService *service.BacktestService
79-
RewardService *service.RewardService
80-
MarginService *service.MarginService
81-
SyncService *service.SyncService
82-
AccountService *service.AccountService
83-
WithdrawService *service.WithdrawService
84-
DepositService *service.DepositService
82+
DatabaseService *service.DatabaseService
83+
OrderService *service.OrderService
84+
TradeService *service.TradeService
85+
ProfitService *service.ProfitService
86+
PositionService *service.PositionService
87+
BacktestService *service.BacktestService
88+
RewardService *service.RewardService
89+
MarginService *service.MarginService
90+
SyncService *service.SyncService
91+
AccountService *service.AccountService
92+
WithdrawService *service.WithdrawService
93+
DepositService *service.DepositService
8594

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

109118
syncStatus: SyncNotStarted,
110-
PersistenceServiceFacade: &service.PersistenceServiceFacade{
111-
Memory: service.NewMemoryService(),
112-
},
113119
}
114120
}
115121

@@ -276,7 +282,8 @@ func (environ *Environment) ConfigurePersistence(conf *PersistenceConfig) error
276282
return err
277283
}
278284

279-
environ.PersistenceServiceFacade.Redis = service.NewRedisPersistenceService(conf.Redis)
285+
redisPersistence := service.NewRedisPersistenceService(conf.Redis)
286+
PersistenceServiceFacade.Redis = redisPersistence
280287
}
281288

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

290-
environ.PersistenceServiceFacade.Json = &service.JsonPersistenceService{Directory: conf.Json.Directory}
297+
jsonPersistence := &service.JsonPersistenceService{Directory: conf.Json.Directory}
298+
PersistenceServiceFacade.Json = jsonPersistence
291299
}
292300

293301
return nil
@@ -772,7 +780,7 @@ func (environ *Environment) ConfigureNotificationSystem(userConfig *Config) erro
772780
}
773781
}
774782

775-
var persistence = environ.PersistenceServiceFacade.Get()
783+
var persistence = PersistenceServiceFacade.Get()
776784

777785
err := environ.setupInteraction(persistence)
778786
if err != nil {

pkg/bbgo/persistence.go

+6
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ type PersistenceSelector struct {
1717
Type string `json:"type" yaml:"type"`
1818
}
1919

20+
var DefaultPersistenceServiceFacade = &service.PersistenceServiceFacade{
21+
Memory: service.NewMemoryService(),
22+
}
23+
24+
var PersistenceServiceFacade = DefaultPersistenceServiceFacade
25+
2026
// Persistence is used for strategy to inject the persistence.
2127
type Persistence struct {
2228
PersistenceSelector *PersistenceSelector `json:"persistence,omitempty" yaml:"persistence,omitempty"`

pkg/bbgo/trader.go

+7-8
Original file line numberDiff line numberDiff line change
@@ -327,11 +327,11 @@ func (trader *Trader) LoadState() error {
327327
return nil
328328
}
329329

330-
if trader.environment.PersistenceServiceFacade == nil {
330+
if PersistenceServiceFacade == nil {
331331
return nil
332332
}
333333

334-
ps := trader.environment.PersistenceServiceFacade.Get()
334+
ps := PersistenceServiceFacade.Get()
335335

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

@@ -364,11 +364,11 @@ func (trader *Trader) SaveState() error {
364364
return nil
365365
}
366366

367-
if trader.environment.PersistenceServiceFacade == nil {
367+
if PersistenceServiceFacade == nil {
368368
return nil
369369
}
370370

371-
ps := trader.environment.PersistenceServiceFacade.Get()
371+
ps := PersistenceServiceFacade.Get()
372372

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

389389
func (trader *Trader) injectCommonServices(s interface{}) error {
390-
persistenceFacade := trader.environment.PersistenceServiceFacade
391390
persistence := &Persistence{
392391
PersistenceSelector: defaultPersistenceSelector,
393-
Facade: persistenceFacade,
392+
Facade: PersistenceServiceFacade,
394393
}
395394

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

407-
if err := injectField(elem, "Facade", persistenceFacade, true); err != nil {
406+
if err := injectField(elem, "Facade", PersistenceServiceFacade, true); err != nil {
408407
return err
409408
}
410409

@@ -426,6 +425,6 @@ func (trader *Trader) injectCommonServices(s interface{}) error {
426425
trader.environment.AccountService,
427426
trader.environment,
428427
persistence,
429-
persistenceFacade, // if the strategy use persistence facade separately
428+
PersistenceServiceFacade, // if the strategy use persistence facade separately
430429
)
431430
}

pkg/cmd/backtest.go

+1
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ var BacktestCmd = &cobra.Command{
160160

161161
backtestService := &service.BacktestService{DB: environ.DatabaseService.DB}
162162
environ.BacktestService = backtestService
163+
bbgo.SetBackTesting(backtestService)
163164

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

0 commit comments

Comments
 (0)