updates + tests
This commit is contained in:
parent
1144b80a46
commit
1555902fc4
13 changed files with 207 additions and 2 deletions
|
@ -7,6 +7,11 @@ import (
|
|||
util "github.com/wcharczuk/go-chart/util"
|
||||
)
|
||||
|
||||
// Interface Assertions.
|
||||
var (
|
||||
_ Series = (*AnnotationSeries)(nil)
|
||||
)
|
||||
|
||||
// AnnotationSeries is a series of labels on the chart.
|
||||
type AnnotationSeries struct {
|
||||
Name string
|
||||
|
|
|
@ -6,6 +6,11 @@ import (
|
|||
"github.com/wcharczuk/go-chart/seq"
|
||||
)
|
||||
|
||||
// Interface Assertions.
|
||||
var (
|
||||
_ Series = (*BollingerBandsSeries)(nil)
|
||||
)
|
||||
|
||||
// BollingerBandsSeries draws bollinger bands for an inner series.
|
||||
// Bollinger bands are defined by two lines, one at SMA+k*stddev, one at SMA-k*stdev.
|
||||
type BollingerBandsSeries struct {
|
||||
|
|
|
@ -2,6 +2,13 @@ package chart
|
|||
|
||||
import "fmt"
|
||||
|
||||
// Interface Assertions.
|
||||
var (
|
||||
_ Series = (*ContinuousSeries)(nil)
|
||||
_ FirstValuesProvider = (*ContinuousSeries)(nil)
|
||||
_ LastValuesProvider = (*ContinuousSeries)(nil)
|
||||
)
|
||||
|
||||
// ContinuousSeries represents a line on a chart.
|
||||
type ContinuousSeries struct {
|
||||
Name string
|
||||
|
@ -36,6 +43,11 @@ func (cs ContinuousSeries) GetValues(index int) (float64, float64) {
|
|||
return cs.XValues[index], cs.YValues[index]
|
||||
}
|
||||
|
||||
// GetFirstValues gets the first x,y values.
|
||||
func (cs ContinuousSeries) GetFirstValues() (float64, float64) {
|
||||
return cs.XValues[0], cs.YValues[0]
|
||||
}
|
||||
|
||||
// GetLastValues gets the last x,y values.
|
||||
func (cs ContinuousSeries) GetLastValues() (float64, float64) {
|
||||
return cs.XValues[len(cs.XValues)-1], cs.YValues[len(cs.YValues)-1]
|
||||
|
|
|
@ -7,6 +7,13 @@ const (
|
|||
DefaultEMAPeriod = 12
|
||||
)
|
||||
|
||||
// Interface Assertions.
|
||||
var (
|
||||
_ Series = (*EMASeries)(nil)
|
||||
_ FirstValuesProvider = (*EMASeries)(nil)
|
||||
_ LastValuesProvider = (*EMASeries)(nil)
|
||||
)
|
||||
|
||||
// EMASeries is a computed series.
|
||||
type EMASeries struct {
|
||||
Name string
|
||||
|
@ -66,6 +73,19 @@ func (ema *EMASeries) GetValues(index int) (x, y float64) {
|
|||
return
|
||||
}
|
||||
|
||||
// GetFirstValues computes the first moving average value.
|
||||
func (ema *EMASeries) GetFirstValues() (x, y float64) {
|
||||
if ema.InnerSeries == nil {
|
||||
return
|
||||
}
|
||||
if len(ema.cache) == 0 {
|
||||
ema.ensureCachedValues()
|
||||
}
|
||||
x, _ = ema.InnerSeries.GetValues(0)
|
||||
y = ema.cache[0]
|
||||
return
|
||||
}
|
||||
|
||||
// GetLastValues computes the last moving average value but walking back window size samples,
|
||||
// and recomputing the last moving average chunk.
|
||||
func (ema *EMASeries) GetLastValues() (x, y float64) {
|
||||
|
|
37
first_value_annotation.go
Normal file
37
first_value_annotation.go
Normal file
|
@ -0,0 +1,37 @@
|
|||
package chart
|
||||
|
||||
import "fmt"
|
||||
|
||||
// FirstValueAnnotation returns an annotation series of just the first value of a value provider as an annotation.
|
||||
func FirstValueAnnotation(innerSeries ValuesProvider, vfs ...ValueFormatter) AnnotationSeries {
|
||||
var vf ValueFormatter
|
||||
if len(vfs) > 0 {
|
||||
vf = vfs[0]
|
||||
} else if typed, isTyped := innerSeries.(ValueFormatterProvider); isTyped {
|
||||
_, vf = typed.GetValueFormatters()
|
||||
} else {
|
||||
vf = FloatValueFormatter
|
||||
}
|
||||
|
||||
var firstValue Value2
|
||||
if typed, isTyped := innerSeries.(FirstValuesProvider); isTyped {
|
||||
firstValue.XValue, firstValue.YValue = typed.GetFirstValues()
|
||||
firstValue.Label = vf(firstValue.YValue)
|
||||
} else {
|
||||
firstValue.XValue, firstValue.YValue = innerSeries.GetValues(0)
|
||||
firstValue.Label = vf(firstValue.YValue)
|
||||
}
|
||||
|
||||
var seriesName string
|
||||
var seriesStyle Style
|
||||
if typed, isTyped := innerSeries.(Series); isTyped {
|
||||
seriesName = fmt.Sprintf("%s - First Value", typed.GetName())
|
||||
seriesStyle = typed.GetStyle()
|
||||
}
|
||||
|
||||
return AnnotationSeries{
|
||||
Name: seriesName,
|
||||
Style: seriesStyle,
|
||||
Annotations: []Value2{firstValue},
|
||||
}
|
||||
}
|
22
first_value_annotation_test.go
Normal file
22
first_value_annotation_test.go
Normal file
|
@ -0,0 +1,22 @@
|
|||
package chart
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/blend/go-sdk/assert"
|
||||
)
|
||||
|
||||
func TestFirstValueAnnotation(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
series := ContinuousSeries{
|
||||
XValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
YValues: []float64{5.0, 3.0, 3.0, 2.0, 1.0},
|
||||
}
|
||||
|
||||
fva := FirstValueAnnotation(series)
|
||||
assert.NotEmpty(fva.Annotations)
|
||||
fvaa := fva.Annotations[0]
|
||||
assert.Equal(1, fvaa.XValue)
|
||||
assert.Equal(5, fvaa.YValue)
|
||||
}
|
22
last_value_annotation_test.go
Normal file
22
last_value_annotation_test.go
Normal file
|
@ -0,0 +1,22 @@
|
|||
package chart
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/blend/go-sdk/assert"
|
||||
)
|
||||
|
||||
func TestLastValueAnnotation(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
series := ContinuousSeries{
|
||||
XValues: []float64{1.0, 2.0, 3.0, 4.0, 5.0},
|
||||
YValues: []float64{5.0, 3.0, 3.0, 2.0, 1.0},
|
||||
}
|
||||
|
||||
lva := LastValueAnnotation(series)
|
||||
assert.NotEmpty(lva.Annotations)
|
||||
lvaa := lva.Annotations[0]
|
||||
assert.Equal(5, lvaa.XValue)
|
||||
assert.Equal(1, lvaa.YValue)
|
||||
}
|
|
@ -7,6 +7,13 @@ import (
|
|||
util "github.com/wcharczuk/go-chart/util"
|
||||
)
|
||||
|
||||
// Interface Assertions.
|
||||
var (
|
||||
_ Series = (*LinearRegressionSeries)(nil)
|
||||
_ FirstValuesProvider = (*LinearRegressionSeries)(nil)
|
||||
_ LastValuesProvider = (*LinearRegressionSeries)(nil)
|
||||
)
|
||||
|
||||
// LinearRegressionSeries is a series that plots the n-nearest neighbors
|
||||
// linear regression for the values.
|
||||
type LinearRegressionSeries struct {
|
||||
|
@ -82,6 +89,19 @@ func (lrs *LinearRegressionSeries) GetValues(index int) (x, y float64) {
|
|||
return
|
||||
}
|
||||
|
||||
// GetFirstValues computes the first linear regression value.
|
||||
func (lrs *LinearRegressionSeries) GetFirstValues() (x, y float64) {
|
||||
if lrs.InnerSeries == nil || lrs.InnerSeries.Len() == 0 {
|
||||
return
|
||||
}
|
||||
if lrs.m == 0 && lrs.b == 0 {
|
||||
lrs.computeCoefficients()
|
||||
}
|
||||
x, y = lrs.InnerSeries.GetValues(0)
|
||||
y = (lrs.m * lrs.normalize(x)) + lrs.b
|
||||
return
|
||||
}
|
||||
|
||||
// GetLastValues computes the last linear regression value.
|
||||
func (lrs *LinearRegressionSeries) GetLastValues() (x, y float64) {
|
||||
if lrs.InnerSeries == nil || lrs.InnerSeries.Len() == 0 {
|
||||
|
|
|
@ -8,6 +8,13 @@ import (
|
|||
util "github.com/wcharczuk/go-chart/util"
|
||||
)
|
||||
|
||||
// Interface Assertions.
|
||||
var (
|
||||
_ Series = (*PolynomialRegressionSeries)(nil)
|
||||
_ FirstValuesProvider = (*PolynomialRegressionSeries)(nil)
|
||||
_ LastValuesProvider = (*PolynomialRegressionSeries)(nil)
|
||||
)
|
||||
|
||||
// PolynomialRegressionSeries implements a polynomial regression over a given
|
||||
// inner series.
|
||||
type PolynomialRegressionSeries struct {
|
||||
|
@ -101,6 +108,23 @@ func (prs *PolynomialRegressionSeries) GetValues(index int) (x, y float64) {
|
|||
return
|
||||
}
|
||||
|
||||
// GetFirstValues computes the first poly regression value.
|
||||
func (prs *PolynomialRegressionSeries) GetFirstValues() (x, y float64) {
|
||||
if prs.InnerSeries == nil || prs.InnerSeries.Len() == 0 {
|
||||
return
|
||||
}
|
||||
if prs.coeffs == nil {
|
||||
coeffs, err := prs.computeCoefficients()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
prs.coeffs = coeffs
|
||||
}
|
||||
x, y = prs.InnerSeries.GetValues(0)
|
||||
y = prs.apply(x)
|
||||
return
|
||||
}
|
||||
|
||||
// GetLastValues computes the last poly regression value.
|
||||
func (prs *PolynomialRegressionSeries) GetLastValues() (x, y float64) {
|
||||
if prs.InnerSeries == nil || prs.InnerSeries.Len() == 0 {
|
||||
|
|
|
@ -11,6 +11,13 @@ const (
|
|||
DefaultSimpleMovingAveragePeriod = 16
|
||||
)
|
||||
|
||||
// Interface Assertions.
|
||||
var (
|
||||
_ Series = (*SMASeries)(nil)
|
||||
_ FirstValuesProvider = (*SMASeries)(nil)
|
||||
_ LastValuesProvider = (*SMASeries)(nil)
|
||||
)
|
||||
|
||||
// SMASeries is a computed series.
|
||||
type SMASeries struct {
|
||||
Name string
|
||||
|
@ -63,6 +70,17 @@ func (sma SMASeries) GetValues(index int) (x, y float64) {
|
|||
return
|
||||
}
|
||||
|
||||
// GetFirstValues computes the first moving average value.
|
||||
func (sma SMASeries) GetFirstValues() (x, y float64) {
|
||||
if sma.InnerSeries == nil || sma.InnerSeries.Len() == 0 {
|
||||
return
|
||||
}
|
||||
px, _ := sma.InnerSeries.GetValues(0)
|
||||
x = px
|
||||
y = sma.getAverage(0)
|
||||
return
|
||||
}
|
||||
|
||||
// GetLastValues computes the last moving average value but walking back window size samples,
|
||||
// and recomputing the last moving average chunk.
|
||||
func (sma SMASeries) GetLastValues() (x, y float64) {
|
||||
|
|
|
@ -7,6 +7,14 @@ import (
|
|||
util "github.com/wcharczuk/go-chart/util"
|
||||
)
|
||||
|
||||
// Interface Assertions.
|
||||
var (
|
||||
_ Series = (*TimeSeries)(nil)
|
||||
_ FirstValuesProvider = (*TimeSeries)(nil)
|
||||
_ LastValuesProvider = (*TimeSeries)(nil)
|
||||
_ ValueFormatterProvider = (*TimeSeries)(nil)
|
||||
)
|
||||
|
||||
// TimeSeries is a line on a chart.
|
||||
type TimeSeries struct {
|
||||
Name string
|
||||
|
@ -33,14 +41,21 @@ func (ts TimeSeries) Len() int {
|
|||
return len(ts.XValues)
|
||||
}
|
||||
|
||||
// GetValues gets a value at a given index.
|
||||
// GetValues gets x, y values at a given index.
|
||||
func (ts TimeSeries) GetValues(index int) (x, y float64) {
|
||||
x = util.Time.ToFloat64(ts.XValues[index])
|
||||
y = ts.YValues[index]
|
||||
return
|
||||
}
|
||||
|
||||
// GetLastValues gets the last value.
|
||||
// GetFirstValues gets the first values.
|
||||
func (ts TimeSeries) GetFirstValues() (x, y float64) {
|
||||
x = util.Time.ToFloat64(ts.XValues[0])
|
||||
y = ts.YValues[0]
|
||||
return
|
||||
}
|
||||
|
||||
// GetLastValues gets the last values.
|
||||
func (ts TimeSeries) GetLastValues() (x, y float64) {
|
||||
x = util.Time.ToFloat64(ts.XValues[len(ts.XValues)-1])
|
||||
y = ts.YValues[len(ts.YValues)-1]
|
||||
|
|
|
@ -14,6 +14,11 @@ type BoundedValuesProvider interface {
|
|||
GetBoundedValues(index int) (x, y1, y2 float64)
|
||||
}
|
||||
|
||||
// FirstValuesProvider is a special type of value provider that can return it's (potentially computed) first value.
|
||||
type FirstValuesProvider interface {
|
||||
GetFirstValues() (x, y float64)
|
||||
}
|
||||
|
||||
// LastValuesProvider is a special type of value provider that can return it's (potentially computed) last value.
|
||||
type LastValuesProvider interface {
|
||||
GetLastValues() (x, y float64)
|
||||
|
|
Loading…
Reference in a new issue