Skip to content

Commit 7168efc

Browse files
authored
Enable defining a new date format for reports. (#165)
# Describe Request Enable defining a new date format for reports. Fixed #158 # Change Type New feature.
1 parent c47be8d commit 7168efc

File tree

4 files changed

+33
-26
lines changed

4 files changed

+33
-26
lines changed

cmd/indicator-backtest/main.go

+4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"os"
1313

1414
"github.com/cinar/indicator/v2/asset"
15+
"github.com/cinar/indicator/v2/helper"
1516
"github.com/cinar/indicator/v2/strategy"
1617
"github.com/cinar/indicator/v2/strategy/compound"
1718
"github.com/cinar/indicator/v2/strategy/momentum"
@@ -27,6 +28,7 @@ func main() {
2728
var writeStrategyRerpots bool
2829
var addSplits bool
2930
var addAnds bool
31+
var dateFormat string
3032

3133
fmt.Fprintln(os.Stderr, "Indicator Backtest")
3234
fmt.Fprintln(os.Stderr, "Copyright (c) 2021-2024 Onur Cinar.")
@@ -41,6 +43,7 @@ func main() {
4143
flag.BoolVar(&writeStrategyRerpots, "write-strategy-reports", strategy.DefaultWriteStrategyReports, "write individual strategy reports")
4244
flag.BoolVar(&addSplits, "splits", false, "add the split strategies")
4345
flag.BoolVar(&addAnds, "ands", false, "add the and strategies")
46+
flag.StringVar(&dateFormat, "date-format", helper.DefaultReportDateFormat, "date format to use")
4447
flag.Parse()
4548

4649
flag.Parse()
@@ -51,6 +54,7 @@ func main() {
5154
backtest.Workers = workers
5255
backtest.LastDays = lastDays
5356
backtest.WriteStrategyReports = writeStrategyRerpots
57+
backtest.DateFormat = dateFormat
5458
backtest.Names = append(backtest.Names, flag.Args()...)
5559
backtest.Strategies = append(backtest.Strategies, compound.AllStrategies()...)
5660
backtest.Strategies = append(backtest.Strategies, momentum.AllStrategies()...)

helper/report.go

+22-24
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ import (
1717
//go:embed "report.tmpl"
1818
var reportTmpl string
1919

20+
const (
21+
// DefaultReportDateFormat is the default date format used in the report.
22+
DefaultReportDateFormat = "2006-01-02"
23+
)
24+
2025
// ReportColumn defines the interface that all report data columns must implement.
2126
// This interface ensures that different types of data columns can be used
2227
// consistently within the report generation process.
@@ -34,62 +39,55 @@ type ReportColumn interface {
3439
Value() string
3540
}
3641

37-
// reportModel struct holds the data that is exposed to the template renderer
38-
// for generating the report. It encapsulates all the information necessary
39-
// to render the report's content, including data, and annotations.
40-
type reportModel struct {
41-
Title string
42-
Date <-chan time.Time
43-
Columns []ReportColumn
44-
Views [][]int
45-
}
46-
4742
// Report generates an HTML file containing an interactive chart that
4843
// visually represents the provided data and annotations.
4944
//
5045
// The generated HTML file can be opened in a web browser to explore
5146
// the data visually, interact with the chart elements, and view
5247
// the associated annotations.
5348
type Report struct {
54-
model reportModel
49+
Title string
50+
Date <-chan time.Time
51+
Columns []ReportColumn
52+
Views [][]int
53+
DateFormat string
5554
}
5655

5756
// NewReport takes a channel of time as the time axis and returns a new
5857
// instance of the Report struct. This instance can later be used to
5958
// add data and annotations and subsequently generate a report.
6059
func NewReport(title string, date <-chan time.Time) *Report {
6160
return &Report{
62-
model: reportModel{
63-
Title: title,
64-
Date: date,
65-
Columns: []ReportColumn{},
66-
Views: [][]int{
67-
{},
68-
},
61+
Title: title,
62+
Date: date,
63+
Columns: []ReportColumn{},
64+
Views: [][]int{
65+
{},
6966
},
67+
DateFormat: DefaultReportDateFormat,
7068
}
7169
}
7270

7371
// AddChart adds a new chart to the report and returns its unique
7472
// identifier. This identifier can be used later to refer to the
7573
// chart and add columns to it.
7674
func (r *Report) AddChart() int {
77-
r.model.Views = append(r.model.Views, []int{})
78-
return len(r.model.Views) - 1
75+
r.Views = append(r.Views, []int{})
76+
return len(r.Views) - 1
7977
}
8078

8179
// AddColumn adds a new data column to the specified charts. If no
8280
// chart is specified, it will be added to the main chart.
8381
func (r *Report) AddColumn(column ReportColumn, charts ...int) {
84-
r.model.Columns = append(r.model.Columns, column)
85-
columnID := len(r.model.Columns)
82+
r.Columns = append(r.Columns, column)
83+
columnID := len(r.Columns)
8684

8785
if len(charts) == 0 {
8886
charts = append(charts, 0)
8987
}
9088

9189
for _, chartID := range charts {
92-
r.model.Views[chartID] = append(r.model.Views[chartID], columnID)
90+
r.Views[chartID] = append(r.Views[chartID], columnID)
9391
}
9492
}
9593

@@ -102,7 +100,7 @@ func (r *Report) WriteToWriter(writer io.Writer) error {
102100
return err
103101
}
104102

105-
return tmpl.Execute(writer, r.model)
103+
return tmpl.Execute(writer, r)
106104
}
107105

108106
// WriteToFile writes the generated report content to a file with

helper/report.tmpl

+2-2
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@
102102

103103
{{ range .Date }}
104104
data.addRow([
105-
new Date("{{ .Format "2006-01-02" }}"),
105+
new Date("{{ .Format $.DateFormat }}"),
106106
{{ range $.Columns }}
107107
{{ .Value }},
108108
{{ end }}
@@ -119,4 +119,4 @@
119119
</script>
120120
</body>
121121

122-
</html>
122+
</html>

strategy/backtest.go

+5
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ type Backtest struct {
6262

6363
// WriteStrategyReports indicates whether the individual strategy reports should be generated.
6464
WriteStrategyReports bool
65+
66+
// DateFormat is the date format that is used in the reports.
67+
DateFormat string
6568
}
6669

6770
// backtestResult encapsulates the outcome of running a strategy.
@@ -95,6 +98,7 @@ func NewBacktest(repository asset.Repository, outputDir string) *Backtest {
9598
Workers: DefaultBacktestWorkers,
9699
LastDays: DefaultLastDays,
97100
WriteStrategyReports: DefaultWriteStrategyReports,
101+
DateFormat: helper.DefaultReportDateFormat,
98102
}
99103
}
100104

@@ -204,6 +208,7 @@ func (b *Backtest) worker(names <-chan string, bestResults chan<- *backtestResul
204208
// Generate inidividual strategy report.
205209
if b.WriteStrategyReports {
206210
report := st.Report(helper.SliceToChan(snapshotsSlice))
211+
report.DateFormat = b.DateFormat
207212

208213
err := report.WriteToFile(path.Join(b.outputDir, b.strategyReportFileName(name, st.Name())))
209214
if err != nil {

0 commit comments

Comments
 (0)