cmd

package
v1.30.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 15, 2022 License: MIT Imports: 61 Imported by: 10

Documentation

Index

Constants

This section is empty.

Variables

View Source
var BacktestCmd = &cobra.Command{
	Use:          "backtest",
	Short:        "backtest your strategies",
	SilenceUsage: true,
	RunE: func(cmd *cobra.Command, args []string) error {
		verboseCnt, err := cmd.Flags().GetCount("verbose")
		if err != nil {
			return err
		}

		if viper.GetBool("debug") {
			verboseCnt = 2
		}

		configFile, err := cmd.Flags().GetString("config")
		if err != nil {
			return err
		}

		if len(configFile) == 0 {
			return errors.New("--config option is required")
		}

		wantBaseAssetBaseline, err := cmd.Flags().GetBool("base-asset-baseline")
		if err != nil {
			return err
		}

		wantSync, err := cmd.Flags().GetBool("sync")
		if err != nil {
			return err
		}

		force, err := cmd.Flags().GetBool("force")
		if err != nil {
			return err
		}

		outputDirectory, err := cmd.Flags().GetString("output")
		if err != nil {
			return err
		}

		jsonOutputEnabled := len(outputDirectory) > 0

		syncOnly, err := cmd.Flags().GetBool("sync-only")
		if err != nil {
			return err
		}

		syncFromDateStr, err := cmd.Flags().GetString("sync-from")
		if err != nil {
			return err
		}

		shouldVerify, err := cmd.Flags().GetBool("verify")
		if err != nil {
			return err
		}

		userConfig, err := bbgo.Load(configFile, true)
		if err != nil {
			return err
		}

		if verboseCnt == 2 {
			log.SetLevel(log.DebugLevel)
		} else if verboseCnt > 0 {
			log.SetLevel(log.InfoLevel)
		} else {

			log.SetLevel(log.ErrorLevel)
		}

		if userConfig.Backtest == nil {
			return errors.New("backtest config is not defined")
		}

		ctx, cancel := context.WithCancel(context.Background())
		defer cancel()

		var now = time.Now()
		var startTime, endTime time.Time

		startTime = userConfig.Backtest.StartTime.Time()

		if userConfig.Backtest.EndTime != nil {
			endTime = userConfig.Backtest.EndTime.Time()
		} else {
			endTime = now
		}
		_ = endTime

		log.Infof("starting backtest with startTime %s", startTime.Format(time.ANSIC))

		environ := bbgo.NewEnvironment()
		if err := BootstrapBacktestEnvironment(ctx, environ, userConfig); err != nil {
			return err
		}

		if environ.DatabaseService == nil {
			return errors.New("database service is not enabled, please check your environment variables DB_DRIVER and DB_DSN")
		}

		backtestService := &service.BacktestService{DB: environ.DatabaseService.DB}
		environ.BacktestService = backtestService

		var sourceExchanges = make(map[types.ExchangeName]types.Exchange)
		if len(userConfig.Backtest.Sessions) > 0 {
			for _, name := range userConfig.Backtest.Sessions {
				exName, err := types.ValidExchangeName(name)
				if err != nil {
					return err
				}

				publicExchange, err := cmdutil.NewExchangePublic(exName)
				if err != nil {
					return err
				}
				sourceExchanges[exName] = publicExchange
			}
		} else {
			for _, exName := range types.SupportedExchanges {
				publicExchange, err := cmdutil.NewExchangePublic(exName)
				if err != nil {
					return err
				}
				sourceExchanges[exName] = publicExchange
			}
		}

		if wantSync {
			var syncFromTime time.Time

			if len(syncFromDateStr) > 0 {
				syncFromTime, err = time.Parse(types.DateFormat, syncFromDateStr)
				if err != nil {
					return err
				}

				if syncFromTime.After(startTime) {
					return fmt.Errorf("sync-from time %s can not be latter than the backtest start time %s", syncFromTime, startTime)
				}
			} else {

				syncFromTime = startTime.AddDate(0, -1, 0)
				log.Infof("adjusted sync start time %s to %s for backward market data", startTime, syncFromTime)
			}

			log.Infof("starting synchronization: %v", userConfig.Backtest.Symbols)
			for _, symbol := range userConfig.Backtest.Symbols {

				for _, sourceExchange := range sourceExchanges {
					exCustom, ok := sourceExchange.(types.CustomIntervalProvider)

					var supportIntervals map[types.Interval]int
					if ok {
						supportIntervals = exCustom.SupportedInterval()
					} else {
						supportIntervals = types.SupportedIntervals
					}

					for interval := range supportIntervals {

						firstKLine, err := backtestService.QueryFirstKLine(sourceExchange.Name(), symbol, interval)
						if err != nil {
							return errors.Wrapf(err, "failed to query backtest kline")
						}

						if firstKLine != nil {
							if err := backtestService.SyncExist(ctx, sourceExchange, symbol, syncFromTime, time.Now(), interval); err != nil {
								return err
							}
						} else {
							if err := backtestService.Sync(ctx, sourceExchange, symbol, syncFromTime, time.Now(), interval); err != nil {
								return err
							}
						}
					}
				}
			}
			log.Info("synchronization done")

			for _, sourceExchange := range sourceExchanges {
				if shouldVerify {
					err2, done := backtestService.Verify(userConfig.Backtest.Symbols, startTime, time.Now(), sourceExchange, verboseCnt)
					if done {
						return err2
					}
				}
			}

			if syncOnly {
				return nil
			}
		}

		if userConfig.Backtest.RecordTrades {
			log.Warn("!!! Trade recording is enabled for back-testing !!!")
			log.Warn("!!! To run back-testing, you should use an isolated database for storing back-testing trades !!!")
			log.Warn("!!! The trade record in the current database WILL ALL BE DELETED BEFORE THIS BACK-TESTING !!!")
			if !force {
				if !confirmation("Are you sure to continue?") {
					return nil
				}
			}

			if err := environ.TradeService.DeleteAll(); err != nil {
				return err
			}
		}

		environ.SetStartTime(startTime)

		for name, sourceExchange := range sourceExchanges {
			backtestExchange, err := backtest.NewExchange(sourceExchange.Name(), sourceExchange, backtestService, userConfig.Backtest)
			if err != nil {
				return errors.Wrap(err, "failed to create backtest exchange")
			}
			environ.AddExchange(name.String(), backtestExchange)
		}

		if err := environ.Init(ctx); err != nil {
			return err
		}

		trader := bbgo.NewTrader(environ)
		if verboseCnt == 0 {
			trader.DisableLogging()
		}

		if err := trader.Configure(userConfig); err != nil {
			return err
		}

		if err := trader.Run(ctx); err != nil {
			return err
		}

		type KChanEx struct {
			KChan    chan types.KLine
			Exchange *backtest.Exchange
		}
		for _, session := range environ.Sessions() {
			backtestExchange := session.Exchange.(*backtest.Exchange)
			backtestExchange.InitMarketData()
		}

		var klineChans []KChanEx
		for _, session := range environ.Sessions() {
			exchange := session.Exchange.(*backtest.Exchange)
			c, err := exchange.GetMarketData()
			if err != nil {
				return err
			}
			klineChans = append(klineChans, KChanEx{KChan: c, Exchange: exchange})
		}

		runCtx, cancelRun := context.WithCancel(ctx)
		go func() {
			defer cancelRun()
			for {
				count := len(klineChans)
				for _, kchanex := range klineChans {
					kLine, more := <-kchanex.KChan
					if more {
						kchanex.Exchange.ConsumeKLine(kLine)
					} else {
						if err := kchanex.Exchange.CloseMarketData(); err != nil {
							log.Errorf("%v", err)
							return
						}
						count--
					}
				}
				if count == 0 {
					break
				}
			}
		}()

		cmdutil.WaitForSignal(runCtx, syscall.SIGINT, syscall.SIGTERM)

		log.Infof("shutting down trader...")
		shutdownCtx, cancelShutdown := context.WithDeadline(runCtx, time.Now().Add(10*time.Second))
		trader.Graceful.Shutdown(shutdownCtx)
		cancelShutdown()

		log.SetLevel(log.InfoLevel)
		for _, session := range environ.Sessions() {
			backtestExchange := session.Exchange.(*backtest.Exchange)
			exchangeName := session.Exchange.Name().String()
			for symbol, trades := range session.Trades {
				market, ok := session.Market(symbol)
				if !ok {
					return fmt.Errorf("market not found: %s, %s", symbol, exchangeName)
				}

				calculator := &pnl.AverageCostCalculator{
					TradingFeeCurrency: backtestExchange.PlatformFeeCurrency(),
					Market:             market,
				}

				startPrice, ok := session.StartPrice(symbol)
				if !ok {
					return fmt.Errorf("start price not found: %s, %s. run --sync first", symbol, exchangeName)
				}

				lastPrice, ok := session.LastPrice(symbol)
				if !ok {
					return fmt.Errorf("last price not found: %s, %s", symbol, exchangeName)
				}

				color.Green("%s %s PROFIT AND LOSS REPORT", strings.ToUpper(exchangeName), symbol)
				color.Green("===============================================")

				report := calculator.Calculate(symbol, trades.Trades, lastPrice)
				report.Print()

				initBalances := userConfig.Backtest.Account[exchangeName].Balances.BalanceMap()
				finalBalances := session.Account.Balances()

				log.Infof("INITIAL BALANCES:")
				initBalances.Print()

				log.Infof("FINAL BALANCES:")
				finalBalances.Print()

				if jsonOutputEnabled {
					result := BackTestReport{
						Symbol:          symbol,
						LastPrice:       lastPrice,
						StartPrice:      startPrice,
						PnLReport:       report,
						InitialBalances: initBalances,
						FinalBalances:   finalBalances,
					}

					jsonOutput, err := json.MarshalIndent(&result, "", "  ")
					if err != nil {
						return err
					}

					if err := ioutil.WriteFile(filepath.Join(outputDirectory, symbol+".json"), jsonOutput, 0644); err != nil {
						return err
					}
				}

				initQuoteAsset := inQuoteAsset(initBalances, market, startPrice)
				finalQuoteAsset := inQuoteAsset(finalBalances, market, lastPrice)
				log.Infof("INITIAL ASSET IN %s ~= %s %s (1 %s = %v)", market.QuoteCurrency, market.FormatQuantity(initQuoteAsset), market.QuoteCurrency, market.BaseCurrency, startPrice)
				log.Infof("FINAL ASSET IN %s ~= %s %s (1 %s = %v)", market.QuoteCurrency, market.FormatQuantity(finalQuoteAsset), market.QuoteCurrency, market.BaseCurrency, lastPrice)

				if report.Profit.Sign() > 0 {
					color.Green("REALIZED PROFIT: +%v %s", report.Profit, market.QuoteCurrency)
				} else {
					color.Red("REALIZED PROFIT: %v %s", report.Profit, market.QuoteCurrency)
				}

				if report.UnrealizedProfit.Sign() > 0 {
					color.Green("UNREALIZED PROFIT: +%v %s", report.UnrealizedProfit, market.QuoteCurrency)
				} else {
					color.Red("UNREALIZED PROFIT: %v %s", report.UnrealizedProfit, market.QuoteCurrency)
				}

				if finalQuoteAsset.Compare(initQuoteAsset) > 0 {
					color.Green("ASSET INCREASED: +%v %s (+%s)", finalQuoteAsset.Sub(initQuoteAsset), market.QuoteCurrency, finalQuoteAsset.Sub(initQuoteAsset).Div(initQuoteAsset).FormatPercentage(2))
				} else {
					color.Red("ASSET DECREASED: %v %s (%s)", finalQuoteAsset.Sub(initQuoteAsset), market.QuoteCurrency, finalQuoteAsset.Sub(initQuoteAsset).Div(initQuoteAsset).FormatPercentage(2))
				}

				if wantBaseAssetBaseline {

					if lastPrice.Compare(startPrice) > 0 {
						color.Green("%s BASE ASSET PERFORMANCE: +%s (= (%s - %s) / %s)",
							market.BaseCurrency,
							lastPrice.Sub(startPrice).Div(startPrice).FormatPercentage(2),
							lastPrice.FormatString(2),
							startPrice.FormatString(2),
							startPrice.FormatString(2))
					} else {
						color.Red("%s BASE ASSET PERFORMANCE: %s (= (%s - %s) / %s)",
							market.BaseCurrency,
							lastPrice.Sub(startPrice).Div(startPrice).FormatPercentage(2),
							lastPrice.FormatString(2),
							startPrice.FormatString(2),
							startPrice.FormatString(2))
					}
				}
			}
		}

		return nil
	},
}
View Source
var BuildCmd = &cobra.Command{
	Use:   "build",
	Short: "build cross-platform binary",

	SilenceUsage: true,

	RunE: func(cmd *cobra.Command, args []string) error {
		ctx, cancel := context.WithCancel(context.Background())
		defer cancel()

		configFile, err := cmd.Flags().GetString("config")
		if err != nil {
			return err
		}

		if len(configFile) == 0 {
			return errors.New("--config option is required")
		}

		userConfig, err := bbgo.LoadBuildConfig(configFile)
		if err != nil {
			return err
		}

		if userConfig.Build == nil {
			return errors.New("build config is not defined")
		}

		for _, target := range userConfig.Build.Targets {
			log.Infof("building %s ...", target.Name)

			binary, err := bbgo.BuildTarget(ctx, userConfig, target)
			if err != nil {
				return err
			}

			log.Infof("build succeeded: %s", binary)
		}

		return nil
	},
}
View Source
var PnLCmd = &cobra.Command{
	Use:          "pnl",
	Short:        "pnl calculator",
	SilenceUsage: true,
	RunE: func(cmd *cobra.Command, args []string) error {
		ctx := context.Background()

		configFile, err := cmd.Flags().GetString("config")
		if err != nil {
			return err
		}

		if len(configFile) == 0 {
			return errors.New("--config option is required")
		}

		if _, err := os.Stat(configFile); os.IsNotExist(err) {
			return err
		}

		userConfig, err := bbgo.Load(configFile, false)
		if err != nil {
			return err
		}

		sessionName, err := cmd.Flags().GetString("session")
		if err != nil {
			return err
		}

		symbol, err := cmd.Flags().GetString("symbol")
		if err != nil {
			return err
		}

		if len(symbol) == 0 {
			return errors.New("--symbol [SYMBOL] is required")
		}

		limit, err := cmd.Flags().GetInt("limit")
		if err != nil {
			return err
		}

		environ := bbgo.NewEnvironment()

		if err := environ.ConfigureDatabase(ctx); err != nil {
			return err
		}

		if err := environ.ConfigureExchangeSessions(userConfig); err != nil {
			return err
		}

		session, ok := environ.Session(sessionName)
		if !ok {
			return fmt.Errorf("session %s not found", sessionName)
		}

		if err := environ.SyncSession(ctx, session); err != nil {
			return err
		}

		if err = environ.Init(ctx); err != nil {
			return err
		}

		exchange := session.Exchange

		market, ok := session.Market(symbol)
		if !ok {
			return fmt.Errorf("market config %s not found", symbol)
		}

		since := time.Now().AddDate(-1, 0, 0)
		until := time.Now()

		includeTransfer, err := cmd.Flags().GetBool("include-transfer")
		if err != nil {
			return err
		}

		if includeTransfer {
			transferService, ok := exchange.(types.ExchangeTransferService)
			if !ok {
				return fmt.Errorf("session exchange %s does not implement transfer service", sessionName)
			}

			deposits, err := transferService.QueryDepositHistory(ctx, market.BaseCurrency, since, until)
			if err != nil {
				return err
			}
			_ = deposits

			withdrawals, err := transferService.QueryWithdrawHistory(ctx, market.BaseCurrency, since, until)
			if err != nil {
				return err
			}
			_ = withdrawals

			backtestService := &service.BacktestService{DB: environ.DatabaseService.DB}
			if err := backtestService.SyncKLineByInterval(ctx, exchange, symbol, types.Interval1d, since, until); err != nil {
				return err
			}
		}

		var trades []types.Trade
		tradingFeeCurrency := exchange.PlatformFeeCurrency()
		if strings.HasPrefix(symbol, tradingFeeCurrency) {
			log.Infof("loading all trading fee currency related trades: %s", symbol)
			trades, err = environ.TradeService.QueryForTradingFeeCurrency(exchange.Name(), symbol, tradingFeeCurrency)
		} else {
			trades, err = environ.TradeService.Query(service.QueryTradesOptions{
				Exchange: exchange.Name(),
				Symbol:   symbol,
				Limit:    limit,
			})
		}

		if err != nil {
			return err
		}

		log.Infof("%d trades loaded", len(trades))

		stockManager := &accounting.StockDistribution{
			Symbol:             symbol,
			TradingFeeCurrency: tradingFeeCurrency,
		}

		checkpoints, err := stockManager.AddTrades(trades)
		if err != nil {
			return err
		}

		log.Infof("found checkpoints: %+v", checkpoints)
		log.Infof("stock: %v", stockManager.Stocks.Quantity())

		tickers, err := exchange.QueryTickers(ctx, symbol)

		if err != nil {
			return err
		}

		currentTick, ok := tickers[symbol]

		if !ok {
			return errors.New("no ticker data for current price")
		}

		currentPrice := currentTick.Last

		calculator := &pnl.AverageCostCalculator{
			TradingFeeCurrency: tradingFeeCurrency,
		}

		report := calculator.Calculate(symbol, trades, currentPrice)
		report.Print()
		return nil
	},
}
View Source
var RootCmd = &cobra.Command{
	Use:   "bbgo",
	Short: "bbgo is a crypto trading bot",

	SilenceUsage: true,

	PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
		disableDotEnv, err := cmd.Flags().GetBool("no-dotenv")
		if err != nil {
			return err
		}

		if !disableDotEnv {
			dotenvFile, err := cmd.Flags().GetString("dotenv")
			if err != nil {
				return err
			}

			if _, err := os.Stat(dotenvFile); err == nil {
				if err := godotenv.Load(dotenvFile); err != nil {
					return errors.Wrap(err, "error loading dotenv file")
				}
			}
		}

		if viper.GetBool("debug") {
			log.Infof("debug mode is enabled")
			log.SetLevel(log.DebugLevel)
		}

		if viper.GetBool("metrics") {
			http.Handle("/metrics", promhttp.Handler())
			go func() {
				port := viper.GetString("metrics-port")
				log.Infof("starting metrics server at :%s", port)
				err := http.ListenAndServe(":"+port, nil)
				if err != nil {
					log.WithError(err).Errorf("metrics server error")
				}
			}()
		}

		configFile, err := cmd.Flags().GetString("config")
		if err != nil {
			return errors.Wrapf(err, "failed to get the config flag")
		}

		if len(configFile) > 0 {

			if _, err := os.Stat(configFile); err == nil {

				userConfig, err = bbgo.Load(configFile, false)
				if err != nil {
					return errors.Wrapf(err, "can not load config file: %s", configFile)
				}

			} else if os.IsNotExist(err) {

				userConfig = &bbgo.Config{}
			} else {

				return errors.Wrapf(err, "config file load error: %s", configFile)
			}
		}

		return nil
	},

	RunE: func(cmd *cobra.Command, args []string) error {
		return nil
	},
}
View Source
var RunCmd = &cobra.Command{
	Use:   "run",
	Short: "run strategies from config file",

	SilenceUsage: true,
	RunE:         run,
}
View Source
var SyncCmd = &cobra.Command{
	Use:          "sync --session=[exchange_name] --symbol=[pair_name] [--since=yyyy/mm/dd]",
	Short:        "sync trades and orders history",
	SilenceUsage: true,
	RunE: func(cmd *cobra.Command, args []string) error {
		ctx := context.Background()

		configFile, err := cmd.Flags().GetString("config")
		if err != nil {
			return err
		}

		if len(configFile) == 0 {
			return errors.New("--config option is required")
		}

		if _, err := os.Stat(configFile); os.IsNotExist(err) {
			return err
		}

		userConfig, err := bbgo.Load(configFile, false)
		if err != nil {
			return err
		}

		since, err := cmd.Flags().GetString("since")
		if err != nil {
			return err
		}

		environ := bbgo.NewEnvironment()
		if err := environ.ConfigureDatabase(ctx); err != nil {
			return err
		}

		if err := environ.ConfigureExchangeSessions(userConfig); err != nil {
			return err
		}

		sessionName, err := cmd.Flags().GetString("session")
		if err != nil {
			return err
		}

		symbol, err := cmd.Flags().GetString("symbol")
		if err != nil {
			return err
		}

		var (
			// default sync start time
			defaultSyncStartTime = time.Now().AddDate(-1, 0, 0)
		)

		var syncStartTime = defaultSyncStartTime

		if userConfig.Sync != nil && userConfig.Sync.Since != nil {
			syncStartTime = userConfig.Sync.Since.Time()
		}

		if len(since) > 0 {
			syncStartTime, err = time.ParseInLocation("2006-01-02", since, time.Local)
			if err != nil {
				return err
			}
		}

		environ.SetSyncStartTime(syncStartTime)

		// syncSymbols is the symbol list to sync
		var syncSymbols []string

		if userConfig.Sync != nil && len(userConfig.Sync.Symbols) > 0 {
			syncSymbols = userConfig.Sync.Symbols
		}

		if len(symbol) > 0 {
			syncSymbols = []string{symbol}
		}

		var selectedSessions []string

		if userConfig.Sync != nil && len(userConfig.Sync.Sessions) > 0 {
			selectedSessions = userConfig.Sync.Sessions
		}
		if len(sessionName) > 0 {
			selectedSessions = []string{sessionName}
		}

		sessions := environ.SelectSessions(selectedSessions...)
		for _, session := range sessions {
			if err := environ.SyncSession(ctx, session, syncSymbols...); err != nil {
				return err
			}

			log.Infof("exchange session %s synchronization done", session.Name)
		}

		return nil
	},
}
View Source
var TransferHistoryCmd = &cobra.Command{
	Use:   "transfer-history",
	Short: "show transfer history",

	SilenceUsage: true,
	RunE: func(cmd *cobra.Command, args []string) error {
		ctx := context.Background()

		configFile, err := cmd.Flags().GetString("config")
		if err != nil {
			return err
		}

		userConfig, err := bbgo.Load(configFile, false)
		if err != nil {
			return err
		}

		environ := bbgo.NewEnvironment()
		if err := BootstrapEnvironment(ctx, environ, userConfig); err != nil {
			return err
		}

		sessionName, err := cmd.Flags().GetString("session")
		if err != nil {
			return err
		}

		asset, err := cmd.Flags().GetString("asset")
		if err != nil {
			return err
		}

		session, ok := environ.Session(sessionName)
		if !ok {
			return fmt.Errorf("session %s not found", sessionName)
		}

		// default
		var now = time.Now()
		var since = now.AddDate(-1, 0, 0)
		var until = now

		sinceStr, err := cmd.Flags().GetString("since")
		if err != nil {
			return err
		}

		if len(sinceStr) > 0 {
			loc, err := time.LoadLocation("Asia/Taipei")
			if err != nil {
				return err
			}

			since, err = time.ParseInLocation("2006-01-02", sinceStr, loc)
			if err != nil {
				return err
			}
		}

		var records timeSlice

		exchange, ok := session.Exchange.(types.ExchangeTransferService)
		if !ok {
			return fmt.Errorf("exchange session %s does not implement transfer service", sessionName)
		}

		deposits, err := exchange.QueryDepositHistory(ctx, asset, since, until)
		if err != nil {
			return err
		}
		for _, d := range deposits {
			records = append(records, timeRecord{
				Record: d,
				Time:   d.EffectiveTime(),
			})
		}

		withdraws, err := exchange.QueryWithdrawHistory(ctx, asset, since, until)
		if err != nil {
			return err
		}
		for _, w := range withdraws {
			records = append(records, timeRecord{
				Record: w,
				Time:   w.EffectiveTime(),
			})
		}

		sort.Sort(records)

		for _, record := range records {
			switch record := record.Record.(type) {

			case types.Deposit:
				logrus.Infof("%s: <--- DEPOSIT %v %s [%s]", record.Time, record.Amount, record.Asset, record.Status)

			case types.Withdraw:
				logrus.Infof("%s: ---> WITHDRAW %v %s  [%s]", record.ApplyTime, record.Amount, record.Asset, record.Status)

			default:
				logrus.Infof("unknown record: %+v", record)

			}
		}

		stats := calBaselineStats(asset, deposits, withdraws)
		for asset, quantity := range stats.TotalDeposit {
			logrus.Infof("total %s deposit: %v", asset, quantity)
		}

		for asset, quantity := range stats.TotalWithdraw {
			logrus.Infof("total %s withdraw: %v", asset, quantity)
		}

		for asset, quantity := range stats.BaselineBalance {
			logrus.Infof("baseline %s balance: %v", asset, quantity)
		}

		return nil
	},
}
View Source
var VersionCmd = &cobra.Command{
	Use:          "version",
	Short:        "show version name",
	SilenceUsage: true,
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Println(version.Version)
	},
}

Functions

func BootstrapBacktestEnvironment added in v1.15.5

func BootstrapBacktestEnvironment(ctx context.Context, environ *bbgo.Environment, userConfig *bbgo.Config) error

func BootstrapEnvironment added in v1.11.0

func BootstrapEnvironment(ctx context.Context, environ *bbgo.Environment, userConfig *bbgo.Config) error

func Execute

func Execute()

Types

type BackTestReport added in v1.28.0

type BackTestReport struct {
	Symbol          string                    `json:"symbol,omitempty"`
	LastPrice       fixedpoint.Value          `json:"lastPrice,omitempty"`
	StartPrice      fixedpoint.Value          `json:"startPrice,omitempty"`
	PnLReport       *pnl.AverageCostPnlReport `json:"pnlReport,omitempty"`
	InitialBalances types.BalanceMap          `json:"initialBalances,omitempty"`
	FinalBalances   types.BalanceMap          `json:"finalBalances,omitempty"`
}

type BaselineStats

type BaselineStats struct {
	Asset           string
	TotalDeposit    map[string]fixedpoint.Value
	TotalWithdraw   map[string]fixedpoint.Value
	BaselineBalance map[string]fixedpoint.Value
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL