Skip to content

Commit

Permalink
Apo strategy report added.
Browse files Browse the repository at this point in the history
  • Loading branch information
cinar committed Dec 10, 2023
1 parent 5d968d8 commit da4e9e0
Show file tree
Hide file tree
Showing 15 changed files with 855 additions and 568 deletions.
27 changes: 20 additions & 7 deletions helper/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ The information provided on this project is strictly for informational purposes
- [func \(r \*Report\) WriteToFile\(fileName string\) error](<#Report.WriteToFile>)
- [func \(r \*Report\) WriteToWriter\(writer io.Writer\) error](<#Report.WriteToWriter>)
- [type ReportColumn](<#ReportColumn>)
- [func NewAnnotationReportColumn\(values \<\-chan string\) ReportColumn](<#NewAnnotationReportColumn>)
- [func NewNumericReportColumn\[T Number\]\(name string, values \<\-chan T\) ReportColumn](<#NewNumericReportColumn>)
- [type Ring](<#Ring>)
- [func NewRing\[T any\]\(size int\) \*Ring\[T\]](<#NewRing>)
Expand Down Expand Up @@ -851,7 +852,7 @@ type Number interface {
```

<a name="Report"></a>
## type [Report](<https://github.com/cinar/indicator/blob/v2/helper/report.go#L80-L82>)
## type [Report](<https://github.com/cinar/indicator/blob/v2/helper/report.go#L52-L54>)

Report generates an HTML file containing an interactive chart that visually represents the provided data and annotations.

Expand All @@ -864,7 +865,7 @@ type Report struct {
```

<a name="NewReport"></a>
### func [NewReport](<https://github.com/cinar/indicator/blob/v2/helper/report.go#L87>)
### func [NewReport](<https://github.com/cinar/indicator/blob/v2/helper/report.go#L59>)

```go
func NewReport(title string, date <-chan time.Time) *Report
Expand All @@ -873,7 +874,7 @@ func NewReport(title string, date <-chan time.Time) *Report
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.

<a name="Report.AddColumn"></a>
### func \(\*Report\) [AddColumn](<https://github.com/cinar/indicator/blob/v2/helper/report.go#L98>)
### func \(\*Report\) [AddColumn](<https://github.com/cinar/indicator/blob/v2/helper/report.go#L70>)

```go
func (r *Report) AddColumn(column ReportColumn)
Expand All @@ -882,7 +883,7 @@ func (r *Report) AddColumn(column ReportColumn)
AddColumn adds a new data column to the report.

<a name="Report.WriteToFile"></a>
### func \(\*Report\) [WriteToFile](<https://github.com/cinar/indicator/blob/v2/helper/report.go#L117>)
### func \(\*Report\) [WriteToFile](<https://github.com/cinar/indicator/blob/v2/helper/report.go#L89>)

```go
func (r *Report) WriteToFile(fileName string) error
Expand All @@ -891,7 +892,7 @@ func (r *Report) WriteToFile(fileName string) error
WriteToFile writes the generated report content to a file with the specified name. This allows users to conveniently save the report for later viewing or analysis.

<a name="Report.WriteToWriter"></a>
### func \(\*Report\) [WriteToWriter](<https://github.com/cinar/indicator/blob/v2/helper/report.go#L105>)
### func \(\*Report\) [WriteToWriter](<https://github.com/cinar/indicator/blob/v2/helper/report.go#L77>)

```go
func (r *Report) WriteToWriter(writer io.Writer) error
Expand All @@ -900,7 +901,7 @@ func (r *Report) WriteToWriter(writer io.Writer) error
WriteToWriter writes the report content to the provided io.Writer. This allows the report to be sent to various destinations, such as a file, a network socket, or even the standard output.

<a name="ReportColumn"></a>
## type [ReportColumn](<https://github.com/cinar/indicator/blob/v2/helper/report.go#L24-L33>)
## type [ReportColumn](<https://github.com/cinar/indicator/blob/v2/helper/report.go#L23-L35>)

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.

Expand All @@ -912,13 +913,25 @@ type ReportColumn interface {
// Type returns the data type of the report column.
Type() string

// Role returns the role of the report column.
Role() string

// Value returns the next data value for the report column.
Value() string
}
```

<a name="NewAnnotationReportColumn"></a>
### func [NewAnnotationReportColumn](<https://github.com/cinar/indicator/blob/v2/helper/annotation_report_column.go#L16>)

```go
func NewAnnotationReportColumn(values <-chan string) ReportColumn
```

NewAnnotationReportColumn returns a new instance of a annotation column for a report.

<a name="NewNumericReportColumn"></a>
### func [NewNumericReportColumn](<https://github.com/cinar/indicator/blob/v2/helper/report.go#L43>)
### func [NewNumericReportColumn](<https://github.com/cinar/indicator/blob/v2/helper/numeric_report_column.go#L17>)

```go
func NewNumericReportColumn[T Number](name string, values <-chan T) ReportColumn
Expand Down
46 changes: 46 additions & 0 deletions helper/annotation_report_column.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright (c) 2023 Onur Cinar. All Rights Reserved.
// The source code is provided under MIT License.
// https://github.com/cinar/indicator

package helper

import "fmt"

// annotationReportColumn is the annotation report column struct.
type annotationReportColumn struct {
ReportColumn
values <-chan string
}

// NewAnnotationReportColumn returns a new instance of a annotation column for a report.
func NewAnnotationReportColumn(values <-chan string) ReportColumn {
return &annotationReportColumn{
values: values,
}
}

// Name returns the name of the report column.
func (c *annotationReportColumn) Name() string {
return ""
}

// Type returns number as the data type.
func (c *annotationReportColumn) Type() string {
return "string"
}

// Role returns the role of the report column.
func (c *annotationReportColumn) Role() string {
return "annotation"
}

// Value returns the next data value for the report column.
func (c *annotationReportColumn) Value() string {
value := <-c.values

if value != "" {
return fmt.Sprintf("\"%s\"", value)
}

return "null"
}
42 changes: 42 additions & 0 deletions helper/numeric_report_column.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright (c) 2023 Onur Cinar. All Rights Reserved.
// The source code is provided under MIT License.
// https://github.com/cinar/indicator

package helper

import "fmt"

// numericReportColumn is the number report column struct.
type numericReportColumn[T Number] struct {
ReportColumn
name string
values <-chan T
}

// NewNumericReportColumn returns a new instance of a numeric data column for a report.
func NewNumericReportColumn[T Number](name string, values <-chan T) ReportColumn {
return &numericReportColumn[T]{
name: name,
values: values,
}
}

// Name returns the name of the report column.
func (c *numericReportColumn[T]) Name() string {
return c.name
}

// Type returns number as the data type.
func (c *numericReportColumn[T]) Type() string {
return "number"
}

// Role returns the role of the report column.
func (c *numericReportColumn[T]) Role() string {
return "data"
}

// Value returns the next data value for the report column.
func (c *numericReportColumn[T]) Value() string {
return fmt.Sprintf("%v", <-c.values)
}
34 changes: 3 additions & 31 deletions helper/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ package helper
import (
// Go embed report template.
_ "embed"
"fmt"
"io"
"os"
"path/filepath"
Expand All @@ -28,40 +27,13 @@ type ReportColumn interface {
// Type returns the data type of the report column.
Type() string

// Role returns the role of the report column.
Role() string

// Value returns the next data value for the report column.
Value() string
}

// numericReportColumn is the number report column struct.
type numericReportColumn[T Number] struct {
ReportColumn
name string
values <-chan T
}

// NewNumericReportColumn returns a new instance of a numeric data column for a report.
func NewNumericReportColumn[T Number](name string, values <-chan T) ReportColumn {
return &numericReportColumn[T]{
name: name,
values: values,
}
}

// Name returns the name of the report column.
func (c *numericReportColumn[T]) Name() string {
return c.name
}

// Type returns number as the data type.
func (c *numericReportColumn[T]) Type() string {
return "number"
}

// Value returns the next data value for the report column.
func (c *numericReportColumn[T]) Value() string {
return fmt.Sprintf("%v", <-c.values)
}

// 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.
Expand Down
19 changes: 12 additions & 7 deletions helper/report.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@
"curveType": "function",
"legend": {
"position": "right",
}
}
},
"height": 400,
},
});

var rangeFilter = new google.visualization.ControlWrapper({
Expand All @@ -55,17 +56,21 @@
"filterColumnLabel": "Date",
"ui": {
"chartOptions": {
"height": 50
}
}
}
"height": 50,
},
},
},
});

