mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 23:16:45 +00:00
backtester: run manager (#1040)
* begins defining run management options * fleshes out concept * completes fund manager and RPC commands * coverage and improvements * adds coverage, and bad log concept * simplifies output at expense of races * removes run logging for now. tightens races. adds cov * Lints thine splints * Fixes stopping and clearing bugs * some niteroos * fix races
This commit is contained in:
@@ -10,6 +10,19 @@ import (
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
var (
|
||||
doNotRunFlag = &cli.BoolFlag{
|
||||
Name: "donotrunimmediately",
|
||||
Aliases: []string{"dnr"},
|
||||
Usage: "if true, will load the strategy, but will not execute until another command is sent",
|
||||
}
|
||||
doNotStoreFlag = &cli.BoolFlag{
|
||||
Name: "donotstore",
|
||||
Aliases: []string{"dns"},
|
||||
Usage: "if true, will not store the run internally - cannot be run in conjunction with dnr",
|
||||
}
|
||||
)
|
||||
|
||||
var executeStrategyFromFileCommand = &cli.Command{
|
||||
Name: "executestrategyfromfile",
|
||||
Usage: "runs the strategy from a config file",
|
||||
@@ -21,6 +34,8 @@ var executeStrategyFromFileCommand = &cli.Command{
|
||||
Aliases: []string{"p"},
|
||||
Usage: "the filepath to a strategy to execute",
|
||||
},
|
||||
doNotRunFlag,
|
||||
doNotStoreFlag,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -32,7 +47,7 @@ func executeStrategyFromFile(c *cli.Context) error {
|
||||
defer closeConn(conn, cancel)
|
||||
|
||||
if c.NArg() == 0 && c.NumFlags() == 0 {
|
||||
return cli.ShowCommandHelp(c, "executestrategyfromfile")
|
||||
return cli.ShowCommandHelp(c, c.Command.Name)
|
||||
}
|
||||
|
||||
var path string
|
||||
@@ -42,11 +57,22 @@ func executeStrategyFromFile(c *cli.Context) error {
|
||||
path = c.Args().First()
|
||||
}
|
||||
|
||||
var dnr bool
|
||||
if c.IsSet("donotrunimmediately") {
|
||||
dnr = c.Bool("donotrunimmediately")
|
||||
}
|
||||
var dns bool
|
||||
if c.IsSet("donotstore") {
|
||||
dns = c.Bool("donotstore")
|
||||
}
|
||||
|
||||
client := btrpc.NewBacktesterServiceClient(conn)
|
||||
result, err := client.ExecuteStrategyFromFile(
|
||||
c.Context,
|
||||
&btrpc.ExecuteStrategyFromFileRequest{
|
||||
StrategyFilePath: path,
|
||||
StrategyFilePath: path,
|
||||
DoNotRunImmediately: dnr,
|
||||
DoNotStore: dns,
|
||||
},
|
||||
)
|
||||
|
||||
@@ -58,11 +84,264 @@ func executeStrategyFromFile(c *cli.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var listAllRunsCommand = &cli.Command{
|
||||
Name: "listallruns",
|
||||
Usage: "returns a list of all loaded backtest/livestrategy runs",
|
||||
Action: listAllRuns,
|
||||
}
|
||||
|
||||
func listAllRuns(c *cli.Context) error {
|
||||
conn, cancel, err := setupClient(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closeConn(conn, cancel)
|
||||
|
||||
client := btrpc.NewBacktesterServiceClient(conn)
|
||||
result, err := client.ListAllRuns(
|
||||
c.Context,
|
||||
&btrpc.ListAllRunsRequest{},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
jsonOutput(result)
|
||||
return nil
|
||||
}
|
||||
|
||||
var startRunCommand = &cli.Command{
|
||||
Name: "startrun",
|
||||
Usage: "executes a strategy loaded into the server",
|
||||
ArgsUsage: "<id>",
|
||||
Action: startRun,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "id",
|
||||
Usage: "the id of the backtest/livestrategy run",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func startRun(c *cli.Context) error {
|
||||
conn, cancel, err := setupClient(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closeConn(conn, cancel)
|
||||
|
||||
if c.NArg() == 0 && c.NumFlags() == 0 {
|
||||
return cli.ShowCommandHelp(c, c.Command.Name)
|
||||
}
|
||||
|
||||
var id string
|
||||
if c.IsSet("id") {
|
||||
id = c.String("id")
|
||||
} else {
|
||||
id = c.Args().First()
|
||||
}
|
||||
|
||||
client := btrpc.NewBacktesterServiceClient(conn)
|
||||
result, err := client.StartRun(
|
||||
c.Context,
|
||||
&btrpc.StartRunRequest{
|
||||
Id: id,
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
jsonOutput(result)
|
||||
return nil
|
||||
}
|
||||
|
||||
var startAllRunsCommand = &cli.Command{
|
||||
Name: "startallruns",
|
||||
Usage: "executes all strategies loaded into the server that have not been run",
|
||||
Action: startAllRuns,
|
||||
}
|
||||
|
||||
func startAllRuns(c *cli.Context) error {
|
||||
conn, cancel, err := setupClient(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closeConn(conn, cancel)
|
||||
|
||||
client := btrpc.NewBacktesterServiceClient(conn)
|
||||
result, err := client.StartAllRuns(
|
||||
c.Context,
|
||||
&btrpc.StartAllRunsRequest{},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
jsonOutput(result)
|
||||
return nil
|
||||
}
|
||||
|
||||
var stopRunCommand = &cli.Command{
|
||||
Name: "stoprun",
|
||||
Usage: "stops a strategy loaded into the server",
|
||||
ArgsUsage: "<id>",
|
||||
Action: stopRun,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "id",
|
||||
Usage: "the id of the backtest/livestrategy run",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func stopRun(c *cli.Context) error {
|
||||
conn, cancel, err := setupClient(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closeConn(conn, cancel)
|
||||
|
||||
if c.NArg() == 0 && c.NumFlags() == 0 {
|
||||
return cli.ShowCommandHelp(c, c.Command.Name)
|
||||
}
|
||||
|
||||
var id string
|
||||
if c.IsSet("id") {
|
||||
id = c.String("id")
|
||||
} else {
|
||||
id = c.Args().First()
|
||||
}
|
||||
|
||||
client := btrpc.NewBacktesterServiceClient(conn)
|
||||
result, err := client.StopRun(
|
||||
c.Context,
|
||||
&btrpc.StopRunRequest{
|
||||
Id: id,
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
jsonOutput(result)
|
||||
return nil
|
||||
}
|
||||
|
||||
var stopAllRunsCommand = &cli.Command{
|
||||
Name: "stopallruns",
|
||||
Usage: "stops all strategies loaded into the server",
|
||||
Action: stopAllRuns,
|
||||
}
|
||||
|
||||
func stopAllRuns(c *cli.Context) error {
|
||||
conn, cancel, err := setupClient(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closeConn(conn, cancel)
|
||||
|
||||
client := btrpc.NewBacktesterServiceClient(conn)
|
||||
result, err := client.StopAllRuns(
|
||||
c.Context,
|
||||
&btrpc.StopAllRunsRequest{},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
jsonOutput(result)
|
||||
return nil
|
||||
}
|
||||
|
||||
var clearRunCommand = &cli.Command{
|
||||
Name: "clearrun",
|
||||
Usage: "clears/deletes a strategy loaded into the server - if it is not running",
|
||||
ArgsUsage: "<id>",
|
||||
Action: clearRun,
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "id",
|
||||
Usage: "the id of the backtest/livestrategy run",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func clearRun(c *cli.Context) error {
|
||||
conn, cancel, err := setupClient(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closeConn(conn, cancel)
|
||||
|
||||
if c.NArg() == 0 && c.NumFlags() == 0 {
|
||||
return cli.ShowCommandHelp(c, c.Command.Name)
|
||||
}
|
||||
|
||||
var id string
|
||||
if c.IsSet("id") {
|
||||
id = c.String("id")
|
||||
} else {
|
||||
id = c.Args().First()
|
||||
}
|
||||
|
||||
client := btrpc.NewBacktesterServiceClient(conn)
|
||||
result, err := client.ClearRun(
|
||||
c.Context,
|
||||
&btrpc.ClearRunRequest{
|
||||
Id: id,
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
jsonOutput(result)
|
||||
return nil
|
||||
}
|
||||
|
||||
var clearAllRunsCommand = &cli.Command{
|
||||
Name: "clearallruns",
|
||||
Usage: "clears all strategies loaded into the server. Only runs not actively running will be cleared",
|
||||
Action: clearAllRuns,
|
||||
}
|
||||
|
||||
func clearAllRuns(c *cli.Context) error {
|
||||
conn, cancel, err := setupClient(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closeConn(conn, cancel)
|
||||
|
||||
client := btrpc.NewBacktesterServiceClient(conn)
|
||||
result, err := client.ClearAllRuns(
|
||||
c.Context,
|
||||
&btrpc.ClearAllRunsRequest{},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
jsonOutput(result)
|
||||
return nil
|
||||
}
|
||||
|
||||
var executeStrategyFromConfigCommand = &cli.Command{
|
||||
Name: "executestrategyfromconfig",
|
||||
Usage: "runs the default strategy config but via passing in as a struct instead of a filepath - this is a proof-of-concept implementation",
|
||||
Description: "the cli is not a good place to manage this type of command with n variables to pass in from a command line",
|
||||
Action: executeStrategyFromConfig,
|
||||
Flags: []cli.Flag{
|
||||
doNotRunFlag,
|
||||
doNotStoreFlag,
|
||||
},
|
||||
}
|
||||
|
||||
// executeStrategyFromConfig this is a proof of concept command
|
||||
@@ -235,11 +514,22 @@ func executeStrategyFromConfig(c *cli.Context) error {
|
||||
},
|
||||
}
|
||||
|
||||
var dnr bool
|
||||
if c.IsSet("donotrunimmediately") {
|
||||
dnr = c.Bool("donotrunimmediately")
|
||||
}
|
||||
var dns bool
|
||||
if c.IsSet("donotstore") {
|
||||
dns = c.Bool("donotstore")
|
||||
}
|
||||
|
||||
client := btrpc.NewBacktesterServiceClient(conn)
|
||||
result, err := client.ExecuteStrategyFromConfig(
|
||||
c.Context,
|
||||
&btrpc.ExecuteStrategyFromConfigRequest{
|
||||
Config: cfg,
|
||||
Config: cfg,
|
||||
DoNotRunImmediately: dnr,
|
||||
DoNotStore: dns,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@@ -112,6 +112,13 @@ func main() {
|
||||
app.Commands = []*cli.Command{
|
||||
executeStrategyFromFileCommand,
|
||||
executeStrategyFromConfigCommand,
|
||||
listAllRunsCommand,
|
||||
startRunCommand,
|
||||
startAllRunsCommand,
|
||||
stopRunCommand,
|
||||
stopAllRunsCommand,
|
||||
clearRunCommand,
|
||||
clearAllRunsCommand,
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -103,57 +103,414 @@ func local_request_BacktesterService_ExecuteStrategyFromConfig_0(ctx context.Con
|
||||
|
||||
}
|
||||
|
||||
func request_BacktesterService_ListAllRuns_0(ctx context.Context, marshaler runtime.Marshaler, client BacktesterServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq ListAllRunsRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
msg, err := client.ListAllRuns(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_BacktesterService_ListAllRuns_0(ctx context.Context, marshaler runtime.Marshaler, server BacktesterServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq ListAllRunsRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
msg, err := server.ListAllRuns(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_BacktesterService_StartRun_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
||||
)
|
||||
|
||||
func request_BacktesterService_StartRun_0(ctx context.Context, marshaler runtime.Marshaler, client BacktesterServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq StartRunRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_BacktesterService_StartRun_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.StartRun(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_BacktesterService_StartRun_0(ctx context.Context, marshaler runtime.Marshaler, server BacktesterServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq StartRunRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_BacktesterService_StartRun_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.StartRun(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_BacktesterService_StartAllRuns_0(ctx context.Context, marshaler runtime.Marshaler, client BacktesterServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq StartAllRunsRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
msg, err := client.StartAllRuns(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_BacktesterService_StartAllRuns_0(ctx context.Context, marshaler runtime.Marshaler, server BacktesterServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq StartAllRunsRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
msg, err := server.StartAllRuns(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_BacktesterService_StopRun_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
||||
)
|
||||
|
||||
func request_BacktesterService_StopRun_0(ctx context.Context, marshaler runtime.Marshaler, client BacktesterServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq StopRunRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_BacktesterService_StopRun_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.StopRun(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_BacktesterService_StopRun_0(ctx context.Context, marshaler runtime.Marshaler, server BacktesterServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq StopRunRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_BacktesterService_StopRun_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.StopRun(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_BacktesterService_StopAllRuns_0(ctx context.Context, marshaler runtime.Marshaler, client BacktesterServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq StopAllRunsRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
msg, err := client.StopAllRuns(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_BacktesterService_StopAllRuns_0(ctx context.Context, marshaler runtime.Marshaler, server BacktesterServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq StopAllRunsRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
msg, err := server.StopAllRuns(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_BacktesterService_ClearRun_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
||||
)
|
||||
|
||||
func request_BacktesterService_ClearRun_0(ctx context.Context, marshaler runtime.Marshaler, client BacktesterServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq ClearRunRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_BacktesterService_ClearRun_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.ClearRun(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_BacktesterService_ClearRun_0(ctx context.Context, marshaler runtime.Marshaler, server BacktesterServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq ClearRunRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_BacktesterService_ClearRun_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.ClearRun(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_BacktesterService_ClearAllRuns_0(ctx context.Context, marshaler runtime.Marshaler, client BacktesterServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq ClearAllRunsRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
msg, err := client.ClearAllRuns(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_BacktesterService_ClearAllRuns_0(ctx context.Context, marshaler runtime.Marshaler, server BacktesterServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq ClearAllRunsRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
msg, err := server.ClearAllRuns(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
// RegisterBacktesterServiceHandlerServer registers the http handlers for service BacktesterService to "mux".
|
||||
// UnaryRPC :call BacktesterServiceServer directly.
|
||||
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
|
||||
// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterBacktesterServiceHandlerFromEndpoint instead.
|
||||
func RegisterBacktesterServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server BacktesterServiceServer) error {
|
||||
|
||||
mux.Handle("GET", pattern_BacktesterService_ExecuteStrategyFromFile_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
mux.Handle("POST", pattern_BacktesterService_ExecuteStrategyFromFile_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/btrpc.BacktesterService/ExecuteStrategyFromFile", runtime.WithHTTPPathPattern("/v1/executestrategyfromfile"))
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/btrpc.BacktesterService/ExecuteStrategyFromFile", runtime.WithHTTPPathPattern("/v1/executestrategyfromfile"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_BacktesterService_ExecuteStrategyFromFile_0(ctx, inboundMarshaler, server, req, pathParams)
|
||||
resp, md, err := local_request_BacktesterService_ExecuteStrategyFromFile_0(annotatedContext, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_BacktesterService_ExecuteStrategyFromFile_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
forward_BacktesterService_ExecuteStrategyFromFile_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_BacktesterService_ExecuteStrategyFromConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
mux.Handle("POST", pattern_BacktesterService_ExecuteStrategyFromConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
ctx, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/btrpc.BacktesterService/ExecuteStrategyFromConfig", runtime.WithHTTPPathPattern("/v1/executestrategyfromconfig"))
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/btrpc.BacktesterService/ExecuteStrategyFromConfig", runtime.WithHTTPPathPattern("/v1/executestrategyfromconfig"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_BacktesterService_ExecuteStrategyFromConfig_0(ctx, inboundMarshaler, server, req, pathParams)
|
||||
resp, md, err := local_request_BacktesterService_ExecuteStrategyFromConfig_0(annotatedContext, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_BacktesterService_ExecuteStrategyFromConfig_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
forward_BacktesterService_ExecuteStrategyFromConfig_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_BacktesterService_ListAllRuns_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/btrpc.BacktesterService/ListAllRuns", runtime.WithHTTPPathPattern("/v1/listallruns"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_BacktesterService_ListAllRuns_0(annotatedContext, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_BacktesterService_ListAllRuns_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_BacktesterService_StartRun_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/btrpc.BacktesterService/StartRun", runtime.WithHTTPPathPattern("/v1/startrun"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_BacktesterService_StartRun_0(annotatedContext, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_BacktesterService_StartRun_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_BacktesterService_StartAllRuns_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/btrpc.BacktesterService/StartAllRuns", runtime.WithHTTPPathPattern("/v1/startallruns"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_BacktesterService_StartAllRuns_0(annotatedContext, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_BacktesterService_StartAllRuns_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_BacktesterService_StopRun_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/btrpc.BacktesterService/StopRun", runtime.WithHTTPPathPattern("/v1/stoprun"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_BacktesterService_StopRun_0(annotatedContext, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_BacktesterService_StopRun_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_BacktesterService_StopAllRuns_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/btrpc.BacktesterService/StopAllRuns", runtime.WithHTTPPathPattern("/v1/stopallruns"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_BacktesterService_StopAllRuns_0(annotatedContext, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_BacktesterService_StopAllRuns_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("DELETE", pattern_BacktesterService_ClearRun_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/btrpc.BacktesterService/ClearRun", runtime.WithHTTPPathPattern("/v1/clearrun"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_BacktesterService_ClearRun_0(annotatedContext, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_BacktesterService_ClearRun_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("DELETE", pattern_BacktesterService_ClearAllRuns_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/btrpc.BacktesterService/ClearAllRuns", runtime.WithHTTPPathPattern("/v1/clearallruns"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_BacktesterService_ClearAllRuns_0(annotatedContext, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_BacktesterService_ClearAllRuns_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
@@ -198,45 +555,201 @@ func RegisterBacktesterServiceHandler(ctx context.Context, mux *runtime.ServeMux
|
||||
// "BacktesterServiceClient" to call the correct interceptors.
|
||||
func RegisterBacktesterServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client BacktesterServiceClient) error {
|
||||
|
||||
mux.Handle("GET", pattern_BacktesterService_ExecuteStrategyFromFile_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
mux.Handle("POST", pattern_BacktesterService_ExecuteStrategyFromFile_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
ctx, err = runtime.AnnotateContext(ctx, mux, req, "/btrpc.BacktesterService/ExecuteStrategyFromFile", runtime.WithHTTPPathPattern("/v1/executestrategyfromfile"))
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/btrpc.BacktesterService/ExecuteStrategyFromFile", runtime.WithHTTPPathPattern("/v1/executestrategyfromfile"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_BacktesterService_ExecuteStrategyFromFile_0(ctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
resp, md, err := request_BacktesterService_ExecuteStrategyFromFile_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_BacktesterService_ExecuteStrategyFromFile_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
forward_BacktesterService_ExecuteStrategyFromFile_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_BacktesterService_ExecuteStrategyFromConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
mux.Handle("POST", pattern_BacktesterService_ExecuteStrategyFromConfig_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
ctx, err = runtime.AnnotateContext(ctx, mux, req, "/btrpc.BacktesterService/ExecuteStrategyFromConfig", runtime.WithHTTPPathPattern("/v1/executestrategyfromconfig"))
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/btrpc.BacktesterService/ExecuteStrategyFromConfig", runtime.WithHTTPPathPattern("/v1/executestrategyfromconfig"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_BacktesterService_ExecuteStrategyFromConfig_0(ctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
resp, md, err := request_BacktesterService_ExecuteStrategyFromConfig_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_BacktesterService_ExecuteStrategyFromConfig_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
forward_BacktesterService_ExecuteStrategyFromConfig_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_BacktesterService_ListAllRuns_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/btrpc.BacktesterService/ListAllRuns", runtime.WithHTTPPathPattern("/v1/listallruns"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_BacktesterService_ListAllRuns_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_BacktesterService_ListAllRuns_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_BacktesterService_StartRun_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/btrpc.BacktesterService/StartRun", runtime.WithHTTPPathPattern("/v1/startrun"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_BacktesterService_StartRun_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_BacktesterService_StartRun_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_BacktesterService_StartAllRuns_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/btrpc.BacktesterService/StartAllRuns", runtime.WithHTTPPathPattern("/v1/startallruns"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_BacktesterService_StartAllRuns_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_BacktesterService_StartAllRuns_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_BacktesterService_StopRun_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/btrpc.BacktesterService/StopRun", runtime.WithHTTPPathPattern("/v1/stoprun"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_BacktesterService_StopRun_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_BacktesterService_StopRun_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_BacktesterService_StopAllRuns_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/btrpc.BacktesterService/StopAllRuns", runtime.WithHTTPPathPattern("/v1/stopallruns"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_BacktesterService_StopAllRuns_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_BacktesterService_StopAllRuns_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("DELETE", pattern_BacktesterService_ClearRun_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/btrpc.BacktesterService/ClearRun", runtime.WithHTTPPathPattern("/v1/clearrun"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_BacktesterService_ClearRun_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_BacktesterService_ClearRun_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("DELETE", pattern_BacktesterService_ClearAllRuns_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/btrpc.BacktesterService/ClearAllRuns", runtime.WithHTTPPathPattern("/v1/clearallruns"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_BacktesterService_ClearAllRuns_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_BacktesterService_ClearAllRuns_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
@@ -247,10 +760,38 @@ var (
|
||||
pattern_BacktesterService_ExecuteStrategyFromFile_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "executestrategyfromfile"}, ""))
|
||||
|
||||
pattern_BacktesterService_ExecuteStrategyFromConfig_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "executestrategyfromconfig"}, ""))
|
||||
|
||||
pattern_BacktesterService_ListAllRuns_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "listallruns"}, ""))
|
||||
|
||||
pattern_BacktesterService_StartRun_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "startrun"}, ""))
|
||||
|
||||
pattern_BacktesterService_StartAllRuns_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "startallruns"}, ""))
|
||||
|
||||
pattern_BacktesterService_StopRun_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "stoprun"}, ""))
|
||||
|
||||
pattern_BacktesterService_StopAllRuns_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "stopallruns"}, ""))
|
||||
|
||||
pattern_BacktesterService_ClearRun_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "clearrun"}, ""))
|
||||
|
||||
pattern_BacktesterService_ClearAllRuns_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "clearallruns"}, ""))
|
||||
)
|
||||
|
||||
var (
|
||||
forward_BacktesterService_ExecuteStrategyFromFile_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_BacktesterService_ExecuteStrategyFromConfig_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_BacktesterService_ListAllRuns_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_BacktesterService_StartRun_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_BacktesterService_StartAllRuns_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_BacktesterService_StopRun_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_BacktesterService_StopAllRuns_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_BacktesterService_ClearRun_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_BacktesterService_ClearAllRuns_0 = runtime.ForwardResponseMessage
|
||||
)
|
||||
|
||||
@@ -171,29 +171,127 @@ message Config {
|
||||
StatisticSettings statistic_settings = 8;
|
||||
}
|
||||
|
||||
message RunSummary {
|
||||
string id = 1;
|
||||
string strategy_name = 2;
|
||||
string date_loaded = 3;
|
||||
string date_started = 4;
|
||||
string date_ended = 5;
|
||||
bool closed = 6;
|
||||
bool live_testing = 7;
|
||||
bool real_orders = 8;
|
||||
}
|
||||
|
||||
// Requests and responses
|
||||
message ExecuteStrategyFromFileRequest {
|
||||
string strategy_file_path = 1;
|
||||
bool do_not_run_immediately = 2;
|
||||
bool do_not_store = 3;
|
||||
}
|
||||
|
||||
message ExecuteStrategyResponse {
|
||||
bool success = 1;
|
||||
string message = 2;
|
||||
RunSummary run = 1;
|
||||
}
|
||||
|
||||
message ExecuteStrategyFromConfigRequest {
|
||||
btrpc.Config config = 1;
|
||||
bool do_not_run_immediately = 1;
|
||||
bool do_not_store = 2;
|
||||
btrpc.Config config = 3;
|
||||
}
|
||||
|
||||
message ListAllRunsRequest {}
|
||||
|
||||
message ListAllRunsResponse {
|
||||
repeated RunSummary runs = 1;
|
||||
}
|
||||
|
||||
message StopRunRequest {
|
||||
string id = 1;
|
||||
}
|
||||
|
||||
message StopRunResponse {
|
||||
RunSummary stopped_run = 1;
|
||||
}
|
||||
|
||||
message StartRunRequest {
|
||||
string id = 1;
|
||||
}
|
||||
|
||||
message StartRunResponse {
|
||||
bool started = 1;
|
||||
}
|
||||
|
||||
message StartAllRunsRequest {}
|
||||
|
||||
message StartAllRunsResponse {
|
||||
repeated string runs_started = 1;
|
||||
}
|
||||
|
||||
message StopAllRunsRequest {}
|
||||
|
||||
message StopAllRunsResponse {
|
||||
repeated RunSummary runs_stopped = 1;
|
||||
}
|
||||
|
||||
message ClearRunRequest {
|
||||
string id = 1;
|
||||
}
|
||||
|
||||
message ClearRunResponse {
|
||||
RunSummary cleared_run = 1;
|
||||
}
|
||||
|
||||
message ClearAllRunsRequest {}
|
||||
|
||||
message ClearAllRunsResponse {
|
||||
repeated RunSummary cleared_runs = 1;
|
||||
repeated RunSummary remaining_runs = 2;
|
||||
}
|
||||
|
||||
service BacktesterService {
|
||||
rpc ExecuteStrategyFromFile(ExecuteStrategyFromFileRequest) returns (ExecuteStrategyResponse) {
|
||||
option (google.api.http) = {
|
||||
get: "/v1/executestrategyfromfile"
|
||||
post: "/v1/executestrategyfromfile"
|
||||
};
|
||||
}
|
||||
rpc ExecuteStrategyFromConfig(ExecuteStrategyFromConfigRequest) returns (ExecuteStrategyResponse) {
|
||||
option (google.api.http) = {
|
||||
get: "/v1/executestrategyfromconfig"
|
||||
post: "/v1/executestrategyfromconfig"
|
||||
};
|
||||
}
|
||||
rpc ListAllRuns(ListAllRunsRequest) returns (ListAllRunsResponse) {
|
||||
option (google.api.http) = {
|
||||
get: "/v1/listallruns"
|
||||
};
|
||||
}
|
||||
rpc StartRun(StartRunRequest) returns (StartRunResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/v1/startrun"
|
||||
};
|
||||
}
|
||||
rpc StartAllRuns(StartAllRunsRequest) returns (StartAllRunsResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/v1/startallruns"
|
||||
};
|
||||
}
|
||||
rpc StopRun(StopRunRequest) returns (StopRunResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/v1/stoprun"
|
||||
};
|
||||
}
|
||||
rpc StopAllRuns(StopAllRunsRequest) returns (StopAllRunsResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/v1/stopallruns"
|
||||
};
|
||||
}
|
||||
rpc ClearRun(ClearRunRequest) returns (ClearRunResponse) {
|
||||
option (google.api.http) = {
|
||||
delete: "/v1/clearrun"
|
||||
};
|
||||
}
|
||||
rpc ClearAllRuns(ClearAllRunsRequest) returns (ClearAllRunsResponse) {
|
||||
option (google.api.http) = {
|
||||
delete: "/v1/clearallruns"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,60 @@
|
||||
"application/json"
|
||||
],
|
||||
"paths": {
|
||||
"/v1/clearallruns": {
|
||||
"delete": {
|
||||
"operationId": "BacktesterService_ClearAllRuns",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/btrpcClearAllRunsResponse"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "An unexpected error response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/rpcStatus"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"BacktesterService"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/v1/clearrun": {
|
||||
"delete": {
|
||||
"operationId": "BacktesterService_ClearRun",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/btrpcClearRunResponse"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "An unexpected error response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/rpcStatus"
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"BacktesterService"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/v1/executestrategyfromconfig": {
|
||||
"get": {
|
||||
"post": {
|
||||
"operationId": "BacktesterService_ExecuteStrategyFromConfig",
|
||||
"responses": {
|
||||
"200": {
|
||||
@@ -34,6 +86,18 @@
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "doNotRunImmediately",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"name": "doNotStore",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"name": "config.nickname",
|
||||
"in": "query",
|
||||
@@ -299,7 +363,7 @@
|
||||
}
|
||||
},
|
||||
"/v1/executestrategyfromfile": {
|
||||
"get": {
|
||||
"post": {
|
||||
"operationId": "BacktesterService_ExecuteStrategyFromFile",
|
||||
"responses": {
|
||||
"200": {
|
||||
@@ -321,6 +385,144 @@
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "doNotRunImmediately",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"name": "doNotStore",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "boolean"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"BacktesterService"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/v1/listallruns": {
|
||||
"get": {
|
||||
"operationId": "BacktesterService_ListAllRuns",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/btrpcListAllRunsResponse"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "An unexpected error response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/rpcStatus"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"BacktesterService"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/v1/startallruns": {
|
||||
"post": {
|
||||
"operationId": "BacktesterService_StartAllRuns",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/btrpcStartAllRunsResponse"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "An unexpected error response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/rpcStatus"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"BacktesterService"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/v1/startrun": {
|
||||
"post": {
|
||||
"operationId": "BacktesterService_StartRun",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/btrpcStartRunResponse"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "An unexpected error response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/rpcStatus"
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
"BacktesterService"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/v1/stopallruns": {
|
||||
"post": {
|
||||
"operationId": "BacktesterService_StopAllRuns",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/btrpcStopAllRunsResponse"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "An unexpected error response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/rpcStatus"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"BacktesterService"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/v1/stoprun": {
|
||||
"post": {
|
||||
"operationId": "BacktesterService_StopRun",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/btrpcStopRunResponse"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"description": "An unexpected error response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/rpcStatus"
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
@@ -354,6 +556,31 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"btrpcClearAllRunsResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"clearedRuns": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/btrpcRunSummary"
|
||||
}
|
||||
},
|
||||
"remainingRuns": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/btrpcRunSummary"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"btrpcClearRunResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"clearedRun": {
|
||||
"$ref": "#/definitions/btrpcRunSummary"
|
||||
}
|
||||
}
|
||||
},
|
||||
"btrpcConfig": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -560,11 +787,8 @@
|
||||
"btrpcExecuteStrategyResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"success": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
"run": {
|
||||
"$ref": "#/definitions/btrpcRunSummary"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -607,6 +831,17 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"btrpcListAllRunsResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"runs": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/btrpcRunSummary"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"btrpcLiveData": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -658,6 +893,35 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"btrpcRunSummary": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"strategyName": {
|
||||
"type": "string"
|
||||
},
|
||||
"dateLoaded": {
|
||||
"type": "string"
|
||||
},
|
||||
"dateStarted": {
|
||||
"type": "string"
|
||||
},
|
||||
"dateEnded": {
|
||||
"type": "string"
|
||||
},
|
||||
"closed": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"liveTesting": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"realOrders": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"btrpcSpotDetails": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -669,6 +933,25 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"btrpcStartAllRunsResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"runsStarted": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"btrpcStartRunResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"started": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"btrpcStatisticSettings": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -677,6 +960,25 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"btrpcStopAllRunsResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"runsStopped": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/btrpcRunSummary"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"btrpcStopRunResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"stoppedRun": {
|
||||
"$ref": "#/definitions/btrpcRunSummary"
|
||||
}
|
||||
}
|
||||
},
|
||||
"btrpcStrategySettings": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -24,6 +24,13 @@ const _ = grpc.SupportPackageIsVersion7
|
||||
type BacktesterServiceClient interface {
|
||||
ExecuteStrategyFromFile(ctx context.Context, in *ExecuteStrategyFromFileRequest, opts ...grpc.CallOption) (*ExecuteStrategyResponse, error)
|
||||
ExecuteStrategyFromConfig(ctx context.Context, in *ExecuteStrategyFromConfigRequest, opts ...grpc.CallOption) (*ExecuteStrategyResponse, error)
|
||||
ListAllRuns(ctx context.Context, in *ListAllRunsRequest, opts ...grpc.CallOption) (*ListAllRunsResponse, error)
|
||||
StartRun(ctx context.Context, in *StartRunRequest, opts ...grpc.CallOption) (*StartRunResponse, error)
|
||||
StartAllRuns(ctx context.Context, in *StartAllRunsRequest, opts ...grpc.CallOption) (*StartAllRunsResponse, error)
|
||||
StopRun(ctx context.Context, in *StopRunRequest, opts ...grpc.CallOption) (*StopRunResponse, error)
|
||||
StopAllRuns(ctx context.Context, in *StopAllRunsRequest, opts ...grpc.CallOption) (*StopAllRunsResponse, error)
|
||||
ClearRun(ctx context.Context, in *ClearRunRequest, opts ...grpc.CallOption) (*ClearRunResponse, error)
|
||||
ClearAllRuns(ctx context.Context, in *ClearAllRunsRequest, opts ...grpc.CallOption) (*ClearAllRunsResponse, error)
|
||||
}
|
||||
|
||||
type backtesterServiceClient struct {
|
||||
@@ -52,12 +59,82 @@ func (c *backtesterServiceClient) ExecuteStrategyFromConfig(ctx context.Context,
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *backtesterServiceClient) ListAllRuns(ctx context.Context, in *ListAllRunsRequest, opts ...grpc.CallOption) (*ListAllRunsResponse, error) {
|
||||
out := new(ListAllRunsResponse)
|
||||
err := c.cc.Invoke(ctx, "/btrpc.BacktesterService/ListAllRuns", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *backtesterServiceClient) StartRun(ctx context.Context, in *StartRunRequest, opts ...grpc.CallOption) (*StartRunResponse, error) {
|
||||
out := new(StartRunResponse)
|
||||
err := c.cc.Invoke(ctx, "/btrpc.BacktesterService/StartRun", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *backtesterServiceClient) StartAllRuns(ctx context.Context, in *StartAllRunsRequest, opts ...grpc.CallOption) (*StartAllRunsResponse, error) {
|
||||
out := new(StartAllRunsResponse)
|
||||
err := c.cc.Invoke(ctx, "/btrpc.BacktesterService/StartAllRuns", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *backtesterServiceClient) StopRun(ctx context.Context, in *StopRunRequest, opts ...grpc.CallOption) (*StopRunResponse, error) {
|
||||
out := new(StopRunResponse)
|
||||
err := c.cc.Invoke(ctx, "/btrpc.BacktesterService/StopRun", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *backtesterServiceClient) StopAllRuns(ctx context.Context, in *StopAllRunsRequest, opts ...grpc.CallOption) (*StopAllRunsResponse, error) {
|
||||
out := new(StopAllRunsResponse)
|
||||
err := c.cc.Invoke(ctx, "/btrpc.BacktesterService/StopAllRuns", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *backtesterServiceClient) ClearRun(ctx context.Context, in *ClearRunRequest, opts ...grpc.CallOption) (*ClearRunResponse, error) {
|
||||
out := new(ClearRunResponse)
|
||||
err := c.cc.Invoke(ctx, "/btrpc.BacktesterService/ClearRun", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *backtesterServiceClient) ClearAllRuns(ctx context.Context, in *ClearAllRunsRequest, opts ...grpc.CallOption) (*ClearAllRunsResponse, error) {
|
||||
out := new(ClearAllRunsResponse)
|
||||
err := c.cc.Invoke(ctx, "/btrpc.BacktesterService/ClearAllRuns", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// BacktesterServiceServer is the server API for BacktesterService service.
|
||||
// All implementations must embed UnimplementedBacktesterServiceServer
|
||||
// for forward compatibility
|
||||
type BacktesterServiceServer interface {
|
||||
ExecuteStrategyFromFile(context.Context, *ExecuteStrategyFromFileRequest) (*ExecuteStrategyResponse, error)
|
||||
ExecuteStrategyFromConfig(context.Context, *ExecuteStrategyFromConfigRequest) (*ExecuteStrategyResponse, error)
|
||||
ListAllRuns(context.Context, *ListAllRunsRequest) (*ListAllRunsResponse, error)
|
||||
StartRun(context.Context, *StartRunRequest) (*StartRunResponse, error)
|
||||
StartAllRuns(context.Context, *StartAllRunsRequest) (*StartAllRunsResponse, error)
|
||||
StopRun(context.Context, *StopRunRequest) (*StopRunResponse, error)
|
||||
StopAllRuns(context.Context, *StopAllRunsRequest) (*StopAllRunsResponse, error)
|
||||
ClearRun(context.Context, *ClearRunRequest) (*ClearRunResponse, error)
|
||||
ClearAllRuns(context.Context, *ClearAllRunsRequest) (*ClearAllRunsResponse, error)
|
||||
mustEmbedUnimplementedBacktesterServiceServer()
|
||||
}
|
||||
|
||||
@@ -71,6 +148,27 @@ func (UnimplementedBacktesterServiceServer) ExecuteStrategyFromFile(context.Cont
|
||||
func (UnimplementedBacktesterServiceServer) ExecuteStrategyFromConfig(context.Context, *ExecuteStrategyFromConfigRequest) (*ExecuteStrategyResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ExecuteStrategyFromConfig not implemented")
|
||||
}
|
||||
func (UnimplementedBacktesterServiceServer) ListAllRuns(context.Context, *ListAllRunsRequest) (*ListAllRunsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListAllRuns not implemented")
|
||||
}
|
||||
func (UnimplementedBacktesterServiceServer) StartRun(context.Context, *StartRunRequest) (*StartRunResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method StartRun not implemented")
|
||||
}
|
||||
func (UnimplementedBacktesterServiceServer) StartAllRuns(context.Context, *StartAllRunsRequest) (*StartAllRunsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method StartAllRuns not implemented")
|
||||
}
|
||||
func (UnimplementedBacktesterServiceServer) StopRun(context.Context, *StopRunRequest) (*StopRunResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method StopRun not implemented")
|
||||
}
|
||||
func (UnimplementedBacktesterServiceServer) StopAllRuns(context.Context, *StopAllRunsRequest) (*StopAllRunsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method StopAllRuns not implemented")
|
||||
}
|
||||
func (UnimplementedBacktesterServiceServer) ClearRun(context.Context, *ClearRunRequest) (*ClearRunResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ClearRun not implemented")
|
||||
}
|
||||
func (UnimplementedBacktesterServiceServer) ClearAllRuns(context.Context, *ClearAllRunsRequest) (*ClearAllRunsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ClearAllRuns not implemented")
|
||||
}
|
||||
func (UnimplementedBacktesterServiceServer) mustEmbedUnimplementedBacktesterServiceServer() {}
|
||||
|
||||
// UnsafeBacktesterServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
@@ -120,6 +218,132 @@ func _BacktesterService_ExecuteStrategyFromConfig_Handler(srv interface{}, ctx c
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _BacktesterService_ListAllRuns_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ListAllRunsRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(BacktesterServiceServer).ListAllRuns(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/btrpc.BacktesterService/ListAllRuns",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(BacktesterServiceServer).ListAllRuns(ctx, req.(*ListAllRunsRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _BacktesterService_StartRun_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(StartRunRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(BacktesterServiceServer).StartRun(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/btrpc.BacktesterService/StartRun",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(BacktesterServiceServer).StartRun(ctx, req.(*StartRunRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _BacktesterService_StartAllRuns_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(StartAllRunsRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(BacktesterServiceServer).StartAllRuns(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/btrpc.BacktesterService/StartAllRuns",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(BacktesterServiceServer).StartAllRuns(ctx, req.(*StartAllRunsRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _BacktesterService_StopRun_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(StopRunRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(BacktesterServiceServer).StopRun(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/btrpc.BacktesterService/StopRun",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(BacktesterServiceServer).StopRun(ctx, req.(*StopRunRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _BacktesterService_StopAllRuns_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(StopAllRunsRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(BacktesterServiceServer).StopAllRuns(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/btrpc.BacktesterService/StopAllRuns",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(BacktesterServiceServer).StopAllRuns(ctx, req.(*StopAllRunsRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _BacktesterService_ClearRun_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ClearRunRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(BacktesterServiceServer).ClearRun(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/btrpc.BacktesterService/ClearRun",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(BacktesterServiceServer).ClearRun(ctx, req.(*ClearRunRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _BacktesterService_ClearAllRuns_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ClearAllRunsRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(BacktesterServiceServer).ClearAllRuns(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/btrpc.BacktesterService/ClearAllRuns",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(BacktesterServiceServer).ClearAllRuns(ctx, req.(*ClearAllRunsRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// BacktesterService_ServiceDesc is the grpc.ServiceDesc for BacktesterService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
@@ -135,6 +359,34 @@ var BacktesterService_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "ExecuteStrategyFromConfig",
|
||||
Handler: _BacktesterService_ExecuteStrategyFromConfig_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ListAllRuns",
|
||||
Handler: _BacktesterService_ListAllRuns_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "StartRun",
|
||||
Handler: _BacktesterService_StartRun_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "StartAllRuns",
|
||||
Handler: _BacktesterService_StartAllRuns_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "StopRun",
|
||||
Handler: _BacktesterService_StopRun_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "StopAllRuns",
|
||||
Handler: _BacktesterService_StopAllRuns_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ClearRun",
|
||||
Handler: _BacktesterService_ClearRun_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ClearAllRuns",
|
||||
Handler: _BacktesterService_ClearAllRuns_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "btrpc.proto",
|
||||
|
||||
@@ -3,7 +3,10 @@ package engine
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gofrs/uuid"
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/data"
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/eventhandlers/eventholder"
|
||||
@@ -17,6 +20,7 @@ import (
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/eventtypes/order"
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/eventtypes/signal"
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/funding"
|
||||
gctcommon "github.com/thrasher-corp/gocryptotrader/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
gctexchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
@@ -25,12 +29,17 @@ import (
|
||||
)
|
||||
|
||||
// New returns a new BackTest instance
|
||||
func New() *BackTest {
|
||||
return &BackTest{
|
||||
func New() (*BackTest, error) {
|
||||
bt := &BackTest{
|
||||
shutdown: make(chan struct{}),
|
||||
Datas: &data.HandlerPerCurrency{},
|
||||
EventQueue: &eventholder.Holder{},
|
||||
}
|
||||
err := bt.SetupMetaData()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bt, nil
|
||||
}
|
||||
|
||||
// Reset BackTest values to default
|
||||
@@ -46,9 +55,73 @@ func (bt *BackTest) Reset() {
|
||||
bt.databaseManager = nil
|
||||
}
|
||||
|
||||
// ExecuteStrategy executes the strategy using the provided configs
|
||||
func (bt *BackTest) ExecuteStrategy(waitForOfflineCompletion bool) error {
|
||||
if bt == nil {
|
||||
return gctcommon.ErrNilPointer
|
||||
}
|
||||
bt.m.Lock()
|
||||
if bt.MetaData.DateLoaded.IsZero() {
|
||||
bt.m.Unlock()
|
||||
return errNotSetup
|
||||
}
|
||||
if !bt.MetaData.Closed && !bt.MetaData.DateStarted.IsZero() {
|
||||
bt.m.Unlock()
|
||||
return fmt.Errorf("%w %v %v", errRunIsRunning, bt.MetaData.ID, bt.MetaData.Strategy)
|
||||
}
|
||||
if bt.MetaData.Closed {
|
||||
bt.m.Unlock()
|
||||
return fmt.Errorf("%w %v %v", errAlreadyRan, bt.MetaData.ID, bt.MetaData.Strategy)
|
||||
}
|
||||
|
||||
bt.MetaData.DateStarted = time.Now()
|
||||
liveTesting := bt.MetaData.LiveTesting
|
||||
bt.m.Unlock()
|
||||
var wg sync.WaitGroup
|
||||
if waitForOfflineCompletion {
|
||||
wg.Add(1)
|
||||
}
|
||||
go func() {
|
||||
if waitForOfflineCompletion {
|
||||
defer wg.Done()
|
||||
}
|
||||
if liveTesting {
|
||||
if waitForOfflineCompletion {
|
||||
log.Errorf(common.Backtester, "%v cannot wait for completion of a live test", errCannotHandleRequest)
|
||||
return
|
||||
}
|
||||
err := bt.RunLive()
|
||||
if err != nil {
|
||||
log.Error(log.Global, err)
|
||||
}
|
||||
} else {
|
||||
bt.Run()
|
||||
close(bt.shutdown)
|
||||
bt.m.Lock()
|
||||
bt.MetaData.Closed = true
|
||||
bt.MetaData.DateEnded = time.Now()
|
||||
bt.m.Unlock()
|
||||
err := bt.Statistic.CalculateAllResults()
|
||||
if err != nil {
|
||||
log.Error(log.Global, err)
|
||||
return
|
||||
}
|
||||
err = bt.Reports.GenerateReport()
|
||||
if err != nil {
|
||||
log.Error(log.Global, err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
wg.Wait()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Run will iterate over loaded data events
|
||||
// save them and then handle the event based on its type
|
||||
func (bt *BackTest) Run() {
|
||||
if bt.MetaData.DateLoaded.IsZero() {
|
||||
return
|
||||
}
|
||||
log.Info(common.Backtester, "Running backtester against pre-defined data")
|
||||
dataLoadingIssue:
|
||||
for ev := bt.EventQueue.NextEvent(); ; ev = bt.EventQueue.NextEvent() {
|
||||
@@ -469,5 +542,109 @@ func (bt *BackTest) processFuturesFillEvent(ev fill.Event, funds funding.IFundRe
|
||||
|
||||
// Stop shuts down the live data loop
|
||||
func (bt *BackTest) Stop() {
|
||||
if bt == nil {
|
||||
return
|
||||
}
|
||||
bt.m.Lock()
|
||||
defer bt.m.Unlock()
|
||||
if bt.MetaData.Closed {
|
||||
return
|
||||
}
|
||||
close(bt.shutdown)
|
||||
bt.MetaData.Closed = true
|
||||
bt.MetaData.DateEnded = time.Now()
|
||||
err := bt.Statistic.CalculateAllResults()
|
||||
if err != nil {
|
||||
log.Error(log.Global, err)
|
||||
return
|
||||
}
|
||||
err = bt.Reports.GenerateReport()
|
||||
if err != nil {
|
||||
log.Error(log.Global, err)
|
||||
}
|
||||
}
|
||||
|
||||
// GenerateSummary creates a summary of a backtesting/livestrategy run
|
||||
// this summary contains many details of a run
|
||||
func (bt *BackTest) GenerateSummary() (*RunSummary, error) {
|
||||
if bt == nil {
|
||||
return nil, gctcommon.ErrNilPointer
|
||||
}
|
||||
bt.m.Lock()
|
||||
defer bt.m.Unlock()
|
||||
return &RunSummary{
|
||||
MetaData: bt.MetaData,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SetupMetaData will populate metadata fields
|
||||
func (bt *BackTest) SetupMetaData() error {
|
||||
if bt == nil {
|
||||
return gctcommon.ErrNilPointer
|
||||
}
|
||||
bt.m.Lock()
|
||||
defer bt.m.Unlock()
|
||||
if !bt.MetaData.ID.IsNil() && !bt.MetaData.DateLoaded.IsZero() {
|
||||
// already setup
|
||||
return nil
|
||||
}
|
||||
id, err := uuid.NewV4()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
bt.MetaData.ID = id
|
||||
bt.MetaData.DateLoaded = time.Now()
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsRunning checks if the run is running
|
||||
func (bt *BackTest) IsRunning() bool {
|
||||
if bt == nil {
|
||||
return false
|
||||
}
|
||||
bt.m.Lock()
|
||||
defer bt.m.Unlock()
|
||||
return !bt.MetaData.DateStarted.IsZero() && !bt.MetaData.Closed
|
||||
}
|
||||
|
||||
// HasRan checks if the run has been ran
|
||||
func (bt *BackTest) HasRan() bool {
|
||||
if bt == nil {
|
||||
return false
|
||||
}
|
||||
bt.m.Lock()
|
||||
defer bt.m.Unlock()
|
||||
return bt.MetaData.Closed
|
||||
}
|
||||
|
||||
// Equal checks if the incoming run matches
|
||||
func (bt *BackTest) Equal(bt2 *BackTest) bool {
|
||||
if bt == nil || bt2 == nil {
|
||||
return false
|
||||
}
|
||||
bt.m.Lock()
|
||||
btM := bt.MetaData
|
||||
bt.m.Unlock()
|
||||
// if they are actually the same pointer
|
||||
// locks must be handled separately
|
||||
bt2.m.Lock()
|
||||
btM2 := bt2.MetaData
|
||||
bt2.m.Unlock()
|
||||
return btM == btM2
|
||||
}
|
||||
|
||||
// MatchesID checks if the backtesting run's ID matches the supplied
|
||||
func (bt *BackTest) MatchesID(id uuid.UUID) bool {
|
||||
if bt == nil {
|
||||
return false
|
||||
}
|
||||
if id.IsNil() {
|
||||
return false
|
||||
}
|
||||
bt.m.Lock()
|
||||
defer bt.m.Unlock()
|
||||
if bt.MetaData.ID.IsNil() {
|
||||
return false
|
||||
}
|
||||
return bt.MetaData.ID == id
|
||||
}
|
||||
|
||||
@@ -2,11 +2,14 @@ package engine
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gofrs/uuid"
|
||||
"github.com/shopspring/decimal"
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/data"
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/data/kline"
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/eventhandlers/eventholder"
|
||||
@@ -24,6 +27,7 @@ import (
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/eventtypes/signal"
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/funding"
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/report"
|
||||
gctcommon "github.com/thrasher-corp/gocryptotrader/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
"github.com/thrasher-corp/gocryptotrader/engine"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
@@ -180,7 +184,19 @@ func TestFullCycle(t *testing.T) {
|
||||
|
||||
func TestStop(t *testing.T) {
|
||||
t.Parallel()
|
||||
bt := BackTest{shutdown: make(chan struct{})}
|
||||
bt := &BackTest{
|
||||
shutdown: make(chan struct{}),
|
||||
Statistic: &statistics.Statistic{},
|
||||
}
|
||||
bt.Stop()
|
||||
tt := bt.MetaData.DateEnded
|
||||
|
||||
bt.Stop()
|
||||
if !tt.Equal(bt.MetaData.DateEnded) {
|
||||
t.Errorf("received '%v' expected '%v'", bt.MetaData.DateEnded, tt)
|
||||
}
|
||||
|
||||
bt = nil
|
||||
bt.Stop()
|
||||
}
|
||||
|
||||
@@ -965,3 +981,232 @@ func TestProcessFuturesFillEvent(t *testing.T) {
|
||||
t.Errorf("received '%v' expected '%v'", err, expectedError)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateSummary(t *testing.T) {
|
||||
t.Parallel()
|
||||
bt := &BackTest{}
|
||||
sum, err := bt.GenerateSummary()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
if !sum.MetaData.ID.IsNil() {
|
||||
t.Errorf("received '%v' expected '%v'", sum.MetaData.ID, "")
|
||||
}
|
||||
id, err := uuid.NewV4()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
bt.MetaData.ID = id
|
||||
sum, err = bt.GenerateSummary()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
if sum.MetaData.ID != id {
|
||||
t.Errorf("received '%v' expected '%v'", sum.MetaData.ID, id)
|
||||
}
|
||||
|
||||
bt = nil
|
||||
_, err = bt.GenerateSummary()
|
||||
if !errors.Is(err, gctcommon.ErrNilPointer) {
|
||||
t.Errorf("received '%v' expected '%v'", err, gctcommon.ErrNilPointer)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetupMetaData(t *testing.T) {
|
||||
t.Parallel()
|
||||
bt := &BackTest{}
|
||||
err := bt.SetupMetaData()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
if bt.MetaData.ID.IsNil() {
|
||||
t.Errorf("received '%v' expected '%v'", bt.MetaData.ID, "an ID")
|
||||
}
|
||||
firstID := bt.MetaData.ID
|
||||
err = bt.SetupMetaData()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
if bt.MetaData.ID != firstID {
|
||||
t.Errorf("received '%v' expected '%v'", bt.MetaData.ID, firstID)
|
||||
}
|
||||
|
||||
bt = nil
|
||||
err = bt.SetupMetaData()
|
||||
if !errors.Is(err, gctcommon.ErrNilPointer) {
|
||||
t.Errorf("received '%v' expected '%v'", err, gctcommon.ErrNilPointer)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsRunning(t *testing.T) {
|
||||
t.Parallel()
|
||||
bt := &BackTest{}
|
||||
if bt.IsRunning() {
|
||||
t.Errorf("received '%v' expected '%v'", true, false)
|
||||
}
|
||||
|
||||
bt.MetaData.DateStarted = time.Now()
|
||||
if !bt.IsRunning() {
|
||||
t.Errorf("received '%v' expected '%v'", false, true)
|
||||
}
|
||||
|
||||
bt.MetaData.Closed = true
|
||||
if bt.IsRunning() {
|
||||
t.Errorf("received '%v' expected '%v'", true, false)
|
||||
}
|
||||
|
||||
bt = nil
|
||||
if bt.IsRunning() {
|
||||
t.Errorf("received '%v' expected '%v'", true, false)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHasRan(t *testing.T) {
|
||||
t.Parallel()
|
||||
bt := &BackTest{}
|
||||
if bt.HasRan() {
|
||||
t.Errorf("received '%v' expected '%v'", true, false)
|
||||
}
|
||||
|
||||
bt.MetaData.DateStarted = time.Now()
|
||||
if bt.HasRan() {
|
||||
t.Errorf("received '%v' expected '%v'", false, true)
|
||||
}
|
||||
|
||||
bt.MetaData.Closed = true
|
||||
if !bt.HasRan() {
|
||||
t.Errorf("received '%v' expected '%v'", true, false)
|
||||
}
|
||||
|
||||
bt = nil
|
||||
if bt.HasRan() {
|
||||
t.Errorf("received '%v' expected '%v'", true, false)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEqual(t *testing.T) {
|
||||
t.Parallel()
|
||||
bt := &BackTest{}
|
||||
bt2 := &BackTest{}
|
||||
bt3 := &BackTest{}
|
||||
if !bt.Equal(bt2) {
|
||||
t.Errorf("received '%v' expected '%v'", false, true)
|
||||
}
|
||||
|
||||
err := bt.SetupMetaData()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
bt2.MetaData = bt.MetaData
|
||||
if !bt.Equal(bt2) {
|
||||
t.Errorf("received '%v' expected '%v'", false, true)
|
||||
}
|
||||
|
||||
if bt.Equal(nil) {
|
||||
t.Errorf("received '%v' expected '%v'", true, false)
|
||||
}
|
||||
|
||||
err = bt3.SetupMetaData()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
if bt.Equal(bt3) {
|
||||
t.Errorf("received '%v' expected '%v'", true, false)
|
||||
}
|
||||
|
||||
bt = nil
|
||||
if bt.Equal(bt2) {
|
||||
t.Errorf("received '%v' expected '%v'", true, false)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMatchesID(t *testing.T) {
|
||||
t.Parallel()
|
||||
bt := &BackTest{}
|
||||
if bt.MatchesID(uuid.Nil) {
|
||||
t.Errorf("received '%v' expected '%v'", true, false)
|
||||
}
|
||||
|
||||
err := bt.SetupMetaData()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
|
||||
if bt.MatchesID(uuid.Nil) {
|
||||
t.Errorf("received '%v' expected '%v'", true, false)
|
||||
}
|
||||
|
||||
if !bt.MatchesID(bt.MetaData.ID) {
|
||||
t.Errorf("received '%v' expected '%v'", false, true)
|
||||
}
|
||||
|
||||
id := bt.MetaData.ID
|
||||
bt.MetaData.ID = uuid.Nil
|
||||
if bt.MatchesID(id) {
|
||||
t.Errorf("received '%v' expected '%v'", true, false)
|
||||
}
|
||||
|
||||
bt = nil
|
||||
if bt.MatchesID(id) {
|
||||
t.Errorf("received '%v' expected '%v'", true, false)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecuteStrategy(t *testing.T) {
|
||||
t.Parallel()
|
||||
bt := &BackTest{}
|
||||
err := bt.ExecuteStrategy(false)
|
||||
if !errors.Is(err, errNotSetup) {
|
||||
t.Errorf("received '%v' expected '%v'", err, errNotSetup)
|
||||
}
|
||||
bt.MetaData.DateLoaded = time.Now()
|
||||
bt.MetaData.DateStarted = time.Now()
|
||||
err = bt.ExecuteStrategy(false)
|
||||
if !errors.Is(err, errRunIsRunning) {
|
||||
t.Errorf("received '%v' expected '%v'", err, errRunIsRunning)
|
||||
}
|
||||
|
||||
strat1 := filepath.Join("..", "config", "strategyexamples", "dca-api-candles.strat")
|
||||
cfg, err := config.ReadStrategyConfigFromFile(strat1)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
|
||||
bt, err = NewFromConfig(cfg, "", "", false)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
bt.Stop()
|
||||
|
||||
err = bt.ExecuteStrategy(true)
|
||||
if !errors.Is(err, errAlreadyRan) {
|
||||
t.Errorf("received '%v' expected '%v'", err, errAlreadyRan)
|
||||
}
|
||||
|
||||
strat2 := filepath.Join("..", "config", "strategyexamples", "dca-candles-live.strat")
|
||||
cfg, err = config.ReadStrategyConfigFromFile(strat2)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
bt, err = NewFromConfig(cfg, "", "", false)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
err = bt.ExecuteStrategy(true)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
|
||||
bt.MetaData.DateStarted = time.Time{}
|
||||
err = bt.ExecuteStrategy(false)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
bt.Stop()
|
||||
|
||||
bt = nil
|
||||
err = bt.ExecuteStrategy(false)
|
||||
if !errors.Is(err, gctcommon.ErrNilPointer) {
|
||||
t.Errorf("received '%v' expected '%v'", err, gctcommon.ErrNilPointer)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,10 @@ package engine
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gofrs/uuid"
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/data"
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/eventhandlers/eventholder"
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/eventhandlers/exchange"
|
||||
@@ -24,11 +27,14 @@ var (
|
||||
errNilData = errors.New("nil data received")
|
||||
errNilExchange = errors.New("nil exchange received")
|
||||
errLiveUSDTrackingNotSupported = errors.New("USD tracking not supported for live data")
|
||||
errNotSetup = errors.New("backtesting run not setup")
|
||||
)
|
||||
|
||||
// BackTest is the main holder of all backtesting functionality
|
||||
type BackTest struct {
|
||||
m sync.Mutex
|
||||
hasHandledEvent bool
|
||||
MetaData RunMetaData
|
||||
shutdown chan struct{}
|
||||
Datas data.Holder
|
||||
Strategy strategies.Handler
|
||||
@@ -42,3 +48,27 @@ type BackTest struct {
|
||||
orderManager *engine.OrderManager
|
||||
databaseManager *engine.DatabaseConnectionManager
|
||||
}
|
||||
|
||||
// RunSummary holds details of a BackTest
|
||||
// rather than passing entire contents around
|
||||
type RunSummary struct {
|
||||
MetaData RunMetaData
|
||||
}
|
||||
|
||||
// RunMetaData contains details about a run such as when it was loaded
|
||||
type RunMetaData struct {
|
||||
ID uuid.UUID
|
||||
Strategy string
|
||||
DateLoaded time.Time
|
||||
DateStarted time.Time
|
||||
DateEnded time.Time
|
||||
Closed bool
|
||||
LiveTesting bool
|
||||
RealOrders bool
|
||||
}
|
||||
|
||||
// RunManager contains all backtesting/livestrategy runs
|
||||
type RunManager struct {
|
||||
m sync.Mutex
|
||||
runs []*BackTest
|
||||
}
|
||||
|
||||
@@ -10,12 +10,14 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/gofrs/uuid"
|
||||
grpcauth "github.com/grpc-ecosystem/go-grpc-middleware/auth"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
||||
"github.com/shopspring/decimal"
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/btrpc"
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/config"
|
||||
gctcommon "github.com/thrasher-corp/gocryptotrader/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/common/crypto"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
"github.com/thrasher-corp/gocryptotrader/database"
|
||||
@@ -32,30 +34,39 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
errBadPort = errors.New("received bad port")
|
||||
errBadPort = errors.New("received bad port")
|
||||
errCannotHandleRequest = errors.New("cannot handle request")
|
||||
)
|
||||
|
||||
// GRPCServer struct
|
||||
type GRPCServer struct {
|
||||
btrpc.BacktesterServiceServer
|
||||
*config.BacktesterConfig
|
||||
config *config.BacktesterConfig
|
||||
manager *RunManager
|
||||
}
|
||||
|
||||
// SetupRPCServer sets up the gRPC server
|
||||
func SetupRPCServer(cfg *config.BacktesterConfig) *GRPCServer {
|
||||
return &GRPCServer{
|
||||
BacktesterConfig: cfg,
|
||||
func SetupRPCServer(cfg *config.BacktesterConfig, manager *RunManager) (*GRPCServer, error) {
|
||||
if cfg == nil {
|
||||
return nil, fmt.Errorf("%w backtester config", common.ErrNilArguments)
|
||||
}
|
||||
if manager == nil {
|
||||
return nil, fmt.Errorf("%w run manager", common.ErrNilArguments)
|
||||
}
|
||||
return &GRPCServer{
|
||||
config: cfg,
|
||||
manager: manager,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// StartRPCServer starts a gRPC server with TLS auth
|
||||
func StartRPCServer(server *GRPCServer) error {
|
||||
targetDir := utils.GetTLSDir(server.GRPC.TLSDir)
|
||||
targetDir := utils.GetTLSDir(server.config.GRPC.TLSDir)
|
||||
if err := gctengine.CheckCerts(targetDir); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Debugf(log.GRPCSys, "Backtester GRPC server enabled. Starting GRPC server on https://%v.\n", server.GRPC.ListenAddress)
|
||||
lis, err := net.Listen("tcp", server.GRPC.ListenAddress)
|
||||
log.Debugf(log.GRPCSys, "Backtester GRPC server enabled. Starting GRPC server on https://%v.\n", server.config.GRPC.ListenAddress)
|
||||
lis, err := net.Listen("tcp", server.config.GRPC.ListenAddress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -81,7 +92,7 @@ func StartRPCServer(server *GRPCServer) error {
|
||||
|
||||
log.Debugln(log.GRPCSys, "GRPC server started!")
|
||||
|
||||
if server.GRPC.GRPCProxyEnabled {
|
||||
if server.config.GRPC.GRPCProxyEnabled {
|
||||
return server.StartRPCRESTProxy()
|
||||
}
|
||||
return nil
|
||||
@@ -89,8 +100,8 @@ func StartRPCServer(server *GRPCServer) error {
|
||||
|
||||
// StartRPCRESTProxy starts a gRPC proxy
|
||||
func (s *GRPCServer) StartRPCRESTProxy() error {
|
||||
log.Debugf(log.GRPCSys, "GRPC proxy server support enabled. Starting gRPC proxy server on http://%v.\n", s.GRPC.GRPCProxyListenAddress)
|
||||
targetDir := utils.GetTLSDir(s.GRPC.TLSDir)
|
||||
log.Debugf(log.GRPCSys, "GRPC proxy server support enabled. Starting gRPC proxy server on http://%v.\n", s.config.GRPC.GRPCProxyListenAddress)
|
||||
targetDir := utils.GetTLSDir(s.config.GRPC.TLSDir)
|
||||
creds, err := credentials.NewClientTLSFromFile(filepath.Join(targetDir, "cert.pem"), "")
|
||||
if err != nil {
|
||||
return fmt.Errorf("unabled to start gRPC proxy. Err: %w", err)
|
||||
@@ -99,18 +110,18 @@ func (s *GRPCServer) StartRPCRESTProxy() error {
|
||||
mux := runtime.NewServeMux()
|
||||
opts := []grpc.DialOption{grpc.WithTransportCredentials(creds),
|
||||
grpc.WithPerRPCCredentials(auth.BasicAuth{
|
||||
Username: s.GRPC.Username,
|
||||
Password: s.GRPC.Password,
|
||||
Username: s.config.GRPC.Username,
|
||||
Password: s.config.GRPC.Password,
|
||||
}),
|
||||
}
|
||||
err = btrpc.RegisterBacktesterServiceHandlerFromEndpoint(context.Background(),
|
||||
mux, s.GRPC.ListenAddress, opts)
|
||||
mux, s.config.GRPC.ListenAddress, opts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to register gRPC proxy. Err: %w", err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
if err = http.ListenAndServe(s.GRPC.GRPCProxyListenAddress, mux); err != nil {
|
||||
if err = http.ListenAndServe(s.config.GRPC.GRPCProxyListenAddress, mux); err != nil {
|
||||
log.Errorf(log.GRPCSys, "GRPC proxy failed to server: %s\n", err)
|
||||
}
|
||||
}()
|
||||
@@ -143,29 +154,93 @@ func (s *GRPCServer) authenticateClient(ctx context.Context) (context.Context, e
|
||||
username := creds[0]
|
||||
password := creds[1]
|
||||
|
||||
if username != s.GRPC.Username ||
|
||||
password != s.GRPC.Password {
|
||||
if username != s.config.GRPC.Username ||
|
||||
password != s.config.GRPC.Password {
|
||||
return ctx, fmt.Errorf("username/password mismatch")
|
||||
}
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
// convertSummary converts a run summary into a RPC format
|
||||
func convertSummary(run *RunSummary) *btrpc.RunSummary {
|
||||
runSummary := &btrpc.RunSummary{
|
||||
Id: run.MetaData.ID.String(),
|
||||
StrategyName: run.MetaData.Strategy,
|
||||
Closed: run.MetaData.Closed,
|
||||
LiveTesting: run.MetaData.LiveTesting,
|
||||
RealOrders: run.MetaData.RealOrders,
|
||||
}
|
||||
if !run.MetaData.DateStarted.IsZero() {
|
||||
runSummary.DateStarted = run.MetaData.DateStarted.Format(gctcommon.SimpleTimeFormatWithTimezone)
|
||||
}
|
||||
if !run.MetaData.DateLoaded.IsZero() {
|
||||
runSummary.DateLoaded = run.MetaData.DateLoaded.Format(gctcommon.SimpleTimeFormatWithTimezone)
|
||||
}
|
||||
if !run.MetaData.DateEnded.IsZero() {
|
||||
runSummary.DateEnded = run.MetaData.DateEnded.Format(gctcommon.SimpleTimeFormatWithTimezone)
|
||||
}
|
||||
return runSummary
|
||||
}
|
||||
|
||||
// ExecuteStrategyFromFile will backtest a strategy from the filepath provided
|
||||
func (s *GRPCServer) ExecuteStrategyFromFile(_ context.Context, request *btrpc.ExecuteStrategyFromFileRequest) (*btrpc.ExecuteStrategyResponse, error) {
|
||||
if s.config == nil {
|
||||
return nil, fmt.Errorf("%w server config", gctcommon.ErrNilPointer)
|
||||
}
|
||||
if s.manager == nil {
|
||||
return nil, fmt.Errorf("%w run manager", gctcommon.ErrNilPointer)
|
||||
}
|
||||
if request == nil {
|
||||
return nil, fmt.Errorf("%w nil request", common.ErrNilArguments)
|
||||
}
|
||||
if request.DoNotRunImmediately && request.DoNotStore {
|
||||
return nil, fmt.Errorf("%w cannot manage a run with both dnr and dns", errCannotHandleRequest)
|
||||
}
|
||||
|
||||
dir := request.StrategyFilePath
|
||||
cfg, err := config.ReadStrategyConfigFromFile(dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = ExecuteStrategy(cfg, s.BacktesterConfig)
|
||||
|
||||
err = cfg.Validate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if cfg == nil {
|
||||
err = fmt.Errorf("%w backtester config", common.ErrNilArguments)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !s.config.Report.GenerateReport {
|
||||
s.config.Report.OutputPath = ""
|
||||
s.config.Report.TemplatePath = ""
|
||||
}
|
||||
|
||||
bt, err := NewFromConfig(cfg, s.config.Report.TemplatePath, s.config.Report.OutputPath, s.config.Verbose)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !request.DoNotStore {
|
||||
err = s.manager.AddRun(bt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if !request.DoNotRunImmediately {
|
||||
err = bt.ExecuteStrategy(false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
btSum, err := bt.GenerateSummary()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &btrpc.ExecuteStrategyResponse{
|
||||
Success: true,
|
||||
Run: convertSummary(btSum),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -173,9 +248,18 @@ func (s *GRPCServer) ExecuteStrategyFromFile(_ context.Context, request *btrpc.E
|
||||
// this should be a preferred method of interacting with backtester, as it allows for very quick
|
||||
// minor tweaks to strategy to determine the best result - SO LONG AS YOU DONT OVERFIT
|
||||
func (s *GRPCServer) ExecuteStrategyFromConfig(_ context.Context, request *btrpc.ExecuteStrategyFromConfigRequest) (*btrpc.ExecuteStrategyResponse, error) {
|
||||
if s.config == nil {
|
||||
return nil, fmt.Errorf("%w server config", gctcommon.ErrNilPointer)
|
||||
}
|
||||
if s.manager == nil {
|
||||
return nil, fmt.Errorf("%w run manager", gctcommon.ErrNilPointer)
|
||||
}
|
||||
if request == nil || request.Config == nil {
|
||||
return nil, fmt.Errorf("%w nil request", common.ErrNilArguments)
|
||||
}
|
||||
if request.DoNotRunImmediately && request.DoNotStore {
|
||||
return nil, fmt.Errorf("%w cannot manage a run with both dnr and dns", errCannotHandleRequest)
|
||||
}
|
||||
|
||||
rfr, err := decimal.NewFromString(request.Config.StatisticSettings.RiskFreeRate)
|
||||
if err != nil {
|
||||
@@ -495,11 +579,185 @@ func (s *GRPCServer) ExecuteStrategyFromConfig(_ context.Context, request *btrpc
|
||||
},
|
||||
}
|
||||
|
||||
err = ExecuteStrategy(cfg, s.BacktesterConfig)
|
||||
if !s.config.Report.GenerateReport {
|
||||
s.config.Report.OutputPath = ""
|
||||
s.config.Report.TemplatePath = ""
|
||||
}
|
||||
|
||||
bt, err := NewFromConfig(cfg, s.config.Report.TemplatePath, s.config.Report.OutputPath, s.config.Verbose)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !request.DoNotStore {
|
||||
err = s.manager.AddRun(bt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if !request.DoNotRunImmediately {
|
||||
err = bt.ExecuteStrategy(false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
btSum, err := bt.GenerateSummary()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &btrpc.ExecuteStrategyResponse{
|
||||
Success: true,
|
||||
Run: convertSummary(btSum),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ListAllRuns returns all backtesting/livestrategy runs managed by the server
|
||||
func (s *GRPCServer) ListAllRuns(_ context.Context, _ *btrpc.ListAllRunsRequest) (*btrpc.ListAllRunsResponse, error) {
|
||||
if s.manager == nil {
|
||||
return nil, fmt.Errorf("%w run manager", gctcommon.ErrNilPointer)
|
||||
}
|
||||
list, err := s.manager.List()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response := make([]*btrpc.RunSummary, len(list))
|
||||
for i := range list {
|
||||
response[i] = convertSummary(list[i])
|
||||
}
|
||||
return &btrpc.ListAllRunsResponse{
|
||||
Runs: response,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// StopRun stops a backtest/livestrategy run in its tracks
|
||||
func (s *GRPCServer) StopRun(_ context.Context, req *btrpc.StopRunRequest) (*btrpc.StopRunResponse, error) {
|
||||
if s.manager == nil {
|
||||
return nil, fmt.Errorf("%w run manager", gctcommon.ErrNilPointer)
|
||||
}
|
||||
if req == nil {
|
||||
return nil, fmt.Errorf("%w StopRunRequest", gctcommon.ErrNilPointer)
|
||||
}
|
||||
id, err := uuid.FromString(req.Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
run, err := s.manager.GetSummary(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = s.manager.StopRun(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &btrpc.StopRunResponse{
|
||||
StoppedRun: convertSummary(run),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// StopAllRuns stops all backtest/livestrategy runs in its tracks
|
||||
func (s *GRPCServer) StopAllRuns(_ context.Context, _ *btrpc.StopAllRunsRequest) (*btrpc.StopAllRunsResponse, error) {
|
||||
if s.manager == nil {
|
||||
return nil, fmt.Errorf("%w run manager", gctcommon.ErrNilPointer)
|
||||
}
|
||||
stopped, err := s.manager.StopAllRuns()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stoppedRuns := make([]*btrpc.RunSummary, len(stopped))
|
||||
for i := range stopped {
|
||||
stoppedRuns[i] = convertSummary(stopped[i])
|
||||
}
|
||||
return &btrpc.StopAllRunsResponse{
|
||||
RunsStopped: stoppedRuns,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// StartRun starts a backtest/livestrategy that was set to not start automatically
|
||||
func (s *GRPCServer) StartRun(_ context.Context, req *btrpc.StartRunRequest) (*btrpc.StartRunResponse, error) {
|
||||
if s.manager == nil {
|
||||
return nil, fmt.Errorf("%w run manager", gctcommon.ErrNilPointer)
|
||||
}
|
||||
if req == nil {
|
||||
return nil, fmt.Errorf("%w StartRunRequest", gctcommon.ErrNilPointer)
|
||||
}
|
||||
id, err := uuid.FromString(req.Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = s.manager.StartRun(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &btrpc.StartRunResponse{
|
||||
Started: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// StartAllRuns starts all backtest/livestrategy runs
|
||||
func (s *GRPCServer) StartAllRuns(_ context.Context, _ *btrpc.StartAllRunsRequest) (*btrpc.StartAllRunsResponse, error) {
|
||||
if s.manager == nil {
|
||||
return nil, fmt.Errorf("%w run manager", gctcommon.ErrNilPointer)
|
||||
}
|
||||
started, err := s.manager.StartAllRuns()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
startedRuns := make([]string, len(started))
|
||||
for i := range started {
|
||||
startedRuns[i] = started[i].String()
|
||||
}
|
||||
return &btrpc.StartAllRunsResponse{
|
||||
RunsStarted: startedRuns,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ClearRun removes a run from memory, but only if it is not running
|
||||
func (s *GRPCServer) ClearRun(_ context.Context, req *btrpc.ClearRunRequest) (*btrpc.ClearRunResponse, error) {
|
||||
if s.manager == nil {
|
||||
return nil, fmt.Errorf("%w run manager", gctcommon.ErrNilPointer)
|
||||
}
|
||||
if req == nil {
|
||||
return nil, fmt.Errorf("%w ClearRunRequest", gctcommon.ErrNilPointer)
|
||||
}
|
||||
id, err := uuid.FromString(req.Id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
run, err := s.manager.GetSummary(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = s.manager.ClearRun(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &btrpc.ClearRunResponse{
|
||||
ClearedRun: convertSummary(run),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ClearAllRuns removes all runs from memory, but only if they are not running
|
||||
func (s *GRPCServer) ClearAllRuns(_ context.Context, _ *btrpc.ClearAllRunsRequest) (*btrpc.ClearAllRunsResponse, error) {
|
||||
if s.manager == nil {
|
||||
return nil, fmt.Errorf("%w run manager", gctcommon.ErrNilPointer)
|
||||
}
|
||||
clearedRuns, remainingRuns, err := s.manager.ClearAllRuns()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
clearedResponse := make([]*btrpc.RunSummary, len(clearedRuns))
|
||||
for i := range clearedRuns {
|
||||
clearedResponse[i] = convertSummary(clearedRuns[i])
|
||||
}
|
||||
remainingResponse := make([]*btrpc.RunSummary, len(remainingRuns))
|
||||
for i := range remainingRuns {
|
||||
remainingResponse[i] = convertSummary(remainingRuns[i])
|
||||
}
|
||||
return &btrpc.ClearAllRunsResponse{
|
||||
ClearedRuns: clearedResponse,
|
||||
RemainingRuns: remainingResponse,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -11,6 +11,11 @@ import (
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/btrpc"
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/data"
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/eventhandlers/eventholder"
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/eventhandlers/statistics"
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/eventhandlers/strategies/ftxcashandcarry"
|
||||
gctcommon "github.com/thrasher-corp/gocryptotrader/common"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
@@ -20,6 +25,22 @@ func TestExecuteStrategyFromFile(t *testing.T) {
|
||||
t.Parallel()
|
||||
s := &GRPCServer{}
|
||||
_, err := s.ExecuteStrategyFromFile(context.Background(), nil)
|
||||
if !errors.Is(err, gctcommon.ErrNilPointer) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, gctcommon.ErrNilPointer)
|
||||
}
|
||||
|
||||
s.config, err = config.GenerateDefaultConfig()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, nil)
|
||||
}
|
||||
s.config.Report.GenerateReport = false
|
||||
_, err = s.ExecuteStrategyFromFile(context.Background(), nil)
|
||||
if !errors.Is(err, gctcommon.ErrNilPointer) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, gctcommon.ErrNilPointer)
|
||||
}
|
||||
|
||||
s.manager = SetupRunManager()
|
||||
_, err = s.ExecuteStrategyFromFile(context.Background(), nil)
|
||||
if !errors.Is(err, common.ErrNilArguments) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, common.ErrNilArguments)
|
||||
}
|
||||
@@ -29,32 +50,43 @@ func TestExecuteStrategyFromFile(t *testing.T) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, common.ErrFileNotFound)
|
||||
}
|
||||
|
||||
_, err = s.ExecuteStrategyFromFile(context.Background(), &btrpc.ExecuteStrategyFromFileRequest{
|
||||
StrategyFilePath: dcaConfigPath,
|
||||
})
|
||||
if !errors.Is(err, common.ErrNilArguments) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, common.ErrNilArguments)
|
||||
}
|
||||
|
||||
s.BacktesterConfig = &config.BacktesterConfig{}
|
||||
_, err = s.ExecuteStrategyFromFile(context.Background(), &btrpc.ExecuteStrategyFromFileRequest{
|
||||
StrategyFilePath: dcaConfigPath,
|
||||
})
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, nil)
|
||||
}
|
||||
|
||||
_, err = s.ExecuteStrategyFromFile(context.Background(), &btrpc.ExecuteStrategyFromFileRequest{
|
||||
StrategyFilePath: dcaConfigPath,
|
||||
DoNotRunImmediately: true,
|
||||
DoNotStore: true,
|
||||
})
|
||||
if !errors.Is(err, errCannotHandleRequest) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, errCannotHandleRequest)
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecuteStrategyFromConfig(t *testing.T) {
|
||||
t.Parallel()
|
||||
s := &GRPCServer{}
|
||||
_, err := s.ExecuteStrategyFromConfig(context.Background(), nil)
|
||||
if !errors.Is(err, common.ErrNilArguments) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, common.ErrNilArguments)
|
||||
if !errors.Is(err, gctcommon.ErrNilPointer) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, gctcommon.ErrNilPointer)
|
||||
}
|
||||
|
||||
s.BacktesterConfig = &config.BacktesterConfig{}
|
||||
_, err = s.ExecuteStrategyFromConfig(context.Background(), &btrpc.ExecuteStrategyFromConfigRequest{})
|
||||
s.config, err = config.GenerateDefaultConfig()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, nil)
|
||||
}
|
||||
_, err = s.ExecuteStrategyFromConfig(context.Background(), nil)
|
||||
if !errors.Is(err, gctcommon.ErrNilPointer) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, gctcommon.ErrNilPointer)
|
||||
}
|
||||
|
||||
s.config.Report.GenerateReport = false
|
||||
s.manager = SetupRunManager()
|
||||
_, err = s.ExecuteStrategyFromConfig(context.Background(), nil)
|
||||
if !errors.Is(err, common.ErrNilArguments) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, common.ErrNilArguments)
|
||||
}
|
||||
@@ -239,6 +271,15 @@ func TestExecuteStrategyFromConfig(t *testing.T) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, nil)
|
||||
}
|
||||
|
||||
_, err = s.ExecuteStrategyFromConfig(context.Background(), &btrpc.ExecuteStrategyFromConfigRequest{
|
||||
DoNotRunImmediately: true,
|
||||
DoNotStore: true,
|
||||
Config: cfg,
|
||||
})
|
||||
if !errors.Is(err, errCannotHandleRequest) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, errCannotHandleRequest)
|
||||
}
|
||||
|
||||
// coverage test to ensure the rest of the config can successfully be converted
|
||||
// this will not have a successful response
|
||||
cfg.FundingSettings.UseExchangeLevelFunding = true
|
||||
@@ -283,3 +324,279 @@ func TestExecuteStrategyFromConfig(t *testing.T) {
|
||||
t.Error("expected an error from a bad setup")
|
||||
}
|
||||
}
|
||||
|
||||
func TestListAllRuns(t *testing.T) {
|
||||
t.Parallel()
|
||||
s := &GRPCServer{}
|
||||
_, err := s.ListAllRuns(context.Background(), nil)
|
||||
if !errors.Is(err, gctcommon.ErrNilPointer) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, gctcommon.ErrNilPointer)
|
||||
}
|
||||
|
||||
s.manager = SetupRunManager()
|
||||
_, err = s.ListAllRuns(context.Background(), nil)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, nil)
|
||||
}
|
||||
|
||||
bt := &BackTest{
|
||||
Strategy: &ftxcashandcarry.Strategy{},
|
||||
EventQueue: &eventholder.Holder{},
|
||||
Datas: &data.HandlerPerCurrency{},
|
||||
Statistic: &statistics.Statistic{},
|
||||
shutdown: make(chan struct{}),
|
||||
}
|
||||
err = s.manager.AddRun(bt)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
resp, err := s.ListAllRuns(context.Background(), &btrpc.ListAllRunsRequest{})
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, nil)
|
||||
}
|
||||
if len(resp.Runs) != 1 {
|
||||
t.Errorf("received '%v' expecting '%v'", len(resp.Runs), 1)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGRPCStopRun(t *testing.T) {
|
||||
t.Parallel()
|
||||
s := &GRPCServer{}
|
||||
_, err := s.StopRun(context.Background(), nil)
|
||||
if !errors.Is(err, gctcommon.ErrNilPointer) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, gctcommon.ErrNilPointer)
|
||||
}
|
||||
|
||||
s.manager = SetupRunManager()
|
||||
_, err = s.StopRun(context.Background(), nil)
|
||||
if !errors.Is(err, gctcommon.ErrNilPointer) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, gctcommon.ErrNilPointer)
|
||||
}
|
||||
|
||||
bt := &BackTest{
|
||||
Strategy: &ftxcashandcarry.Strategy{},
|
||||
EventQueue: &eventholder.Holder{},
|
||||
Datas: &data.HandlerPerCurrency{},
|
||||
Statistic: &statistics.Statistic{},
|
||||
shutdown: make(chan struct{}),
|
||||
}
|
||||
err = s.manager.AddRun(bt)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
_, err = s.StopRun(context.Background(), &btrpc.StopRunRequest{
|
||||
Id: bt.MetaData.ID.String(),
|
||||
})
|
||||
if !errors.Is(err, errRunHasNotRan) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, errRunHasNotRan)
|
||||
}
|
||||
if len(s.manager.runs) != 1 {
|
||||
t.Fatalf("received '%v' expecting '%v'", len(s.manager.runs), 1)
|
||||
}
|
||||
|
||||
s.manager.runs[0].MetaData.DateStarted = time.Now()
|
||||
_, err = s.StopRun(context.Background(), &btrpc.StopRunRequest{
|
||||
Id: bt.MetaData.ID.String(),
|
||||
})
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, nil)
|
||||
}
|
||||
if s.manager.runs[0].MetaData.DateEnded.IsZero() {
|
||||
t.Errorf("received '%v' expecting '%v'", s.manager.runs[0].MetaData.DateEnded, "a date")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGRPCStopAllRuns(t *testing.T) {
|
||||
t.Parallel()
|
||||
s := &GRPCServer{}
|
||||
_, err := s.StopAllRuns(context.Background(), nil)
|
||||
if !errors.Is(err, gctcommon.ErrNilPointer) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, gctcommon.ErrNilPointer)
|
||||
}
|
||||
|
||||
s.manager = SetupRunManager()
|
||||
_, err = s.StopAllRuns(context.Background(), nil)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, nil)
|
||||
}
|
||||
|
||||
bt := &BackTest{
|
||||
Strategy: &ftxcashandcarry.Strategy{},
|
||||
EventQueue: &eventholder.Holder{},
|
||||
Datas: &data.HandlerPerCurrency{},
|
||||
Statistic: &statistics.Statistic{},
|
||||
shutdown: make(chan struct{}),
|
||||
}
|
||||
err = s.manager.AddRun(bt)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
resp, err := s.StopAllRuns(context.Background(), &btrpc.StopAllRunsRequest{})
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, nil)
|
||||
}
|
||||
if len(s.manager.runs) != 1 {
|
||||
t.Fatalf("received '%v' expecting '%v'", len(s.manager.runs), 1)
|
||||
}
|
||||
if len(resp.RunsStopped) != 0 {
|
||||
t.Errorf("received '%v' expecting '%v'", len(resp.RunsStopped), 0)
|
||||
}
|
||||
|
||||
s.manager.runs[0].MetaData.DateStarted = time.Now()
|
||||
resp, err = s.StopAllRuns(context.Background(), &btrpc.StopAllRunsRequest{})
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, nil)
|
||||
}
|
||||
if s.manager.runs[0].MetaData.DateEnded.IsZero() {
|
||||
t.Errorf("received '%v' expecting '%v'", s.manager.runs[0].MetaData.DateEnded, "a date")
|
||||
}
|
||||
if len(resp.RunsStopped) != 1 {
|
||||
t.Errorf("received '%v' expecting '%v'", len(resp.RunsStopped), 1)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGRPCStartRun(t *testing.T) {
|
||||
t.Parallel()
|
||||
s := &GRPCServer{}
|
||||
_, err := s.StartRun(context.Background(), nil)
|
||||
if !errors.Is(err, gctcommon.ErrNilPointer) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, gctcommon.ErrNilPointer)
|
||||
}
|
||||
|
||||
s.manager = SetupRunManager()
|
||||
_, err = s.StartRun(context.Background(), nil)
|
||||
if !errors.Is(err, gctcommon.ErrNilPointer) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, gctcommon.ErrNilPointer)
|
||||
}
|
||||
|
||||
bt := &BackTest{
|
||||
Strategy: &ftxcashandcarry.Strategy{},
|
||||
EventQueue: &eventholder.Holder{},
|
||||
Datas: &data.HandlerPerCurrency{},
|
||||
Statistic: &statistics.Statistic{},
|
||||
shutdown: make(chan struct{}),
|
||||
}
|
||||
err = s.manager.AddRun(bt)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
_, err = s.StartRun(context.Background(), &btrpc.StartRunRequest{
|
||||
Id: bt.MetaData.ID.String(),
|
||||
})
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, nil)
|
||||
}
|
||||
if len(s.manager.runs) != 1 {
|
||||
t.Fatalf("received '%v' expecting '%v'", len(s.manager.runs), 1)
|
||||
}
|
||||
if s.manager.runs[0].MetaData.DateStarted.IsZero() {
|
||||
t.Errorf("received '%v' expecting '%v'", s.manager.runs[0].MetaData.DateStarted, "a date")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGRPCStartAllRuns(t *testing.T) {
|
||||
t.Parallel()
|
||||
s := &GRPCServer{}
|
||||
_, err := s.StartAllRuns(context.Background(), nil)
|
||||
if !errors.Is(err, gctcommon.ErrNilPointer) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, gctcommon.ErrNilPointer)
|
||||
}
|
||||
|
||||
s.manager = SetupRunManager()
|
||||
_, err = s.StartAllRuns(context.Background(), nil)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, nil)
|
||||
}
|
||||
|
||||
bt := &BackTest{
|
||||
Strategy: &ftxcashandcarry.Strategy{},
|
||||
EventQueue: &eventholder.Holder{},
|
||||
Datas: &data.HandlerPerCurrency{},
|
||||
Statistic: &statistics.Statistic{},
|
||||
shutdown: make(chan struct{}),
|
||||
}
|
||||
err = s.manager.AddRun(bt)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
_, err = s.StartAllRuns(context.Background(), &btrpc.StartAllRunsRequest{})
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, nil)
|
||||
}
|
||||
if len(s.manager.runs) != 1 {
|
||||
t.Fatalf("received '%v' expecting '%v'", len(s.manager.runs), 1)
|
||||
}
|
||||
if s.manager.runs[0].MetaData.DateStarted.IsZero() {
|
||||
t.Errorf("received '%v' expecting '%v'", s.manager.runs[0].MetaData.DateStarted, "a date")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGRPCClearRun(t *testing.T) {
|
||||
t.Parallel()
|
||||
s := &GRPCServer{}
|
||||
_, err := s.ClearRun(context.Background(), nil)
|
||||
if !errors.Is(err, gctcommon.ErrNilPointer) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, gctcommon.ErrNilPointer)
|
||||
}
|
||||
|
||||
s.manager = SetupRunManager()
|
||||
_, err = s.ClearRun(context.Background(), nil)
|
||||
if !errors.Is(err, gctcommon.ErrNilPointer) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, gctcommon.ErrNilPointer)
|
||||
}
|
||||
|
||||
bt := &BackTest{
|
||||
Strategy: &ftxcashandcarry.Strategy{},
|
||||
EventQueue: &eventholder.Holder{},
|
||||
Datas: &data.HandlerPerCurrency{},
|
||||
Statistic: &statistics.Statistic{},
|
||||
shutdown: make(chan struct{}),
|
||||
}
|
||||
err = s.manager.AddRun(bt)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
_, err = s.ClearRun(context.Background(), &btrpc.ClearRunRequest{
|
||||
Id: bt.MetaData.ID.String(),
|
||||
})
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, nil)
|
||||
}
|
||||
if len(s.manager.runs) != 0 {
|
||||
t.Fatalf("received '%v' expecting '%v'", len(s.manager.runs), 0)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGRPCClearAllRuns(t *testing.T) {
|
||||
t.Parallel()
|
||||
s := &GRPCServer{}
|
||||
_, err := s.ClearAllRuns(context.Background(), nil)
|
||||
if !errors.Is(err, gctcommon.ErrNilPointer) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, gctcommon.ErrNilPointer)
|
||||
}
|
||||
|
||||
s.manager = SetupRunManager()
|
||||
_, err = s.ClearAllRuns(context.Background(), nil)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, nil)
|
||||
}
|
||||
|
||||
bt := &BackTest{
|
||||
Strategy: &ftxcashandcarry.Strategy{},
|
||||
EventQueue: &eventholder.Holder{},
|
||||
Datas: &data.HandlerPerCurrency{},
|
||||
Statistic: &statistics.Statistic{},
|
||||
shutdown: make(chan struct{}),
|
||||
}
|
||||
err = s.manager.AddRun(bt)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
_, err = s.ClearAllRuns(context.Background(), &btrpc.ClearAllRunsRequest{})
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expecting '%v'", err, nil)
|
||||
}
|
||||
if len(s.manager.runs) != 0 {
|
||||
t.Fatalf("received '%v' expecting '%v'", len(s.manager.runs), 0)
|
||||
}
|
||||
}
|
||||
|
||||
214
backtester/engine/runmanager.go
Normal file
214
backtester/engine/runmanager.go
Normal file
@@ -0,0 +1,214 @@
|
||||
package engine
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/gofrs/uuid"
|
||||
gctcommon "github.com/thrasher-corp/gocryptotrader/common"
|
||||
)
|
||||
|
||||
var (
|
||||
errRunNotFound = errors.New("run not found")
|
||||
errRunAlreadyMonitored = errors.New("run already monitored")
|
||||
errAlreadyRan = errors.New("run already ran")
|
||||
errRunHasNotRan = errors.New("run hasn't ran yet")
|
||||
errRunIsRunning = errors.New("run is already running")
|
||||
errCannotClear = errors.New("cannot clear run")
|
||||
)
|
||||
|
||||
// SetupRunManager creates a run manager to allow the backtester to manage multiple strategies
|
||||
func SetupRunManager() *RunManager {
|
||||
return &RunManager{}
|
||||
}
|
||||
|
||||
// AddRun adds a run to the manager
|
||||
func (r *RunManager) AddRun(b *BackTest) error {
|
||||
if r == nil {
|
||||
return fmt.Errorf("%w RunManager", gctcommon.ErrNilPointer)
|
||||
}
|
||||
if b == nil {
|
||||
return fmt.Errorf("%w BackTest", gctcommon.ErrNilPointer)
|
||||
}
|
||||
r.m.Lock()
|
||||
defer r.m.Unlock()
|
||||
for i := range r.runs {
|
||||
if r.runs[i].Equal(b) {
|
||||
return fmt.Errorf("%w %s %s", errRunAlreadyMonitored, b.MetaData.ID, b.MetaData.Strategy)
|
||||
}
|
||||
}
|
||||
|
||||
err := b.SetupMetaData()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.runs = append(r.runs, b)
|
||||
return nil
|
||||
}
|
||||
|
||||
// List details all backtesting/livestrategy runs
|
||||
func (r *RunManager) List() ([]*RunSummary, error) {
|
||||
if r == nil {
|
||||
return nil, fmt.Errorf("%w RunManager", gctcommon.ErrNilPointer)
|
||||
}
|
||||
r.m.Lock()
|
||||
defer r.m.Unlock()
|
||||
resp := make([]*RunSummary, len(r.runs))
|
||||
for i := range r.runs {
|
||||
sum, err := r.runs[i].GenerateSummary()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp[i] = sum
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// GetSummary returns details about a completed backtesting/livestrategy run
|
||||
func (r *RunManager) GetSummary(id uuid.UUID) (*RunSummary, error) {
|
||||
if r == nil {
|
||||
return nil, fmt.Errorf("%w RunManager", gctcommon.ErrNilPointer)
|
||||
}
|
||||
r.m.Lock()
|
||||
defer r.m.Unlock()
|
||||
for i := range r.runs {
|
||||
if !r.runs[i].MatchesID(id) {
|
||||
continue
|
||||
}
|
||||
return r.runs[i].GenerateSummary()
|
||||
}
|
||||
return nil, fmt.Errorf("%s %w", id, errRunNotFound)
|
||||
}
|
||||
|
||||
// StopRun stops a backtesting/livestrategy run if enabled, this will run CloseAllPositions
|
||||
func (r *RunManager) StopRun(id uuid.UUID) error {
|
||||
if r == nil {
|
||||
return fmt.Errorf("%w RunManager", gctcommon.ErrNilPointer)
|
||||
}
|
||||
r.m.Lock()
|
||||
defer r.m.Unlock()
|
||||
for i := range r.runs {
|
||||
switch {
|
||||
case !r.runs[i].MatchesID(id):
|
||||
continue
|
||||
case r.runs[i].IsRunning():
|
||||
r.runs[i].Stop()
|
||||
return nil
|
||||
case r.runs[i].HasRan():
|
||||
return fmt.Errorf("%w %v", errAlreadyRan, id)
|
||||
default:
|
||||
return fmt.Errorf("%w %v", errRunHasNotRan, id)
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("%s %w", id, errRunNotFound)
|
||||
}
|
||||
|
||||
// StopAllRuns stops all running strategies
|
||||
func (r *RunManager) StopAllRuns() ([]*RunSummary, error) {
|
||||
if r == nil {
|
||||
return nil, fmt.Errorf("%w RunManager", gctcommon.ErrNilPointer)
|
||||
}
|
||||
r.m.Lock()
|
||||
defer r.m.Unlock()
|
||||
resp := make([]*RunSummary, 0, len(r.runs))
|
||||
for i := range r.runs {
|
||||
if !r.runs[i].IsRunning() {
|
||||
continue
|
||||
}
|
||||
r.runs[i].Stop()
|
||||
sum, err := r.runs[i].GenerateSummary()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp = append(resp, sum)
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// StartRun executes a strategy if found
|
||||
func (r *RunManager) StartRun(id uuid.UUID) error {
|
||||
if r == nil {
|
||||
return fmt.Errorf("%w RunManager", gctcommon.ErrNilPointer)
|
||||
}
|
||||
r.m.Lock()
|
||||
defer r.m.Unlock()
|
||||
for i := range r.runs {
|
||||
switch {
|
||||
case !r.runs[i].MatchesID(id):
|
||||
continue
|
||||
case r.runs[i].IsRunning():
|
||||
return fmt.Errorf("%w %v", errRunIsRunning, id)
|
||||
case r.runs[i].HasRan():
|
||||
return fmt.Errorf("%w %v", errAlreadyRan, id)
|
||||
default:
|
||||
return r.runs[i].ExecuteStrategy(false)
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("%s %w", id, errRunNotFound)
|
||||
}
|
||||
|
||||
// StartAllRuns executes all strategies
|
||||
func (r *RunManager) StartAllRuns() ([]uuid.UUID, error) {
|
||||
if r == nil {
|
||||
return nil, fmt.Errorf("%w RunManager", gctcommon.ErrNilPointer)
|
||||
}
|
||||
r.m.Lock()
|
||||
defer r.m.Unlock()
|
||||
executedRuns := make([]uuid.UUID, 0, len(r.runs))
|
||||
for i := range r.runs {
|
||||
if r.runs[i].HasRan() {
|
||||
continue
|
||||
}
|
||||
executedRuns = append(executedRuns, r.runs[i].MetaData.ID)
|
||||
err := r.runs[i].ExecuteStrategy(false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return executedRuns, nil
|
||||
}
|
||||
|
||||
// ClearRun removes a run from memory
|
||||
func (r *RunManager) ClearRun(id uuid.UUID) error {
|
||||
if r == nil {
|
||||
return fmt.Errorf("%w RunManager", gctcommon.ErrNilPointer)
|
||||
}
|
||||
r.m.Lock()
|
||||
defer r.m.Unlock()
|
||||
for i := range r.runs {
|
||||
if !r.runs[i].MatchesID(id) {
|
||||
continue
|
||||
}
|
||||
if r.runs[i].IsRunning() {
|
||||
return fmt.Errorf("%w %v, currently running. Stop it first", errCannotClear, r.runs[i].MetaData.ID)
|
||||
}
|
||||
r.runs = append(r.runs[:i], r.runs[i+1:]...)
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("%s %w", id, errRunNotFound)
|
||||
}
|
||||
|
||||
// ClearAllRuns removes all runs from memory
|
||||
func (r *RunManager) ClearAllRuns() (clearedRuns, remainingRuns []*RunSummary, err error) {
|
||||
if r == nil {
|
||||
return nil, nil, fmt.Errorf("%w RunManager", gctcommon.ErrNilPointer)
|
||||
}
|
||||
r.m.Lock()
|
||||
defer r.m.Unlock()
|
||||
for i := 0; i < len(r.runs); i++ {
|
||||
var run *RunSummary
|
||||
run, err = r.runs[i].GenerateSummary()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if r.runs[i].IsRunning() {
|
||||
remainingRuns = append(remainingRuns, run)
|
||||
} else {
|
||||
clearedRuns = append(clearedRuns, run)
|
||||
r.runs = append(r.runs[:i], r.runs[i+1:]...)
|
||||
i--
|
||||
}
|
||||
}
|
||||
return clearedRuns, remainingRuns, nil
|
||||
}
|
||||
425
backtester/engine/runmanager_test.go
Normal file
425
backtester/engine/runmanager_test.go
Normal file
@@ -0,0 +1,425 @@
|
||||
package engine
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gofrs/uuid"
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/data"
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/eventhandlers/eventholder"
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/eventhandlers/statistics"
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/eventhandlers/strategies/ftxcashandcarry"
|
||||
gctcommon "github.com/thrasher-corp/gocryptotrader/common"
|
||||
)
|
||||
|
||||
func TestSetupRunManager(t *testing.T) {
|
||||
t.Parallel()
|
||||
rm := SetupRunManager()
|
||||
if rm == nil {
|
||||
t.Errorf("received '%v' expected '%v'", rm, "&RunManager{}")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddRun(t *testing.T) {
|
||||
t.Parallel()
|
||||
rm := SetupRunManager()
|
||||
err := rm.AddRun(nil)
|
||||
if !errors.Is(err, gctcommon.ErrNilPointer) {
|
||||
t.Errorf("received '%v' expected '%v'", err, gctcommon.ErrNilPointer)
|
||||
}
|
||||
|
||||
bt := &BackTest{}
|
||||
err = rm.AddRun(bt)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
if bt.MetaData.ID.IsNil() {
|
||||
t.Errorf("received '%v' expected '%v'", bt.MetaData.ID, "a random ID")
|
||||
}
|
||||
if len(rm.runs) != 1 {
|
||||
t.Errorf("received '%v' expected '%v'", len(rm.runs), 1)
|
||||
}
|
||||
|
||||
err = rm.AddRun(bt)
|
||||
if !errors.Is(err, errRunAlreadyMonitored) {
|
||||
t.Errorf("received '%v' expected '%v'", err, errRunAlreadyMonitored)
|
||||
}
|
||||
if len(rm.runs) != 1 {
|
||||
t.Errorf("received '%v' expected '%v'", len(rm.runs), 1)
|
||||
}
|
||||
|
||||
rm = nil
|
||||
err = rm.AddRun(bt)
|
||||
if !errors.Is(err, gctcommon.ErrNilPointer) {
|
||||
t.Errorf("received '%v' expected '%v'", err, gctcommon.ErrNilPointer)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSummary(t *testing.T) {
|
||||
t.Parallel()
|
||||
rm := SetupRunManager()
|
||||
id, err := uuid.NewV4()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
_, err = rm.GetSummary(id)
|
||||
if !errors.Is(err, errRunNotFound) {
|
||||
t.Errorf("received '%v' expected '%v'", err, errRunNotFound)
|
||||
}
|
||||
|
||||
bt := &BackTest{
|
||||
Strategy: &ftxcashandcarry.Strategy{},
|
||||
Statistic: &statistics.Statistic{},
|
||||
}
|
||||
err = rm.AddRun(bt)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
|
||||
sum, err := rm.GetSummary(bt.MetaData.ID)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
if sum.MetaData.ID != bt.MetaData.ID {
|
||||
t.Errorf("received '%v' expected '%v'", sum.MetaData.ID, bt.MetaData.ID)
|
||||
}
|
||||
|
||||
rm = nil
|
||||
_, err = rm.GetSummary(id)
|
||||
if !errors.Is(err, gctcommon.ErrNilPointer) {
|
||||
t.Errorf("received '%v' expected '%v'", err, gctcommon.ErrNilPointer)
|
||||
}
|
||||
}
|
||||
|
||||
func TestList(t *testing.T) {
|
||||
t.Parallel()
|
||||
rm := SetupRunManager()
|
||||
list, err := rm.List()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
if len(list) != 0 {
|
||||
t.Errorf("received '%v' expected '%v'", len(list), 0)
|
||||
}
|
||||
|
||||
bt := &BackTest{
|
||||
Strategy: &ftxcashandcarry.Strategy{},
|
||||
Statistic: &statistics.Statistic{},
|
||||
}
|
||||
err = rm.AddRun(bt)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
|
||||
list, err = rm.List()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
if len(list) != 1 {
|
||||
t.Errorf("received '%v' expected '%v'", len(list), 1)
|
||||
}
|
||||
|
||||
rm = nil
|
||||
_, err = rm.List()
|
||||
if !errors.Is(err, gctcommon.ErrNilPointer) {
|
||||
t.Errorf("received '%v' expected '%v'", err, gctcommon.ErrNilPointer)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStopRun(t *testing.T) {
|
||||
t.Parallel()
|
||||
rm := SetupRunManager()
|
||||
list, err := rm.List()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
if len(list) != 0 {
|
||||
t.Errorf("received '%v' expected '%v'", len(list), 0)
|
||||
}
|
||||
|
||||
id, err := uuid.NewV4()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
err = rm.StopRun(id)
|
||||
if !errors.Is(err, errRunNotFound) {
|
||||
t.Errorf("received '%v' expected '%v'", err, errRunNotFound)
|
||||
}
|
||||
|
||||
bt := &BackTest{
|
||||
Strategy: &ftxcashandcarry.Strategy{},
|
||||
Statistic: &statistics.Statistic{},
|
||||
shutdown: make(chan struct{}),
|
||||
}
|
||||
err = rm.AddRun(bt)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
err = rm.StopRun(bt.MetaData.ID)
|
||||
if !errors.Is(err, errRunHasNotRan) {
|
||||
t.Errorf("received '%v' expected '%v'", err, errRunHasNotRan)
|
||||
}
|
||||
|
||||
bt.MetaData.DateStarted = time.Now()
|
||||
err = rm.StopRun(bt.MetaData.ID)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
|
||||
err = rm.StopRun(bt.MetaData.ID)
|
||||
if !errors.Is(err, errAlreadyRan) {
|
||||
t.Errorf("received '%v' expected '%v'", err, errAlreadyRan)
|
||||
}
|
||||
|
||||
rm = nil
|
||||
err = rm.StopRun(id)
|
||||
if !errors.Is(err, gctcommon.ErrNilPointer) {
|
||||
t.Errorf("received '%v' expected '%v'", err, gctcommon.ErrNilPointer)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStopAllRuns(t *testing.T) {
|
||||
t.Parallel()
|
||||
rm := SetupRunManager()
|
||||
stoppedRuns, err := rm.StopAllRuns()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
if len(stoppedRuns) != 0 {
|
||||
t.Errorf("received '%v' expected '%v'", len(stoppedRuns), 0)
|
||||
}
|
||||
|
||||
bt := &BackTest{
|
||||
Strategy: &ftxcashandcarry.Strategy{},
|
||||
Statistic: &statistics.Statistic{},
|
||||
shutdown: make(chan struct{}),
|
||||
}
|
||||
err = rm.AddRun(bt)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
bt.MetaData.DateStarted = time.Now()
|
||||
stoppedRuns, err = rm.StopAllRuns()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
if len(stoppedRuns) != 1 {
|
||||
t.Errorf("received '%v' expected '%v'", len(stoppedRuns), 1)
|
||||
}
|
||||
|
||||
rm = nil
|
||||
_, err = rm.StopAllRuns()
|
||||
if !errors.Is(err, gctcommon.ErrNilPointer) {
|
||||
t.Errorf("received '%v' expected '%v'", err, gctcommon.ErrNilPointer)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStartRun(t *testing.T) {
|
||||
t.Parallel()
|
||||
rm := SetupRunManager()
|
||||
list, err := rm.List()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
if len(list) != 0 {
|
||||
t.Errorf("received '%v' expected '%v'", len(list), 0)
|
||||
}
|
||||
|
||||
id, err := uuid.NewV4()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
err = rm.StartRun(id)
|
||||
if !errors.Is(err, errRunNotFound) {
|
||||
t.Errorf("received '%v' expected '%v'", err, errRunNotFound)
|
||||
}
|
||||
|
||||
bt := &BackTest{
|
||||
Strategy: &ftxcashandcarry.Strategy{},
|
||||
EventQueue: &eventholder.Holder{},
|
||||
Datas: &data.HandlerPerCurrency{},
|
||||
Statistic: &statistics.Statistic{},
|
||||
shutdown: make(chan struct{}),
|
||||
}
|
||||
err = rm.AddRun(bt)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
err = rm.StartRun(bt.MetaData.ID)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
|
||||
err = rm.StartRun(bt.MetaData.ID)
|
||||
if !errors.Is(err, errRunIsRunning) {
|
||||
t.Errorf("received '%v' expected '%v'", err, errRunIsRunning)
|
||||
}
|
||||
|
||||
bt.MetaData.DateEnded = time.Now()
|
||||
bt.MetaData.Closed = true
|
||||
|
||||
err = rm.StartRun(bt.MetaData.ID)
|
||||
if !errors.Is(err, errAlreadyRan) {
|
||||
t.Errorf("received '%v' expected '%v'", err, errAlreadyRan)
|
||||
}
|
||||
|
||||
rm = nil
|
||||
err = rm.StartRun(id)
|
||||
if !errors.Is(err, gctcommon.ErrNilPointer) {
|
||||
t.Errorf("received '%v' expected '%v'", err, gctcommon.ErrNilPointer)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStartAllRuns(t *testing.T) {
|
||||
t.Parallel()
|
||||
rm := SetupRunManager()
|
||||
startedRuns, err := rm.StartAllRuns()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
if len(startedRuns) != 0 {
|
||||
t.Errorf("received '%v' expected '%v'", len(startedRuns), 0)
|
||||
}
|
||||
|
||||
bt := &BackTest{
|
||||
Strategy: &ftxcashandcarry.Strategy{},
|
||||
EventQueue: &eventholder.Holder{},
|
||||
Datas: &data.HandlerPerCurrency{},
|
||||
Statistic: &statistics.Statistic{},
|
||||
shutdown: make(chan struct{}),
|
||||
}
|
||||
err = rm.AddRun(bt)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
startedRuns, err = rm.StartAllRuns()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
if len(startedRuns) != 1 {
|
||||
t.Errorf("received '%v' expected '%v'", len(startedRuns), 1)
|
||||
}
|
||||
|
||||
rm = nil
|
||||
_, err = rm.StartAllRuns()
|
||||
if !errors.Is(err, gctcommon.ErrNilPointer) {
|
||||
t.Errorf("received '%v' expected '%v'", err, gctcommon.ErrNilPointer)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClearRun(t *testing.T) {
|
||||
t.Parallel()
|
||||
rm := SetupRunManager()
|
||||
|
||||
id, err := uuid.NewV4()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
err = rm.ClearRun(id)
|
||||
if !errors.Is(err, errRunNotFound) {
|
||||
t.Errorf("received '%v' expected '%v'", err, errRunNotFound)
|
||||
}
|
||||
|
||||
bt := &BackTest{
|
||||
Strategy: &ftxcashandcarry.Strategy{},
|
||||
EventQueue: &eventholder.Holder{},
|
||||
Datas: &data.HandlerPerCurrency{},
|
||||
Statistic: &statistics.Statistic{},
|
||||
shutdown: make(chan struct{}),
|
||||
}
|
||||
err = rm.AddRun(bt)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
|
||||
bt.MetaData.DateStarted = time.Now()
|
||||
err = rm.ClearRun(bt.MetaData.ID)
|
||||
if !errors.Is(err, errCannotClear) {
|
||||
t.Errorf("received '%v' expected '%v'", err, errCannotClear)
|
||||
}
|
||||
|
||||
bt.MetaData.DateStarted = time.Time{}
|
||||
err = rm.ClearRun(bt.MetaData.ID)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
list, err := rm.List()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
if len(list) != 0 {
|
||||
t.Errorf("received '%v' expected '%v'", len(list), 0)
|
||||
}
|
||||
|
||||
rm = nil
|
||||
err = rm.ClearRun(id)
|
||||
if !errors.Is(err, gctcommon.ErrNilPointer) {
|
||||
t.Errorf("received '%v' expected '%v'", err, gctcommon.ErrNilPointer)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClearAllRuns(t *testing.T) {
|
||||
t.Parallel()
|
||||
rm := SetupRunManager()
|
||||
|
||||
clearedRuns, remainingRuns, err := rm.ClearAllRuns()
|
||||
if len(clearedRuns) != 0 {
|
||||
t.Errorf("received '%v' expected '%v'", len(clearedRuns), 0)
|
||||
}
|
||||
if len(remainingRuns) != 0 {
|
||||
t.Errorf("received '%v' expected '%v'", len(remainingRuns), 0)
|
||||
}
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
|
||||
bt := &BackTest{
|
||||
Strategy: &ftxcashandcarry.Strategy{},
|
||||
EventQueue: &eventholder.Holder{},
|
||||
Datas: &data.HandlerPerCurrency{},
|
||||
Statistic: &statistics.Statistic{},
|
||||
shutdown: make(chan struct{}),
|
||||
}
|
||||
err = rm.AddRun(bt)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
|
||||
bt.MetaData.DateStarted = time.Now()
|
||||
clearedRuns, remainingRuns, err = rm.ClearAllRuns()
|
||||
if len(clearedRuns) != 0 {
|
||||
t.Errorf("received '%v' expected '%v'", len(clearedRuns), 0)
|
||||
}
|
||||
if len(remainingRuns) != 1 {
|
||||
t.Errorf("received '%v' expected '%v'", len(remainingRuns), 1)
|
||||
}
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
|
||||
bt.MetaData.DateStarted = time.Time{}
|
||||
clearedRuns, remainingRuns, err = rm.ClearAllRuns()
|
||||
if len(clearedRuns) != 1 {
|
||||
t.Errorf("received '%v' expected '%v'", len(clearedRuns), 1)
|
||||
}
|
||||
if len(remainingRuns) != 0 {
|
||||
t.Errorf("received '%v' expected '%v'", len(remainingRuns), 0)
|
||||
}
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
list, err := rm.List()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
if len(list) != 0 {
|
||||
t.Errorf("received '%v' expected '%v'", len(list), 0)
|
||||
}
|
||||
|
||||
rm = nil
|
||||
_, _, err = rm.ClearAllRuns()
|
||||
if !errors.Is(err, gctcommon.ErrNilPointer) {
|
||||
t.Errorf("received '%v' expected '%v'", err, gctcommon.ErrNilPointer)
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,6 @@ import (
|
||||
gctkline "github.com/thrasher-corp/gocryptotrader/exchanges/kline"
|
||||
gctorder "github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
||||
"github.com/thrasher-corp/gocryptotrader/log"
|
||||
"github.com/thrasher-corp/gocryptotrader/signaler"
|
||||
)
|
||||
|
||||
// NewFromConfig takes a strategy config and configures a backtester variable to run
|
||||
@@ -49,13 +48,16 @@ func NewFromConfig(cfg *config.Config, templatePath, output string, verbose bool
|
||||
if cfg == nil {
|
||||
return nil, errNilConfig
|
||||
}
|
||||
var err error
|
||||
bt := New()
|
||||
bt, err := New()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bt.exchangeManager = engine.SetupExchangeManager()
|
||||
bt.orderManager, err = engine.SetupOrderManager(bt.exchangeManager, &engine.CommunicationManager{}, &sync.WaitGroup{}, false, false, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = bt.orderManager.Start()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -348,7 +350,9 @@ func NewFromConfig(cfg *config.Config, templatePath, output string, verbose bool
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bt.MetaData.Strategy = bt.Strategy.Name()
|
||||
bt.Strategy.SetDefaults()
|
||||
|
||||
if cfg.StrategySettings.CustomSettings != nil {
|
||||
err = bt.Strategy.SetCustomSettings(cfg.StrategySettings.CustomSettings)
|
||||
if err != nil && !errors.Is(err, base.ErrCustomSettingsUnsupported) {
|
||||
@@ -514,6 +518,8 @@ func (bt *BackTest) setupExchangeSettings(cfg *config.Config) (exchange.Exchange
|
||||
realOrders := false
|
||||
if cfg.DataSettings.LiveData != nil {
|
||||
realOrders = cfg.DataSettings.LiveData.RealOrders
|
||||
bt.MetaData.LiveTesting = true
|
||||
bt.MetaData.RealOrders = realOrders
|
||||
}
|
||||
|
||||
buyRule := exchange.MinMax{
|
||||
@@ -880,45 +886,24 @@ func loadLiveData(cfg *config.Config, base *gctexchange.Base) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExecuteStrategy executes the strategy using the provided configs
|
||||
func ExecuteStrategy(strategyCfg *config.Config, backtesterCfg *config.BacktesterConfig) error {
|
||||
if err := strategyCfg.Validate(); err != nil {
|
||||
return err
|
||||
// NewBacktesterFromConfigs creates a new backtester based on config settings
|
||||
func NewBacktesterFromConfigs(strategyCfg *config.Config, backtesterCfg *config.BacktesterConfig) (*BackTest, error) {
|
||||
if strategyCfg == nil {
|
||||
return nil, fmt.Errorf("%w strategy config", gctcommon.ErrNilPointer)
|
||||
}
|
||||
if backtesterCfg == nil {
|
||||
err := fmt.Errorf("%w backtester config", common.ErrNilArguments)
|
||||
return err
|
||||
return nil, fmt.Errorf("%w backtester config", gctcommon.ErrNilPointer)
|
||||
}
|
||||
if err := strategyCfg.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bt, err := NewFromConfig(strategyCfg, backtesterCfg.Report.TemplatePath, backtesterCfg.Report.OutputPath, backtesterCfg.Verbose)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
if strategyCfg.DataSettings.LiveData != nil {
|
||||
go func() {
|
||||
err = bt.RunLive()
|
||||
if err != nil {
|
||||
log.Error(log.Global, err)
|
||||
return
|
||||
}
|
||||
}()
|
||||
interrupt := signaler.WaitForInterrupt()
|
||||
log.Infof(log.Global, "Captured %v, shutdown requested.\n", interrupt)
|
||||
bt.Stop()
|
||||
} else {
|
||||
bt.Run()
|
||||
}
|
||||
|
||||
err = bt.Statistic.CalculateAllResults()
|
||||
err = bt.SetupMetaData()
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
if backtesterCfg.Report.GenerateReport {
|
||||
bt.Reports.UseDarkMode(backtesterCfg.Report.DarkMode)
|
||||
err = bt.Reports.GenerateReport()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return bt, nil
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package engine
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -10,6 +11,7 @@ import (
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/common"
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/config"
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/eventhandlers/portfolio/holdings"
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/eventhandlers/statistics"
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/eventhandlers/strategies/base"
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/eventhandlers/strategies/dollarcostaverage"
|
||||
"github.com/thrasher-corp/gocryptotrader/backtester/report"
|
||||
@@ -128,7 +130,8 @@ func TestNewFromConfig(t *testing.T) {
|
||||
func TestLoadDataAPI(t *testing.T) {
|
||||
t.Parallel()
|
||||
bt := BackTest{
|
||||
Reports: &report.Data{},
|
||||
Reports: &report.Data{},
|
||||
Statistic: &statistics.Statistic{},
|
||||
}
|
||||
cp := currency.NewPair(currency.BTC, currency.USDT)
|
||||
cfg := &config.Config{
|
||||
@@ -185,7 +188,8 @@ func TestLoadDataAPI(t *testing.T) {
|
||||
func TestLoadDataDatabase(t *testing.T) {
|
||||
t.Parallel()
|
||||
bt := BackTest{
|
||||
Reports: &report.Data{},
|
||||
Reports: &report.Data{},
|
||||
Statistic: &statistics.Statistic{},
|
||||
}
|
||||
cp := currency.NewPair(currency.BTC, currency.USDT)
|
||||
cfg := &config.Config{
|
||||
@@ -253,7 +257,8 @@ func TestLoadDataDatabase(t *testing.T) {
|
||||
func TestLoadDataCSV(t *testing.T) {
|
||||
t.Parallel()
|
||||
bt := BackTest{
|
||||
Reports: &report.Data{},
|
||||
Reports: &report.Data{},
|
||||
Statistic: &statistics.Statistic{},
|
||||
}
|
||||
cp := currency.NewPair(currency.BTC, currency.USDT)
|
||||
cfg := &config.Config{
|
||||
@@ -310,8 +315,9 @@ func TestLoadDataCSV(t *testing.T) {
|
||||
func TestLoadDataLive(t *testing.T) {
|
||||
t.Parallel()
|
||||
bt := BackTest{
|
||||
Reports: &report.Data{},
|
||||
shutdown: make(chan struct{}),
|
||||
Reports: &report.Data{},
|
||||
Statistic: &statistics.Statistic{},
|
||||
shutdown: make(chan struct{}),
|
||||
}
|
||||
cp := currency.NewPair(currency.BTC, currency.USDT)
|
||||
cfg := &config.Config{
|
||||
@@ -367,3 +373,39 @@ func TestLoadDataLive(t *testing.T) {
|
||||
}
|
||||
bt.Stop()
|
||||
}
|
||||
|
||||
func TestNewBacktesterFromConfigs(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := NewBacktesterFromConfigs(nil, nil)
|
||||
if !errors.Is(err, gctcommon.ErrNilPointer) {
|
||||
t.Errorf("received '%v' expected '%v'", err, gctcommon.ErrNilPointer)
|
||||
}
|
||||
|
||||
strat1 := filepath.Join("..", "config", "strategyexamples", "dca-api-candles.strat")
|
||||
cfg, err := config.ReadStrategyConfigFromFile(strat1)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
dc, err := config.GenerateDefaultConfig()
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
|
||||
_, err = NewBacktesterFromConfigs(cfg, nil)
|
||||
if !errors.Is(err, gctcommon.ErrNilPointer) {
|
||||
t.Errorf("received '%v' expected '%v'", err, gctcommon.ErrNilPointer)
|
||||
}
|
||||
|
||||
_, err = NewBacktesterFromConfigs(nil, dc)
|
||||
if !errors.Is(err, gctcommon.ErrNilPointer) {
|
||||
t.Errorf("received '%v' expected '%v'", err, gctcommon.ErrNilPointer)
|
||||
}
|
||||
|
||||
bt, err := NewBacktesterFromConfigs(cfg, dc)
|
||||
if !errors.Is(err, nil) {
|
||||
t.Errorf("received '%v' expected '%v'", err, nil)
|
||||
}
|
||||
if bt.MetaData.DateLoaded.IsZero() {
|
||||
t.Errorf("received '%v' expected '%v'", bt.MetaData.DateLoaded, "a date")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,6 +297,15 @@ func (s *Statistic) SetStrategyName(name string) {
|
||||
|
||||
// Serialise outputs the Statistic struct in json
|
||||
func (s *Statistic) Serialise() (string, error) {
|
||||
s.CurrencyStatistics = nil
|
||||
for _, exchangeMap := range s.ExchangeAssetPairStatistics {
|
||||
for _, assetMap := range exchangeMap {
|
||||
for _, stats := range assetMap {
|
||||
s.CurrencyStatistics = append(s.CurrencyStatistics, stats)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resp, err := json.MarshalIndent(s, "", " ")
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
||||
@@ -41,7 +41,8 @@ type Statistic struct {
|
||||
EndDate time.Time `json:"end-date"`
|
||||
CandleInterval gctkline.Interval `json:"candle-interval"`
|
||||
RiskFreeRate decimal.Decimal `json:"risk-free-rate"`
|
||||
ExchangeAssetPairStatistics map[string]map[asset.Item]map[currency.Pair]*CurrencyPairStatistic `json:"exchange-asset-pair-statistics"`
|
||||
ExchangeAssetPairStatistics map[string]map[asset.Item]map[currency.Pair]*CurrencyPairStatistic `json:"-"`
|
||||
CurrencyStatistics []*CurrencyPairStatistic `json:"currency-statistics"`
|
||||
TotalBuyOrders int64 `json:"total-buy-orders"`
|
||||
TotalLongOrders int64 `json:"total-long-orders"`
|
||||
TotalShortOrders int64 `json:"total-short-orders"`
|
||||
@@ -164,11 +165,11 @@ type CurrencyPairStatistic struct {
|
||||
UnrealisedPNL decimal.Decimal `json:"unrealised-pnl"`
|
||||
RealisedPNL decimal.Decimal `json:"realised-pnl"`
|
||||
CompoundAnnualGrowthRate decimal.Decimal `json:"compound-annual-growth-rate"`
|
||||
TotalAssetValue decimal.Decimal
|
||||
TotalFees decimal.Decimal
|
||||
TotalValueLostToVolumeSizing decimal.Decimal
|
||||
TotalValueLostToSlippage decimal.Decimal
|
||||
TotalValueLost decimal.Decimal
|
||||
TotalAssetValue decimal.Decimal `json:"total-asset-value"`
|
||||
TotalFees decimal.Decimal `json:"total-fees"`
|
||||
TotalValueLostToVolumeSizing decimal.Decimal `json:"total-value-lost-to-volume-sizing"`
|
||||
TotalValueLostToSlippage decimal.Decimal `json:"total-value-lost-to-slippage"`
|
||||
TotalValueLost decimal.Decimal `json:"total-value-lost"`
|
||||
|
||||
Events []DataAtOffset `json:"-"`
|
||||
|
||||
@@ -194,7 +195,7 @@ type Swing struct {
|
||||
Highest ValueAtTime `json:"highest"`
|
||||
Lowest ValueAtTime `json:"lowest"`
|
||||
DrawdownPercent decimal.Decimal `json:"drawdown"`
|
||||
IntervalDuration int64
|
||||
IntervalDuration int64 `json:"interval-duration"`
|
||||
}
|
||||
|
||||
// ValueAtTime is an individual iteration of price at a time
|
||||
@@ -211,55 +212,55 @@ type relatedCurrencyPairStatistics struct {
|
||||
|
||||
// FundingStatistics stores all funding related statistics
|
||||
type FundingStatistics struct {
|
||||
Report *funding.Report
|
||||
Items []FundingItemStatistics
|
||||
TotalUSDStatistics *TotalFundingStatistics
|
||||
Report *funding.Report `json:"-"`
|
||||
Items []FundingItemStatistics `json:"funding-item-statistics"`
|
||||
TotalUSDStatistics *TotalFundingStatistics `json:"total-usd-statistics"`
|
||||
}
|
||||
|
||||
// FundingItemStatistics holds statistics for funding items
|
||||
type FundingItemStatistics struct {
|
||||
ReportItem *funding.ReportItem
|
||||
ReportItem *funding.ReportItem `json:"-"`
|
||||
// USD stats
|
||||
StartingClosePrice ValueAtTime
|
||||
EndingClosePrice ValueAtTime
|
||||
LowestClosePrice ValueAtTime
|
||||
HighestClosePrice ValueAtTime
|
||||
MarketMovement decimal.Decimal
|
||||
StrategyMovement decimal.Decimal
|
||||
DidStrategyBeatTheMarket bool
|
||||
RiskFreeRate decimal.Decimal
|
||||
CompoundAnnualGrowthRate decimal.Decimal
|
||||
BuyOrders int64
|
||||
SellOrders int64
|
||||
TotalOrders int64
|
||||
MaxDrawdown Swing
|
||||
HighestCommittedFunds ValueAtTime
|
||||
StartingClosePrice ValueAtTime `json:"starting-close-price"`
|
||||
EndingClosePrice ValueAtTime `json:"ending-close-price"`
|
||||
LowestClosePrice ValueAtTime `json:"lowest-close-price"`
|
||||
HighestClosePrice ValueAtTime `json:"highest-close-price"`
|
||||
MarketMovement decimal.Decimal `json:"market-movement"`
|
||||
StrategyMovement decimal.Decimal `json:"strategy-movement"`
|
||||
DidStrategyBeatTheMarket bool `json:"did-strategy-beat-the-market"`
|
||||
RiskFreeRate decimal.Decimal `json:"risk-free-rate"`
|
||||
CompoundAnnualGrowthRate decimal.Decimal `json:"compound-annual-growth-rate"`
|
||||
BuyOrders int64 `json:"buy-orders"`
|
||||
SellOrders int64 `json:"sell-orders"`
|
||||
TotalOrders int64 `json:"total-orders"`
|
||||
MaxDrawdown Swing `json:"max-drawdown"`
|
||||
HighestCommittedFunds ValueAtTime `json:"highest-committed-funds"`
|
||||
// CollateralPair stats
|
||||
IsCollateral bool
|
||||
InitialCollateral ValueAtTime
|
||||
FinalCollateral ValueAtTime
|
||||
HighestCollateral ValueAtTime
|
||||
LowestCollateral ValueAtTime
|
||||
IsCollateral bool `json:"is-collateral"`
|
||||
InitialCollateral ValueAtTime `json:"initial-collateral"`
|
||||
FinalCollateral ValueAtTime `json:"final-collateral"`
|
||||
HighestCollateral ValueAtTime `json:"highest-collateral"`
|
||||
LowestCollateral ValueAtTime `json:"lowest-collateral"`
|
||||
// Contracts
|
||||
LowestHoldings ValueAtTime
|
||||
HighestHoldings ValueAtTime
|
||||
InitialHoldings ValueAtTime
|
||||
FinalHoldings ValueAtTime
|
||||
LowestHoldings ValueAtTime `json:"lowest-holdings"`
|
||||
HighestHoldings ValueAtTime `json:"highest-holdings"`
|
||||
InitialHoldings ValueAtTime `json:"initial-holdings"`
|
||||
FinalHoldings ValueAtTime `json:"final-holdings"`
|
||||
}
|
||||
|
||||
// TotalFundingStatistics holds values for overall statistics for funding items
|
||||
type TotalFundingStatistics struct {
|
||||
HoldingValues []ValueAtTime
|
||||
HighestHoldingValue ValueAtTime
|
||||
LowestHoldingValue ValueAtTime
|
||||
BenchmarkMarketMovement decimal.Decimal
|
||||
StrategyMovement decimal.Decimal
|
||||
RiskFreeRate decimal.Decimal
|
||||
CompoundAnnualGrowthRate decimal.Decimal
|
||||
MaxDrawdown Swing
|
||||
GeometricRatios *Ratios
|
||||
ArithmeticRatios *Ratios
|
||||
DidStrategyBeatTheMarket bool
|
||||
DidStrategyMakeProfit bool
|
||||
HoldingValueDifference decimal.Decimal
|
||||
HoldingValues []ValueAtTime `json:"-"`
|
||||
HighestHoldingValue ValueAtTime `json:"highest-holding-value"`
|
||||
LowestHoldingValue ValueAtTime `json:"lowest-holding-value"`
|
||||
BenchmarkMarketMovement decimal.Decimal `json:"benchmark-market-movement"`
|
||||
StrategyMovement decimal.Decimal `json:"strategy-movement"`
|
||||
RiskFreeRate decimal.Decimal `json:"risk-free-rate"`
|
||||
CompoundAnnualGrowthRate decimal.Decimal `json:"compound-annual-growth-rate"`
|
||||
MaxDrawdown Swing `json:"max-drawdown"`
|
||||
GeometricRatios *Ratios `json:"geometric-ratios"`
|
||||
ArithmeticRatios *Ratios `json:"arithmetic-ratios"`
|
||||
DidStrategyBeatTheMarket bool `json:"did-strategy-beat-the-market"`
|
||||
DidStrategyMakeProfit bool `json:"did-strategy-make-profit"`
|
||||
HoldingValueDifference decimal.Decimal `json:"holding-value-difference"`
|
||||
}
|
||||
|
||||
@@ -152,7 +152,8 @@ func main() {
|
||||
fmt.Printf("Could not read strategy config. Error: %v.\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
err = backtest.ExecuteStrategy(cfg, &config.BacktesterConfig{
|
||||
var bt *backtest.BackTest
|
||||
bt, err = backtest.NewBacktesterFromConfigs(cfg, &config.BacktesterConfig{
|
||||
Report: config.Report{
|
||||
GenerateReport: generateReport,
|
||||
TemplatePath: btCfg.Report.TemplatePath,
|
||||
@@ -164,15 +165,36 @@ func main() {
|
||||
fmt.Printf("Could not execute strategy. Error: %v.\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if bt.MetaData.LiveTesting {
|
||||
err = bt.ExecuteStrategy(false)
|
||||
if err != nil {
|
||||
fmt.Printf("Could execute strategy. Error: %v.\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
interrupt := signaler.WaitForInterrupt()
|
||||
log.Infof(log.Global, "Captured %v, shutdown requested.\n", interrupt)
|
||||
log.Infoln(log.Global, "Exiting.")
|
||||
bt.Stop()
|
||||
} else {
|
||||
err = bt.ExecuteStrategy(true)
|
||||
if err != nil {
|
||||
fmt.Printf("Could execute strategy. Error: %v.\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// grpc server mode
|
||||
btCfg.Report.DarkMode = darkReport
|
||||
btCfg.Report.GenerateReport = generateReport
|
||||
|
||||
runManager := backtest.SetupRunManager()
|
||||
|
||||
go func(c *config.BacktesterConfig) {
|
||||
log.Info(log.GRPCSys, "Starting RPC server")
|
||||
s := backtest.SetupRPCServer(c)
|
||||
var s *backtest.GRPCServer
|
||||
s, err = backtest.SetupRPCServer(c, runManager)
|
||||
err = backtest.StartRPCServer(s)
|
||||
if err != nil {
|
||||
fmt.Printf("Could not start RPC server. Error: %v.\n", err)
|
||||
|
||||
@@ -18,6 +18,9 @@ import (
|
||||
// GenerateReport sends final data from statistics to a template
|
||||
// to create a lovely final report for someone to view
|
||||
func (d *Data) GenerateReport() error {
|
||||
if d.TemplatePath == "" || d.OutputPath == "" {
|
||||
return nil
|
||||
}
|
||||
log.Info(common.Report, "Generating report")
|
||||
err := d.enhanceCandles()
|
||||
if err != nil {
|
||||
|
||||
@@ -111,7 +111,7 @@ func (t *TimePeriodCalculator) calculatePeriods() {
|
||||
return
|
||||
}
|
||||
iterateDateMate := t.start
|
||||
for !iterateDateMate.Equal(t.end) && !iterateDateMate.After(t.end) {
|
||||
for !iterateDateMate.Equal(t.end) && iterateDateMate.Before(t.end) {
|
||||
tp := TimePeriod{
|
||||
Time: iterateDateMate,
|
||||
dataInRange: false,
|
||||
|
||||
@@ -286,7 +286,7 @@ func (b *Binance) batchAggregateTrades(ctx context.Context, arg *AggregatedTrade
|
||||
// cutting off trades for high activity pairs
|
||||
increment := time.Second * 10
|
||||
for start := arg.StartTime; len(resp) == 0; start = start.Add(increment) {
|
||||
if !arg.EndTime.IsZero() && !start.Before(arg.EndTime) {
|
||||
if !arg.EndTime.IsZero() && start.After(arg.EndTime) {
|
||||
// All requests returned empty
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -288,7 +288,7 @@ func (bi *Binanceus) batchAggregateTrades(ctx context.Context, arg *AggregatedTr
|
||||
increment := time.Second * 10
|
||||
for len(resp) == 0 {
|
||||
startTime = startTime.Add(increment)
|
||||
if !endTime.IsZero() && !startTime.Before(endTime) {
|
||||
if !endTime.IsZero() && startTime.After(endTime) {
|
||||
// All requests returned empty
|
||||
return nil, nil
|
||||
}
|
||||
@@ -915,10 +915,10 @@ func (bi *Binanceus) GetSubaccountTransferHistory(ctx context.Context,
|
||||
|
||||
hundredDayBefore := time.Now()
|
||||
hundredDayBefore.Sub(time.UnixMilli(int64((time.Hour * 24 * 10) / time.Millisecond)))
|
||||
if !(startTimeT.Before(hundredDayBefore)) || !startTimeT.After(time.Now()) {
|
||||
if !(startTimeT.Before(hundredDayBefore)) || startTimeT.Before(time.Now()) {
|
||||
params.Set("startTime", strconv.Itoa(int(startTime)))
|
||||
}
|
||||
if !(endTimeT.Before(hundredDayBefore)) || !endTimeT.After(time.Now()) {
|
||||
if !(endTimeT.Before(hundredDayBefore)) || endTimeT.Before(time.Now()) {
|
||||
params.Set("startTime", strconv.Itoa(int(endTime)))
|
||||
}
|
||||
return resp.Transfers, bi.SendAuthHTTPRequest(ctx,
|
||||
|
||||
@@ -415,7 +415,7 @@ func CalculateCandleDateRanges(start, end time.Time, interval Interval, limit ui
|
||||
End: CreateIntervalTime(end),
|
||||
}
|
||||
var intervalsInWholePeriod []IntervalData
|
||||
for i := start; !i.After(end) && !i.Equal(end); i = i.Add(interval.Duration()) {
|
||||
for i := start; i.Before(end) && !i.Equal(end); i = i.Add(interval.Duration()) {
|
||||
intervalsInWholePeriod = append(intervalsInWholePeriod, IntervalData{
|
||||
Start: CreateIntervalTime(i.Round(interval.Duration())),
|
||||
End: CreateIntervalTime(i.Round(interval.Duration()).Add(interval.Duration())),
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
errWriterAlreadyLoaded = errors.New("io.Writer already loaded")
|
||||
errWriterNotFound = errors.New("io.Writer not found")
|
||||
errWriterAlreadyLoaded = errors.New("io.Writer already loaded")
|
||||
)
|
||||
|
||||
// Add appends a new writer to the multiwriter slice
|
||||
|
||||
Reference in New Issue
Block a user