-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
83 lines (76 loc) · 2.39 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"os"
"strings"
"time"
"github.com/portfoliotree/round"
"github.com/portfoliotree/portfolio"
"github.com/portfoliotree/portfolio/backtest"
"github.com/portfoliotree/portfolio/returns"
)
func main() {
specs, err := portfolio.WalkDirectoryAndParseSpecificationFiles(os.DirFS("."))
if err != nil {
log.Fatal(err)
}
backtestResultsJSON, err := os.Create("backtest_results.json")
if err != nil {
log.Fatal(err)
}
defer func() {
_ = backtestResultsJSON.Close()
}()
backtestResultsEncoder := json.NewEncoder(backtestResultsJSON)
var table returns.Table
ctx := context.Background()
var names []string
for _, spec := range specs {
log.Printf("running backtest with %d assets for %s: %q\n", len(spec.Assets), spec.Filepath, spec.Name)
assets, err := spec.AssetReturns(ctx)
if err != nil {
log.Fatal(err)
}
if assets.NumberOfRows() == 0 {
log.Fatal("assets table has 0 rows")
}
result, err := spec.Backtest(ctx, assets, nil)
if err != nil {
log.Fatal(err)
}
if err := backtestResultsEncoder.Encode(result); err != nil {
log.Fatal(err)
}
rs := result.Returns()
log.Println(report(spec, result))
table = table.AddColumn(rs)
names = append(names, spec.Filepath)
}
returnsCSV, err := os.Create("returns.csv")
if err != nil {
log.Fatal(err)
}
defer func() {
_ = returnsCSV.Close()
}()
if err := table.WriteCSV(returnsCSV, names); err != nil {
log.Fatal(err)
}
}
func report(spec portfolio.Specification, result backtest.Result) string {
rs := result.Returns()
var s strings.Builder
s.WriteString(fmt.Sprintf("finished backtest for %s: %q\n", spec.Filepath, spec.Name))
s.WriteString(fmt.Sprintf("\tlast_time: %s\n", rs.LastTime().Format(time.DateOnly)))
s.WriteString(fmt.Sprintf("\tfirst_time: %s\n", rs.FirstTime().Format(time.DateOnly)))
s.WriteString(fmt.Sprintf("\tnumber_of_returns: %d\n", rs.Len()))
s.WriteString(fmt.Sprintf("\tannualized_arithmetic_return: %f\n", round.Decimal(rs.AnnualizedArithmeticReturn()*100, 6)))
s.WriteString(fmt.Sprintf("\tannualized_risk: %f\n", round.Decimal(rs.AnnualizedRisk()*100, 6)))
s.WriteString(fmt.Sprintf("\tnumber_of_assets: %d\n", len(spec.Assets)))
s.WriteString(fmt.Sprintf("\trebalance_count: %d\n", len(result.RebalanceTimes)))
s.WriteString(fmt.Sprintf("\tpolicy_weight_update_count: %d\n", len(result.PolicyUpdateTimes)))
return s.String()
}