diff --git a/cmd/run.go b/cmd/run.go new file mode 100644 index 000000000..cf3d94d61 --- /dev/null +++ b/cmd/run.go @@ -0,0 +1,84 @@ +package cmd + +import ( + "context" + "syscall" + + "github.com/pkg/errors" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/spf13/viper" + + "github.com/c9s/bbgo/cmd/cmdutil" + "github.com/c9s/bbgo/pkg/bbgo" + "github.com/c9s/bbgo/pkg/config" + "github.com/c9s/bbgo/pkg/slack/slacklog" +) + +var errSlackTokenUndefined = errors.New("slack token is not defined.") + +func init() { + runCmd.Flags().String("config", "", "strategy config file") + runCmd.Flags().String("since", "", "pnl since time") + RootCmd.AddCommand(runCmd) +} + +var runCmd = &cobra.Command{ + Use: "run", + Short: "run strategies", + + // SilenceUsage is an option to silence usage when an error occurs. + SilenceUsage: true, + + RunE: func(cmd *cobra.Command, args []string) error { + configFile, err := cmd.Flags().GetString("config") + if err != nil { + return err + } + + if len(configFile) == 0 { + return errors.New("--config option is not given") + } + + userConfig, err := config.Load(configFile) + if err != nil { + return err + } + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + slackToken := viper.GetString("slack-token") + if len(slackToken) == 0 { + return errSlackTokenUndefined + } + + log.AddHook(slacklog.NewLogHook(slackToken, viper.GetString("slack-error-channel"))) + + db, err := cmdutil.ConnectMySQL() + if err != nil { + return err + } + + environ := bbgo.NewDefaultEnvironment(db) + trader := bbgo.NewTrader(environ) + + for _, entry := range userConfig.ExchangeStrategies { + for _, mount := range entry.Mounts { + trader.AttachStrategyOn(mount, entry.Strategy) + } + } + + for _, strategy := range userConfig.CrossExchangeStrategies { + trader.AttachCrossExchangeStrategy(strategy) + } + + err = trader.Run(ctx) + if err != nil { + return err + } + + cmdutil.WaitForSignal(ctx, syscall.SIGINT, syscall.SIGTERM) + return err + }, +}