Merge pull request #750 from c9s/refactor/persistence-singleton

refactor: persistence singleton and improve backtest cancel performance
This commit is contained in:
Yo-An Lin 2022-06-21 14:01:14 +08:00 committed by GitHub
commit 612df45c5e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 47 additions and 28 deletions

View File

@ -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

View File

@ -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)
@ -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
@ -107,9 +116,6 @@ func NewEnvironment() *Environment {
startTime: now,
syncStatus: SyncNotStarted,
PersistenceServiceFacade: &service.PersistenceServiceFacade{
Memory: service.NewMemoryService(),
},
}
}
@ -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 {
@ -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
@ -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 {

View File

@ -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"`

View File

@ -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...")
@ -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 {
@ -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:
@ -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
}
@ -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
)
}

View File

@ -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}