bbgo: improve dynamic injection

This commit is contained in:
c9s 2022-03-05 02:51:43 +08:00
parent db4d8a31bc
commit fa7bab2c3a
2 changed files with 43 additions and 49 deletions

View File

@ -219,6 +219,16 @@ func (trader *Trader) RunSingleExchangeStrategy(ctx context.Context, strategy Si
return errors.New("strategy object is not a struct")
}
if err := parseStructAndInject(strategy,
&trader.Graceful,
&trader.logger,
trader.environment.Notifiability,
trader.environment.TradeService,
trader.environment.AccountService,
) ; err != nil {
return err
}
if err := trader.injectCommonServices(rs); err != nil {
return err
}
@ -229,36 +239,24 @@ func (trader *Trader) RunSingleExchangeStrategy(ctx context.Context, strategy Si
if symbol, ok := isSymbolBasedStrategy(rs); ok {
log.Infof("found symbol based strategy from %s", rs.Type())
if _, ok := hasField(rs, "Market"); ok {
if market, ok := session.Market(symbol); ok {
// let's make the market object passed by pointer
if err := injectField(rs, "Market", &market, false); err != nil {
return errors.Wrapf(err, "failed to inject Market on %T", strategy)
}
}
market, ok := session.Market(symbol)
if !ok {
return fmt.Errorf("market of symbol %s not found", symbol)
}
// StandardIndicatorSet
if _, ok := hasField(rs, "StandardIndicatorSet"); ok {
indicatorSet, ok := session.StandardIndicatorSet(symbol)
if !ok {
return fmt.Errorf("standardIndicatorSet of symbol %s not found", symbol)
}
if err := injectField(rs, "StandardIndicatorSet", indicatorSet, true); err != nil {
return errors.Wrapf(err, "failed to inject StandardIndicatorSet on %T", strategy)
}
indicatorSet, ok := session.StandardIndicatorSet(symbol)
if !ok {
return fmt.Errorf("standardIndicatorSet of symbol %s not found", symbol)
}
if _, ok := hasField(rs, "MarketDataStore"); ok {
store, ok := session.MarketDataStore(symbol)
if !ok {
return fmt.Errorf("marketDataStore of symbol %s not found", symbol)
}
store, ok := session.MarketDataStore(symbol)
if !ok {
return fmt.Errorf("marketDataStore of symbol %s not found", symbol)
}
if err := injectField(rs, "MarketDataStore", store, true); err != nil {
return errors.Wrapf(err, "failed to inject MarketDataStore on %T", strategy)
}
if err := parseStructAndInject(strategy, market, indicatorSet, store) ; err != nil {
return errors.Wrapf(err, "failed to inject object into %T", strategy)
}
}
@ -357,30 +355,6 @@ func (trader *Trader) Run(ctx context.Context) error {
}
func (trader *Trader) injectCommonServices(rs reflect.Value) error {
if err := injectField(rs, "Graceful", &trader.Graceful, true); err != nil {
return errors.Wrap(err, "failed to inject Graceful")
}
if err := injectField(rs, "Logger", &trader.logger, false); err != nil {
return errors.Wrap(err, "failed to inject Logger")
}
if err := injectField(rs, "Notifiability", &trader.environment.Notifiability, false); err != nil {
return errors.Wrap(err, "failed to inject Notifiability")
}
if trader.environment.TradeService != nil {
if err := injectField(rs, "TradeService", trader.environment.TradeService, true); err != nil {
return errors.Wrap(err, "failed to inject TradeService")
}
}
if trader.environment.AccountService != nil {
if err := injectField(rs, "AccountService", trader.environment.AccountService, true); err != nil {
return errors.Wrap(err, "failed to inject AccountService")
}
}
if field, ok := hasField(rs, "Persistence"); ok {
if trader.environment.PersistenceServiceFacade == nil {
log.Warnf("strategy has Persistence field but persistence service is not defined")
@ -439,6 +413,10 @@ func parseStructAndInject(f interface{}, objects ...interface{}) error {
case reflect.Ptr, reflect.Struct:
for oi := 0; oi < len(objects); oi++ {
obj := objects[oi]
if obj == nil {
continue
}
ot := reflect.TypeOf(obj)
if ft.AssignableTo(ot) {
if !fv.CanSet() {
@ -451,6 +429,10 @@ func parseStructAndInject(f interface{}, objects ...interface{}) error {
case reflect.Interface:
for oi := 0; oi < len(objects); oi++ {
obj := objects[oi]
if obj == nil {
continue
}
objT := reflect.TypeOf(obj)
log.Debugln(
ft.PkgPath(),

View File

@ -10,6 +10,18 @@ import (
)
func Test_parseStructAndInject(t *testing.T) {
t.Run("skip nil", func(t *testing.T) {
ss := struct {
a int
Env *Environment
}{
a: 1,
Env: nil,
}
err := parseStructAndInject(&ss, nil)
assert.NoError(t, err)
assert.Nil(t, ss.Env)
})
t.Run("pointer", func(t *testing.T) {
ss := struct {
a int