Skip to content

Commit

Permalink
Enable defining a new date format for reports. (#165)
Browse files Browse the repository at this point in the history
# Describe Request

Enable defining a new date format for reports. 

Fixed #158 

# Change Type

New feature.
  • Loading branch information
cinar authored Jun 30, 2024
1 parent c47be8d commit 7168efc
Showing 4 changed files with 33 additions and 26 deletions.
4 changes: 4 additions & 0 deletions cmd/indicator-backtest/main.go
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@ import (
"os"

"github.com/cinar/indicator/v2/asset"
"github.com/cinar/indicator/v2/helper"
"github.com/cinar/indicator/v2/strategy"
"github.com/cinar/indicator/v2/strategy/compound"
"github.com/cinar/indicator/v2/strategy/momentum"
@@ -27,6 +28,7 @@ func main() {
var writeStrategyRerpots bool
var addSplits bool
var addAnds bool
var dateFormat string

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

flag.Parse()
@@ -51,6 +54,7 @@ func main() {
backtest.Workers = workers
backtest.LastDays = lastDays
backtest.WriteStrategyReports = writeStrategyRerpots
backtest.DateFormat = dateFormat
backtest.Names = append(backtest.Names, flag.Args()...)
backtest.Strategies = append(backtest.Strategies, compound.AllStrategies()...)
backtest.Strategies = append(backtest.Strategies, momentum.AllStrategies()...)
46 changes: 22 additions & 24 deletions helper/report.go
Original file line number Diff line number Diff line change
@@ -17,6 +17,11 @@ import (
//go:embed "report.tmpl"
var reportTmpl string

const (
// DefaultReportDateFormat is the default date format used in the report.
DefaultReportDateFormat = "2006-01-02"
)

// ReportColumn defines the interface that all report data columns must implement.
// This interface ensures that different types of data columns can be used
// consistently within the report generation process.
@@ -34,62 +39,55 @@ type ReportColumn interface {
Value() string
}

// reportModel struct holds the data that is exposed to the template renderer
// for generating the report. It encapsulates all the information necessary
// to render the report's content, including data, and annotations.
type reportModel struct {
Title string
Date <-chan time.Time
Columns []ReportColumn
Views [][]int
}

// Report generates an HTML file containing an interactive chart that
// visually represents the provided data and annotations.
//
// The generated HTML file can be opened in a web browser to explore
// the data visually, interact with the chart elements, and view
// the associated annotations.
type Report struct {
model reportModel
Title string
Date <-chan time.Time
Columns []ReportColumn
Views [][]int
DateFormat string
}

// NewReport takes a channel of time as the time axis and returns a new
// instance of the Report struct. This instance can later be used to
// add data and annotations and subsequently generate a report.
func NewReport(title string, date <-chan time.Time) *Report {
return &Report{
model: reportModel{
Title: title,
Date: date,
Columns: []ReportColumn{},
Views: [][]int{
{},
},
Title: title,
Date: date,
Columns: []ReportColumn{},
Views: [][]int{
{},
},
DateFormat: DefaultReportDateFormat,
}
}

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

// AddColumn adds a new data column to the specified charts. If no
// chart is specified, it will be added to the main chart.
func (r *Report) AddColumn(column ReportColumn, charts ...int) {
r.model.Columns = append(r.model.Columns, column)
columnID := len(r.model.Columns)
r.Columns = append(r.Columns, column)
columnID := len(r.Columns)

if len(charts) == 0 {
charts = append(charts, 0)
}

for _, chartID := range charts {
r.model.Views[chartID] = append(r.model.Views[chartID], columnID)
r.Views[chartID] = append(r.Views[chartID], columnID)
}
}

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

return tmpl.Execute(writer, r.model)
return tmpl.Execute(writer, r)
}

// WriteToFile writes the generated report content to a file with
4 changes: 2 additions & 2 deletions helper/report.tmpl
Original file line number Diff line number Diff line change
@@ -102,7 +102,7 @@

{{ range .Date }}
data.addRow([
new Date("{{ .Format "2006-01-02" }}"),
new Date("{{ .Format $.DateFormat }}"),
{{ range $.Columns }}
{{ .Value }},
{{ end }}
@@ -119,4 +119,4 @@
</script>
</body>

</html>
</html>
5 changes: 5 additions & 0 deletions strategy/backtest.go
Original file line number Diff line number Diff line change
@@ -62,6 +62,9 @@ type Backtest struct {

// WriteStrategyReports indicates whether the individual strategy reports should be generated.
WriteStrategyReports bool

// DateFormat is the date format that is used in the reports.
DateFormat string
}

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

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

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

0 comments on commit 7168efc

Please sign in to comment.