unmarshal imports into config

This commit is contained in:
c9s 2020-10-23 14:49:54 +08:00
parent e1e8a16f97
commit cd28fb8771
3 changed files with 90 additions and 74 deletions

View File

@ -2,7 +2,6 @@ package bbgo
import ( import (
"context" "context"
"time"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/robfig/cron/v3" "github.com/robfig/cron/v3"
@ -96,7 +95,6 @@ func (reporter *AverageCostPnLReporter) Run() {
for _, sessionName := range reporter.Sessions { for _, sessionName := range reporter.Sessions {
session := reporter.environment.sessions[sessionName] session := reporter.environment.sessions[sessionName]
calculator := &pnl.AverageCostCalculator{ calculator := &pnl.AverageCostCalculator{
StartTime: time.Time{},
TradingFeeCurrency: session.Exchange.PlatformFeeCurrency(), TradingFeeCurrency: session.Exchange.PlatformFeeCurrency(),
} }

View File

@ -24,9 +24,60 @@ func init() {
RootCmd.AddCommand(RunCmd) RootCmd.AddCommand(RunCmd)
} }
func runConfig(ctx context.Context, configFile string) error {
userConfig, err := config.Load(configFile)
if err != nil {
return err
}
slackToken := viper.GetString("slack-token")
if len(slackToken) == 0 {
return errSlackTokenUndefined
}
logrus.AddHook(slacklog.NewLogHook(slackToken, viper.GetString("slack-error-channel")))
var notifier = slacknotifier.New(slackToken, viper.GetString("slack-channel"))
db, err := cmdutil.ConnectMySQL()
if err != nil {
return err
}
environ := bbgo.NewDefaultEnvironment(db)
environ.ReportTrade(notifier)
trader := bbgo.NewTrader(environ)
for _, entry := range userConfig.ExchangeStrategies {
for _, mount := range entry.Mounts {
logrus.Infof("attaching strategy %T on %s...", entry.Strategy, mount)
trader.AttachStrategyOn(mount, entry.Strategy)
}
}
for _, strategy := range userConfig.CrossExchangeStrategies {
logrus.Infof("attaching strategy %T", strategy)
trader.AttachCrossExchangeStrategy(strategy)
}
for _, report := range userConfig.PnLReporters {
if len(report.AverageCostBySymbols) > 0 {
trader.ReportPnL(notifier).
AverageCostBySymbols(report.AverageCostBySymbols...).
Of(report.Of...).
When(report.When...)
} else {
return errors.Errorf("unsupported PnL reporter: %+v", report)
}
}
return trader.Run(ctx)
}
var RunCmd = &cobra.Command{ var RunCmd = &cobra.Command{
Use: "run", Use: "run",
Short: "run strategies", Short: "run strategies from config file",
// SilenceUsage is an option to silence usage when an error occurs. // SilenceUsage is an option to silence usage when an error occurs.
SilenceUsage: true, SilenceUsage: true,
@ -38,63 +89,13 @@ var RunCmd = &cobra.Command{
} }
if len(configFile) == 0 { if len(configFile) == 0 {
return errors.New("--config option is not given") return errors.New("--config option is required")
}
userConfig, err := config.Load(configFile)
if err != nil {
return err
} }
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
defer cancel() defer cancel()
slackToken := viper.GetString("slack-token") err = runConfig(ctx, configFile)
if len(slackToken) == 0 {
return errSlackTokenUndefined
}
logrus.AddHook(slacklog.NewLogHook(slackToken, viper.GetString("slack-error-channel")))
var notifier = slacknotifier.New(slackToken, viper.GetString("slack-channel"))
db, err := cmdutil.ConnectMySQL()
if err != nil {
return err
}
environ := bbgo.NewDefaultEnvironment(db)
environ.ReportTrade(notifier)
trader := bbgo.NewTrader(environ)
for _, entry := range userConfig.ExchangeStrategies {
for _, mount := range entry.Mounts {
logrus.Infof("attaching strategy %T on %s...", entry.Strategy, mount)
trader.AttachStrategyOn(mount, entry.Strategy)
}
}
for _, strategy := range userConfig.CrossExchangeStrategies {
logrus.Infof("attaching strategy %T", strategy)
trader.AttachCrossExchangeStrategy(strategy)
}
for _, report := range userConfig.PnLReporters {
if len(report.AverageCostBySymbols) > 0 {
trader.ReportPnL(notifier).
AverageCostBySymbols(report.AverageCostBySymbols...).
Of(report.Of...).
When(report.When...)
} else {
return errors.Errorf("unsupported PnL reporter: %+v", report)
}
}
err = trader.Run(ctx)
if err != nil {
return err
}
cmdutil.WaitForSignal(ctx, syscall.SIGINT, syscall.SIGTERM) cmdutil.WaitForSignal(ctx, syscall.SIGINT, syscall.SIGTERM)
return err return err

View File

@ -67,28 +67,32 @@ type Config struct {
type Stash map[string]interface{} type Stash map[string]interface{}
func loadStash(configFile string) (Stash, error) { func loadStash(config []byte) (Stash, error) {
config, err := ioutil.ReadFile(configFile)
if err != nil {
return nil, err
}
stash := make(Stash) stash := make(Stash)
if err := yaml.Unmarshal(config, stash); err != nil { if err := yaml.Unmarshal(config, stash); err != nil {
return nil, err return nil, err
} }
return stash, err return stash, nil
} }
func Load(configFile string) (*Config, error) { func Load(configFile string) (*Config, error) {
var config Config var config Config
stash, err := loadStash(configFile) content, err := ioutil.ReadFile(configFile)
if err != nil { if err != nil {
return nil, err return nil, err
} }
stash, err := loadStash(content)
if err != nil {
return nil, err
}
if err := loadImports(&config, stash); err != nil {
return nil, err
}
if err := loadExchangeStrategies(&config, stash); err != nil { if err := loadExchangeStrategies(&config, stash); err != nil {
return nil, err return nil, err
} }
@ -104,6 +108,21 @@ func Load(configFile string) (*Config, error) {
return &config, nil return &config, nil
} }
func loadImports(config *Config, stash Stash) error {
importStash, ok := stash["imports"]
if !ok {
return nil
}
imports, err := reUnmarshal(importStash, &config.Imports)
if err != nil {
return err
}
config.Imports = *imports.(*[]string)
return nil
}
func loadReportPnL(config *Config, stash Stash) error { func loadReportPnL(config *Config, stash Stash) error {
reporterStash, ok := stash["reportPnL"] reporterStash, ok := stash["reportPnL"]
if !ok { if !ok {
@ -120,16 +139,16 @@ func loadReportPnL(config *Config, stash Stash) error {
} }
func loadCrossExchangeStrategies(config *Config, stash Stash) (err error) { func loadCrossExchangeStrategies(config *Config, stash Stash) (err error) {
if len(bbgo.LoadedCrossExchangeStrategies) == 0 {
return errors.New("no cross exchange strategy is registered")
}
exchangeStrategiesConf, ok := stash["crossExchangeStrategies"] exchangeStrategiesConf, ok := stash["crossExchangeStrategies"]
if !ok { if !ok {
return nil return nil
} }
if len(bbgo.LoadedCrossExchangeStrategies) == 0 {
return errors.New("no cross exchange strategy is registered")
}
configList, ok := exchangeStrategiesConf.([]interface{}) configList, ok := exchangeStrategiesConf.([]interface{})
if !ok { if !ok {
return errors.New("expecting list in crossExchangeStrategies") return errors.New("expecting list in crossExchangeStrategies")
@ -158,21 +177,20 @@ func loadCrossExchangeStrategies(config *Config, stash Stash) (err error) {
} }
func loadExchangeStrategies(config *Config, stash Stash) (err error) { func loadExchangeStrategies(config *Config, stash Stash) (err error) {
if len(bbgo.LoadedExchangeStrategies) == 0 {
return errors.New("no exchange strategy is registered")
}
exchangeStrategiesConf, ok := stash["exchangeStrategies"] exchangeStrategiesConf, ok := stash["exchangeStrategies"]
if !ok { if !ok {
return nil return nil
} }
if len(bbgo.LoadedExchangeStrategies) == 0 {
return errors.New("no exchange strategy is registered")
}
configList, ok := exchangeStrategiesConf.([]interface{}) configList, ok := exchangeStrategiesConf.([]interface{})
if !ok { if !ok {
return errors.New("expecting list in exchangeStrategies") return errors.New("expecting list in exchangeStrategies")
} }
for _, entry := range configList { for _, entry := range configList {
configStash, ok := entry.(Stash) configStash, ok := entry.(Stash)
if !ok { if !ok {
@ -188,7 +206,6 @@ func loadExchangeStrategies(config *Config, stash Stash) (err error) {
} }
} }
for id, conf := range configStash { for id, conf := range configStash {
// look up the real struct type // look up the real struct type
if st, ok := bbgo.LoadedExchangeStrategies[id]; ok { if st, ok := bbgo.LoadedExchangeStrategies[id]; ok {