mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-17 07:26:48 +00:00
* Ramshackle early leads to GRPC backtester * Adds GRPC server, default config generation * Partial support for GRPC backtester config * Update to use Buf, merge fixes * Full config for GRPC * Adds new commands, causes big panic * Fixes panics * Setup for the future * Docs update * test * grpc tests * Fix merge issues. Lint and test * minor fixes after rebase * Docs, formatting and main fixes * Change buf owner * shazNits * test-123 * rpc fixes * string fixes * Removes --singlerun flag and just relies on --singlerunstrategypath * fixes test * initial post merge compatability fixes * this actually all seems to work? unexpected * adds pluginpath to config * rm unused func. add gitignore * rm unused func. add gitignore * lintle * tITLE cASE lOG fIX,rm auth package, gitignore, tmpdir fix * buf updates + gen. go mod tidy * x2 * Update default port, update error text
259 lines
7.4 KiB
Go
259 lines
7.4 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"flag"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/thrasher-corp/gocryptotrader/backtester/common"
|
|
"github.com/thrasher-corp/gocryptotrader/backtester/config"
|
|
backtest "github.com/thrasher-corp/gocryptotrader/backtester/engine"
|
|
"github.com/thrasher-corp/gocryptotrader/backtester/plugins/strategies"
|
|
"github.com/thrasher-corp/gocryptotrader/common/file"
|
|
"github.com/thrasher-corp/gocryptotrader/engine"
|
|
"github.com/thrasher-corp/gocryptotrader/log"
|
|
"github.com/thrasher-corp/gocryptotrader/signaler"
|
|
)
|
|
|
|
var singleRunStrategyPath, templatePath, outputPath, btConfigDir, strategyPluginPath string
|
|
var printLogo, generateReport, darkReport, colourOutput, logSubHeader bool
|
|
|
|
func main() {
|
|
wd, err := os.Getwd()
|
|
if err != nil {
|
|
fmt.Printf("Could not get working directory. Error: %v.\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
flags := parseFlags(wd)
|
|
var btCfg *config.BacktesterConfig
|
|
if btConfigDir == "" {
|
|
btConfigDir = config.DefaultBTConfigDir
|
|
log.Infof(log.Global, "Blank config received, using default path '%v'", btConfigDir)
|
|
}
|
|
fe := file.Exists(btConfigDir)
|
|
switch {
|
|
case fe:
|
|
btCfg, err = config.ReadBacktesterConfigFromPath(btConfigDir)
|
|
if err != nil {
|
|
fmt.Printf("Could not read config. Error: %v.\n", err)
|
|
os.Exit(1)
|
|
}
|
|
case !fe && btConfigDir == config.DefaultBTConfigDir:
|
|
btCfg, err = config.GenerateDefaultConfig()
|
|
if err != nil {
|
|
fmt.Printf("Could not generate config. Error: %v.\n", err)
|
|
os.Exit(1)
|
|
}
|
|
var btCfgJSON []byte
|
|
btCfgJSON, err = json.MarshalIndent(btCfg, "", " ")
|
|
if err != nil {
|
|
fmt.Printf("Could not generate config. Error: %v.\n", err)
|
|
os.Exit(1)
|
|
}
|
|
err = os.MkdirAll(config.DefaultBTDir, file.DefaultPermissionOctal)
|
|
if err != nil {
|
|
fmt.Printf("Could not generate config. Error: %v.\n", err)
|
|
os.Exit(1)
|
|
}
|
|
err = os.WriteFile(btConfigDir, btCfgJSON, file.DefaultPermissionOctal)
|
|
if err != nil {
|
|
fmt.Printf("Could not generate config. Error: %v.\n", err)
|
|
os.Exit(1)
|
|
}
|
|
default:
|
|
log.Errorf(log.Global, "Non-standard config '%v' does not exist. Exiting...", btConfigDir)
|
|
return
|
|
}
|
|
|
|
flagSet := engine.FlagSet(flags)
|
|
flagSet.WithBool("printlogo", &printLogo, btCfg.PrintLogo)
|
|
flagSet.WithBool("darkreport", &darkReport, btCfg.Report.DarkMode)
|
|
flagSet.WithBool("generatereport", &generateReport, btCfg.Report.GenerateReport)
|
|
flagSet.WithBool("logsubheaders", &logSubHeader, btCfg.LogSubheaders)
|
|
flagSet.WithBool("colouroutput", &colourOutput, btCfg.UseCMDColours)
|
|
|
|
if singleRunStrategyPath != "" && !file.Exists(singleRunStrategyPath) {
|
|
fmt.Printf("Strategy config path not found '%v'", singleRunStrategyPath)
|
|
os.Exit(1)
|
|
}
|
|
|
|
defaultTemplate := filepath.Join(
|
|
wd,
|
|
"report",
|
|
"tpl.gohtml")
|
|
defaultReportOutput := filepath.Join(
|
|
wd,
|
|
"results")
|
|
|
|
if templatePath != defaultTemplate {
|
|
btCfg.Report.TemplatePath = templatePath
|
|
}
|
|
if !file.Exists(btCfg.Report.TemplatePath) {
|
|
fmt.Printf("Report template path not found '%v'", btCfg.Report.TemplatePath)
|
|
os.Exit(1)
|
|
}
|
|
|
|
if outputPath != defaultReportOutput {
|
|
btCfg.Report.OutputPath = outputPath
|
|
}
|
|
if !file.Exists(btCfg.Report.OutputPath) {
|
|
fmt.Printf("Report output path not found '%v'", btCfg.Report.OutputPath)
|
|
os.Exit(1)
|
|
}
|
|
|
|
if colourOutput {
|
|
common.SetColours(&btCfg.Colours)
|
|
} else {
|
|
common.PurgeColours()
|
|
}
|
|
|
|
log.GlobalLogConfig = log.GenDefaultSettings()
|
|
log.GlobalLogConfig.AdvancedSettings.ShowLogSystemName = &logSubHeader
|
|
log.GlobalLogConfig.AdvancedSettings.Headers.Info = common.CMDColours.Info + "[INFO]" + common.CMDColours.Default
|
|
log.GlobalLogConfig.AdvancedSettings.Headers.Warn = common.CMDColours.Warn + "[WARN]" + common.CMDColours.Default
|
|
log.GlobalLogConfig.AdvancedSettings.Headers.Debug = common.CMDColours.Debug + "[DEBUG]" + common.CMDColours.Default
|
|
log.GlobalLogConfig.AdvancedSettings.Headers.Error = common.CMDColours.Error + "[ERROR]" + common.CMDColours.Default
|
|
err = log.SetupGlobalLogger()
|
|
if err != nil {
|
|
fmt.Printf("Could not setup global logger. Error: %v.\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
err = common.RegisterBacktesterSubLoggers()
|
|
if err != nil {
|
|
fmt.Printf("Could not register subloggers. Error: %v.\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
if printLogo {
|
|
fmt.Println(common.Logo())
|
|
}
|
|
|
|
if strategyPluginPath == "" && btCfg.PluginPath != "" {
|
|
strategyPluginPath = btCfg.PluginPath
|
|
}
|
|
if strategyPluginPath != "" {
|
|
err = strategies.LoadCustomStrategies(strategyPluginPath)
|
|
if err != nil {
|
|
fmt.Printf("Could not load custom strategies. Error: %v.\n", err)
|
|
os.Exit(1)
|
|
}
|
|
log.Infof(common.Backtester, "Loaded plugin %v\n", strategyPluginPath)
|
|
}
|
|
|
|
if singleRunStrategyPath != "" {
|
|
dir := singleRunStrategyPath
|
|
var cfg *config.Config
|
|
cfg, err = config.ReadStrategyConfigFromFile(dir)
|
|
if err != nil {
|
|
fmt.Printf("Could not read strategy config. Error: %v.\n", err)
|
|
os.Exit(1)
|
|
}
|
|
err = backtest.ExecuteStrategy(cfg, &config.BacktesterConfig{
|
|
Report: config.Report{
|
|
GenerateReport: generateReport,
|
|
TemplatePath: btCfg.Report.TemplatePath,
|
|
OutputPath: btCfg.Report.OutputPath,
|
|
DarkMode: darkReport,
|
|
},
|
|
})
|
|
if err != nil {
|
|
fmt.Printf("Could not execute strategy. Error: %v.\n", err)
|
|
os.Exit(1)
|
|
}
|
|
return
|
|
}
|
|
|
|
btCfg.Report.DarkMode = darkReport
|
|
btCfg.Report.GenerateReport = generateReport
|
|
|
|
go func(c *config.BacktesterConfig) {
|
|
log.Info(log.GRPCSys, "Starting RPC server")
|
|
s := backtest.SetupRPCServer(c)
|
|
err = backtest.StartRPCServer(s)
|
|
if err != nil {
|
|
fmt.Printf("Could not start RPC server. Error: %v.\n", err)
|
|
os.Exit(1)
|
|
}
|
|
log.Info(log.GRPCSys, "Ready to receive commands")
|
|
}(btCfg)
|
|
interrupt := signaler.WaitForInterrupt()
|
|
log.Infof(log.Global, "Captured %v, shutdown requested.\n", interrupt)
|
|
log.Infoln(log.Global, "Exiting.")
|
|
}
|
|
|
|
func parseFlags(wd string) map[string]bool {
|
|
defaultStrategy := filepath.Join(
|
|
wd,
|
|
"config",
|
|
"strategyexamples",
|
|
"dca-api-candles.strat")
|
|
defaultTemplate := filepath.Join(
|
|
wd,
|
|
"report",
|
|
"tpl.gohtml")
|
|
|
|
defaultReportOutput := filepath.Join(
|
|
wd,
|
|
"results")
|
|
flag.StringVar(
|
|
&singleRunStrategyPath,
|
|
"singlerunstrategypath",
|
|
"",
|
|
fmt.Sprintf("path to a strategy file. Will execute strategy and exit, instead of creating a GRPC server. Example %v", defaultStrategy))
|
|
flag.StringVar(
|
|
&btConfigDir,
|
|
"backtesterconfigpath",
|
|
config.DefaultBTConfigDir,
|
|
"the location of the backtester config")
|
|
flag.StringVar(
|
|
&templatePath,
|
|
"templatepath",
|
|
defaultTemplate,
|
|
"the report template to use")
|
|
flag.BoolVar(
|
|
&generateReport,
|
|
"generatereport",
|
|
true,
|
|
"whether to generate the report file")
|
|
flag.StringVar(
|
|
&outputPath,
|
|
"outputpath",
|
|
defaultReportOutput,
|
|
"the path where to output results")
|
|
flag.BoolVar(
|
|
&darkReport,
|
|
"darkreport",
|
|
false,
|
|
"sets the output report to use a dark theme by default")
|
|
flag.BoolVar(
|
|
&colourOutput,
|
|
"colouroutput",
|
|
false,
|
|
"if enabled, will print in colours, if your terminal supports \033[38;5;99m[colours like this]\u001b[0m")
|
|
flag.BoolVar(
|
|
&logSubHeader,
|
|
"logsubheader",
|
|
true,
|
|
"displays logging subheader to track where activity originates")
|
|
flag.BoolVar(
|
|
&printLogo,
|
|
"printlogo",
|
|
true,
|
|
"shows the stunning, profit inducing logo on startup")
|
|
flag.StringVar(
|
|
&strategyPluginPath,
|
|
"strategypluginpath",
|
|
"",
|
|
"example path: "+filepath.Join(wd, "plugins", "strategies", "example", "example.so"))
|
|
flag.Parse()
|
|
// collect flags
|
|
flags := make(map[string]bool)
|
|
// Stores the set flags
|
|
flag.Visit(func(f *flag.Flag) { flags[f.Name] = true })
|
|
return flags
|
|
}
|