// Create the data table.
var data = new google.visualization.DataTable();
data.addColumn("date", "Date");
{{ range.Columns }}
data.addColumn("{{ .Type }}", "{{ .Name }}");
data.addColumn({
"type": "{{ .Type }}",
"label": "{{ .Name }}",
"role": "{{ .Role }}",
});
{{ end }}

{{ range.Date }}
Expand Down
42 changes: 36 additions & 6 deletions helper/report_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,63 @@ import (

func TestReportWriteToFile(t *testing.T) {
type Row struct {
Date time.Time `format:"2006-01-02"`
High float64
Low float64
Close float64
Date time.Time `format:"2006-01-02"`
High float64
Low float64
Close float64
Annotation string
}

input, err := helper.ReadFromCsvFile[Row]("testdata/report.csv", true)
if err != nil {
t.Fatal(err)
}

inputs := helper.Duplicate(input, 4)
inputs := helper.Duplicate(input, 5)
dates := helper.Map(inputs[0], func(row *Row) time.Time { return row.Date })
highs := helper.Map(inputs[1], func(row *Row) float64 { return row.High })
lows := helper.Map(inputs[2], func(row *Row) float64 { return row.Low })
closes := helper.Map(inputs[3], func(row *Row) float64 { return row.Close })
annotations := helper.Map(inputs[4], func(row *Row) string { return row.Annotation })

report := helper.NewReport("Test Report", dates)
report.AddColumn(helper.NewNumericReportColumn("High", highs))
report.AddColumn(helper.NewNumericReportColumn("Low", lows))
report.AddColumn(helper.NewNumericReportColumn("Close", closes))
report.AddColumn(helper.NewAnnotationReportColumn(annotations))

fileName := "report.html"
defer os.Remove(fileName)

err = report.WriteToFile("report.html")
err = report.WriteToFile(fileName)
if err != nil {
t.Fatal(err)
}
}

func TestReportWriteToFileFailed(t *testing.T) {
type Row struct {
Date time.Time `format:"2006-01-02"`
High float64
Low float64
Close float64
Annotation string
}

input, err := helper.ReadFromCsvFile[Row]("testdata/report.csv", true)
if err != nil {
t.Fatal(err)
}

inputs := helper.Duplicate(input, 2)
dates := helper.Map(inputs[0], func(row *Row) time.Time { return row.Date })
closes := helper.Map(inputs[1], func(row *Row) float64 { return row.Close })

report := helper.NewReport("Test Report", dates)
report.AddColumn(helper.NewNumericReportColumn("Close", closes))

err = report.WriteToFile("")
if err == nil {
t.Fatal("expected error")
}
}
Loading

0 comments on commit da4e9e0

Please sign in to comment.